Exemple #1
0
        /// <summary>
        /// This method constructs the digest request structure which is required to send from protocol client to protocol server.
        /// </summary>
        /// <param name="digestType">It indicates the DigestType field of the DIGEST_VALIDATION_REQ</param>
        /// <param name="algType">It indicates the AlgType field of the DIGEST_VALIDATION_REQ </param>
        /// <param name="ignoredFields">It indicates the fields that should be ignored by DC in DIGEST_VALIDATION_REQ </param>
        /// <param name="digestReq">The request structure for digest validation</param>
        private void GetDigestRequest(
            DigestType_Values digestType,
            AlgType_Values algType,
            IgnoredFields ignoredFields,
            out DIGEST_VALIDATION_REQ digestReq)
        {
            // create a temporary payload structure
            DIGEST_VALIDATION_REQ_Payload reqLoad = new DIGEST_VALIDATION_REQ_Payload();

            reqLoad.AccountName = currentUserName;
            reqLoad.Algorithm   = acceptedAlgType;
            reqLoad.Authzid     = "";
            reqLoad.Nonce       = GenerateNonce();
            reqLoad.CNonce      = reqLoad.Nonce;
            reqLoad.Hentity     = "";
            reqLoad.NonceCount  = nonceCountString;
            reqLoad.QOP         = "";
            reqLoad.Realm       = sutDomainName;
            reqLoad.URI         = "/";
            reqLoad.Username    = currentUserName;

            string servicename = serverName;
            string response    = string.Empty;

            if (digestType == DigestType_Values.Basic)
            {
                reqLoad.Method = httpRequestMethodString;

                // calling RFC 2617 algorithms for calculating H(A1) and Response, when HTTP is involved.
                string strHA1 = DigestCalcHA1HTTP(
                    reqLoad.Algorithm,
                    reqLoad.Username,
                    reqLoad.Realm,
                    currentPassword,
                    reqLoad.Nonce,
                    reqLoad.CNonce,
                    false);

                digestSessionKey = strHA1;

                response = DigestCalcResponseHTTP(
                    strHA1,
                    reqLoad.Nonce,
                    reqLoad.NonceCount,
                    reqLoad.CNonce,
                    reqLoad.QOP,
                    reqLoad.Method,
                    reqLoad.URI,
                    reqLoad.Hentity,
                    false);
            }
            else if (digestType == DigestType_Values.SASL)
            {
                reqLoad.Method = saslRequestMethodString;

                // calling RFC 2617 algorithms for calculating H(A1) and Response, when SASL is involved.
                string strHA1 = DigestCalcHA1SASL(
                    reqLoad.Authzid,
                    reqLoad.Username,
                    reqLoad.Realm,
                    currentPassword,
                    reqLoad.Nonce,
                    reqLoad.CNonce,
                    false);

                digestSessionKey = strHA1;

                response = DigestCalcResponseSASL(
                    strHA1,
                    reqLoad.Nonce,
                    reqLoad.NonceCount,
                    reqLoad.CNonce,
                    reqLoad.QOP,
                    reqLoad.URI,
                    false,
                    false);
            }
            string basicDigestCredentialString = "Digest username="******",realm=" + reqLoad.Realm
                                                 + ",nonce=" + reqLoad.Nonce
                                                 + ",uri=" + reqLoad.URI
                                                 + ",cnonce=" + reqLoad.CNonce
                                                 + ",nc=" + reqLoad.NonceCount
                                                 + ",algorithm=" + reqLoad.Algorithm
                                                 + ",response=" + response
                                                 + ",qop=" + reqLoad.QOP
                                                 + ",charset=" + encodingCodePageString
                                                 + ",service-name=" + servicename;

            DpspResponse dpspResponse = DpspBasicResponse.Decode(basicDigestCredentialString);

            DIGEST_VALIDATION_REQ digestValidationReq = ApdsUtility.CreateDigestValidationRequestPacket(
                clientComputerName,
                string.Empty,
                string.Empty,
                reqLoad.Method,
                digestType,
                acceptedAlgType,
                dpspResponse);

            digestValidationReq.CharsetType = CharsetType_Values.ISO8859_1;
            digestValidationReq.AlgType     = algType;
            digestValidationReq.Flags       = (DIGEST_VALIDATION_FLAGS)5;
            digestValidationReq.Reserved3   = (DIGEST_VALIDATION_REQ_Reserved3_Values)ignoredFields.reserved3;
            digestValidationReq.Reserved4   = (Reserved4_Values)ignoredFields.reserved4;

            digestReq = digestValidationReq;
        }
Exemple #2
0
        /// <summary>
        /// Send Digest request message to DC, and validate the credentials.
        /// </summary>
        /// <param name="isValidationSuccess">Indicates whether the validation from server will be success.</param>
        /// <param name="digestType">Indicates the DigestType field of the request.</param>
        /// <param name="algType">Indicates the AlgType field of the request.</param>
        /// <param name="ignoredFields">It indicates the fields that should be ignored by DC in DIGEST_VALIDATION_REQ.</param>
        /// <returns>Indicates the result status of DC response.</returns>
        public Status GenerateDigestRequest(
            Boolean isValidationSuccess,
            AccountInformation accountInfo,
            DigestType_Values digestType,
            AlgType_Values algType,
            IgnoredFields ignoredFields)
        {
            DIGEST_VALIDATION_REQ           digestReq;
            _NETLOGON_LOGON_INFO_CLASS      logonLevel      = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation;
            _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2;

            //Compute the password
            GenerateCurrentCredentials(accountInfo);

            //Get Digest Request
            GetDigestRequest(digestType, algType, ignoredFields, out digestReq);

            //Create digest validation logon info
            _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreateDpspLogonInfo(
                NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                digestReq);

            //Create Secure Channel
            EstablishSecureChannel();

            //Client calls EncryptNetlogonLevel
            _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                netlogonLevel);

            //Client calls NetrLogonSamLogonEx
            _NETLOGON_VALIDATION?validationInfomation;
            byte?authoritative;
            NrpcNetrLogonSamLogonExtraFlags?extraFlags = NrpcNetrLogonSamLogonExtraFlags.None;

            result = nrpcClient.NetrLogonSamLogonEx(
                nrpcClient.Handle,
                sutComputerName,
                clientComputerName,
                logonLevel,
                encryptedLogonLevel,
                validationLevel,
                out validationInfomation,
                out authoritative,
                ref extraFlags);

            // Whether this method use pass-through mechanism or not.
            bool isPassThroughMethod = false;

            //
            //The Digest validation protocol SHOULD use the generic pass-through mechanism.
            //For generic pass-through, the LogonLevel is 4(NetlogonGenericInformation) as defined in [MS-NRPC] section 3.2.4.1.
            //So when the LogonLevel is  4, we can say that NRPC pass-through authentication method is used.
            //
            if ((int)logonLevel == 4)
            {
                isPassThroughMethod = true;
            }
            //
            //Verify MS-APDS requirment:MS-APDS_R5
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                5,
                @"For domain support, authentication protocols MUST use an NRPC pass-through authentication 
                ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being 
                used[to return the response structures to member server].");

            //
            //Verify MS-APDS requirment:MS-APDS_R15
            //
            Site.CaptureRequirementIfAreEqual <int>(
                5,
                (int)validationLevel,
                15,
                @"Digest response messages MUST be encoded as opaque blobs and transported 
                by the generic pass-through capability of Netlogon.");

            //
            //Configured in PTFConfig file,default SHOULD to true and MAY to false.
            //
            string isR169Implemented = "true";

            //
            //Check OS version
            //
            if (isWindows)
            {
                //
                //Verify MS-APDS requirment:MS-APDS_R100169
                //
                Site.CaptureRequirementIfAreEqual <int>(
                    5,
                    (int)validationLevel,
                    100169,
                    @"In Windows, the Digest validation protocol uses the generic pass-through mechanism.");

                if (null == isR169Implemented)
                {
                    Site.Properties.Add("R169Implemented", Boolean.TrueString);
                    isR169Implemented = Boolean.TrueString;
                }
            }
            if (null != isR169Implemented)
            {
                bool implSigns   = Boolean.Parse(isR169Implemented);
                bool isSatisfied = ((int)_NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2 == 5);
                //
                //Verify MS-APDS requirment:MS-APDS_R169
                //
                Site.CaptureRequirementIfAreEqual <Boolean>(
                    implSigns,
                    isSatisfied,
                    169,
                    string.Format(@"The Digest validation protocol SHOULD use the generic pass-through mechanism. 
                   This requirement is {0} implemented.", implSigns ? "" : "not"));
            }

            byte[] buf;
            bool   isDigestResStructure = true;
            DIGEST_VALIDATION_RESP digestValidationResponse = new DIGEST_VALIDATION_RESP();

            // Judge whether the digest response is exist, validationData is response point.
            // if validationData equals 0, no response return from NRPC.
            if (validationInfomation.Value.ValidationGeneric2 == null)
            {
                isDigestResStructure = false;
            }
            else
            {
                // decrypt validation info
                buf = NrpcUtility.DecryptBuffer(
                    (nrpcClient.Context.NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) == NrpcNegotiateFlags.SupportsAESAndSHA2,
                    nrpcClient.Context.SessionKey,
                    validationInfomation.Value.ValidationGeneric2[0].ValidationData);

                _NETLOGON_VALIDATION decryptValidationInfo = new _NETLOGON_VALIDATION();
                decryptValidationInfo.ValidationGeneric2 = new _NETLOGON_VALIDATION_GENERIC_INFO2[1];
                decryptValidationInfo.ValidationGeneric2[0].ValidationData = buf;

                digestValidationResponse =
                    ApdsUtility.ConvertDataToDigestValidationResponse(decryptValidationInfo);

                VerifyMessageSyntaxDigestValidCredential(digestValidationResponse, validationLevel, (uint)buf.Length);
            }

            if (result != NtStatus.STATUS_SUCCESS)
            {
                //
                //Verify MS-APDS requirment:MS-APDS_R292
                //
                Site.CaptureRequirementIfIsFalse(
                    isDigestResStructure,
                    292,
                    "[If unsuccessful]It[DC] MUST NOT send back the DIGEST_VALIDATION_RESP message.");

                VerifyMessageSyntxDigestInvalidResp((uint)result, digestValidationResponse.AuthDataSize);
            }

            return((Status)result);
        }
Exemple #3
0
        /// <summary>
        /// Send KERB_VERIFY_PAC_REQUEST message to DC through generic pass-through mechanism
        /// </summary>
        /// <param name="serverSignature">Server Signature in the privilege attribute certificate (PAC)</param>
        /// <param name="kdcSignature">Key Distribution Center (KDC) Signature in the PAC</param>
        /// <returns></returns>
        public Status GenerateKerberosValidationRequest(
            PAC_SIGNATURE_DATA serverSignature,
            PAC_SIGNATURE_DATA kdcSignature)
        {
            _NETLOGON_LOGON_INFO_CLASS      logonLevel      = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation;
            _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2;

            //Get Kerberos Request
            KERB_VERIFY_PAC_REQUEST kerberosReq = ApdsUtility.CreateKerbVerifyPacRequest(serverSignature, kdcSignature);

            //Create digest validation logon info
            _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreatePacLogonInfo(
                NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                PrimaryDomainDnsName,
                DomainAdministratorName,
                PDCNetbiosName,
                kerberosReq);

            //Create Secure Channel
            EstablishSecureChannel();

            //Client calls EncryptNetlogonLevel
            _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                netlogonLevel);

            //Client calls NetrLogonSamLogonEx
            _NETLOGON_VALIDATION?validationInfomation;
            byte?authoritative;
            NrpcNetrLogonSamLogonExtraFlags?extraFlags = NrpcNetrLogonSamLogonExtraFlags.None;

            result = nrpcClient.NetrLogonSamLogonEx(
                nrpcClient.Handle,
                sutComputerName,
                clientComputerName,
                logonLevel,
                encryptedLogonLevel,
                validationLevel,
                out validationInfomation,
                out authoritative,
                ref extraFlags);

            // Whether this method use pass-through mechanism or not.
            bool isPassThroughMethod = false;

            //Kerberos PAC validation SHOULD use the generic pass-through mechanism ([MS-NRPC] section 3.2.4.1).
            //For generic pass-through, the LogonLevel is 4(NetlogonGenericInformation) as defined in [MS-NRPC] section 3.2.4.1.
            //So when the LogonLevel is  4, we can say that NRPC pass-through authentication method is used.
            if ((int)logonLevel == 4)
            {
                isPassThroughMethod = true;
            }
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                5,
                @"For domain support, authentication protocols MUST use an NRPC pass-through authentication 
                ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being 
                used[to return the response structures to member server].");
            Site.CaptureRequirementIfAreEqual <int>(
                5,
                (int)validationLevel,
                402,
                @"The encoded data SHOULD be sent by using the generic pass-through mechanism ([MS-NRPC] section 3.2.4.1).");

            if (result == NtStatus.STATUS_SUCCESS)
            {
                Site.CaptureRequirementIfIsNull(validationInfomation.Value.ValidationGeneric2[0].ValidationData, 403,
                                                @"If the checksum is verified, the DC MUST return STATUS_SUCCESS. There is no return message.");
            }
            return((Status)result);
        }
Exemple #4
0
        /// <summary>
        /// Send NTLM request message to DC for validation.
        /// </summary>
        /// <param name="logonLevel">Indicates the logon level.</param>
        /// <param name="accountInfo">Indicates whether this account is valid in DC validation.</param>
        /// <param name="isAccessCheckSuccess">Indicates whether the access checked success.</param>
        /// <param name="validationLevel">Indicates the validation level.</param>
        /// <returns>Indicates the result status of DC response.</returns>
        public Status NTLMLogon(
            _NETLOGON_LOGON_INFO_CLASS logonLevel,
            AccountInformation accountInfo,
            Boolean isAccessCheckSuccess,
            _NETLOGON_VALIDATION_INFO_CLASS validationLevel)
        {
            //Compute the password
            GenerateCurrentCredentials(accountInfo);

            //Create Secure Channel
            EstablishSecureChannel();

            _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL();

            if (logonLevel == _NETLOGON_LOGON_INFO_CLASS.NetlogonInteractiveInformation)
            {
                //Fill InteractiveInfo
                netLogonLevel = ApdsUtility.CreateNlmpInteractiveLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    sutTrustDomainName,
                    currentUserName,
                    currentPassword,
                    sutComputerName);
            }
            else if (logonLevel == _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation)
            {
                //Fill Netlogon_Network_Info
                if (accountInfo == AccountInformation.ManagedServiceAccount)
                {
                    netLogonLevel = nrpcClient.CreateNetlogonLevel(
                        _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation,
                        NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                        sutDomainName, // managed service account is created in the local domain
                        currentUserName,
                        currentPassword);
                }
                else
                {
                    netLogonLevel = nrpcClient.CreateNetlogonLevel(
                        _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation,
                        NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                        sutTrustDomainName,
                        currentUserName,
                        currentPassword);
                }
            }

            _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                logonLevel,
                netLogonLevel);

            byte?authoritative;
            _NETLOGON_VALIDATION?           validationInformation = new _NETLOGON_VALIDATION();
            NrpcNetrLogonSamLogonExtraFlags?extraFlags            = NrpcNetrLogonSamLogonExtraFlags.None;

            result = nrpcClient.NetrLogonSamLogonEx(
                nrpcClient.Handle,
                sutComputerName,
                clientComputerName,
                logonLevel,
                encryptedLogonLevel,
                validationLevel,
                out validationInformation,
                out authoritative,
                ref extraFlags);

            // Whether this method use pass-through mechanism or not.
            bool isPassThroughMethod = false;

            //
            //For NTLM pass-through, the LogonLevel is 1(NetlogonInteractiveInformation) or 2(NetlogonNetworkInformation)
            //based on Interactive Logono and Network Logon,as defined in [MS-APDS] section 3.1.5.1 and section 3.1.5.2.
            //So when the LogonLevel is 1 or 2, we can say that NRPC pass-through authentication method is used.
            //
            if ((int)logonLevel == 1 || (int)logonLevel == 2)
            {
                isPassThroughMethod = true;
            }

            //
            //Verify MS-APDS requirment:MS-APDS_R5
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                5,
                @"For domain support, authentication protocols MUST use an NRPC pass-through authentication 
                ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being 
                used[to return the response structures to member server].");

            //
            //Verify MS-APDS requirment:MS-APDS_R118
            //if isPassThroughMethod is true, this requirement can be verified.
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                118,
                @"NT LAN Manager (NTLM) interactive logon and network logon MUST receive the authentication 
                response sequence by contacting the DC using an NRPC pass-through authentication method .");

            if (result == NtStatus.STATUS_SUCCESS)
            {
                if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);

                    VerifyMessageSyntxNTLMValidV4Resp(
                        validationInformation.Value.ValidationSam4[0].UserSessionKey.data[0].data,
                        validationInformation.Value.ValidationSam4[0].EffectiveName.ToString());
                }
                else if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo2)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);
                }
                else if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);
                }
            }

            return((Status)result);
        }