Ejemplo n.º 1
0
        /// <summary>
        /// Encode common part of DigestValidationRequest
        /// </summary>
        /// <param name="serverName">server name</param>
        /// <param name="domainName">domain name</param>
        /// <param name="accountName">account name</param>
        /// <param name="digestType">digest type</param>
        /// <param name="digestChallengeAlgorithm">digest challenge algorithm</param>
        /// <param name="dpspResponse">dpspResponse</param>
        /// <param name="payload">DIGEST_VALIDATION_REQ_Payload structure</param>
        /// <param name="digestValidationReq">digestValidationReq</param>
        private static void EncodeCommonPartOfDigestValidationRequest(
            string serverName,
            string domainName,
            string accountName,
            DigestType_Values digestType,
            string digestChallengeAlgorithm,
            DpspResponse dpspResponse,
            ref DIGEST_VALIDATION_REQ_Payload payload,
            ref DIGEST_VALIDATION_REQ digestValidationReq
            )
        {
            digestValidationReq.MessageType = DIGEST_VALIDATION_REQ_MessageType_Values.Default;
            digestValidationReq.Version     = DIGEST_VALIDATION_REQ_Version_Values.Default;
            digestValidationReq.DigestType  = digestType;
            digestValidationReq             = SetQopType(dpspResponse, digestValidationReq);
            digestValidationReq             = SetAlgType(digestChallengeAlgorithm, digestValidationReq);
            digestValidationReq.CharsetType = CharsetType_Values.UTF8;
            digestValidationReq.NameFormat  = NameFormat_Values.None;
            digestValidationReq.Flags       =
                DIGEST_VALIDATION_FLAGS.FormatOfUserNameAndRealmIsDeterminedByDC
                | DIGEST_VALIDATION_FLAGS.RequestIsSentFromServer;

            digestValidationReq.Reserved3 = DIGEST_VALIDATION_REQ_Reserved3_Values.Default;
            digestValidationReq.Reserved4 = Reserved4_Values.Default;
            digestValidationReq.Pad1      = DIGEST_VALIDATION_REQ_Pad1_Values.Default;

            // Each of the strings MUST be included. If the string value is empty,
            // then a terminating null character MUST be used for the value.
            payload.Username   = dpspResponse.GetAttributeValue(DpspUtility.USER_NAME_DIRECTIVE);
            payload.Realm      = dpspResponse.GetAttributeValue(DpspUtility.REALM_DIRECTIVE);
            payload.Nonce      = dpspResponse.GetAttributeValue(DpspUtility.NONCE_DIRECTIVE);
            payload.CNonce     = dpspResponse.GetAttributeValue(DpspUtility.CNONCE_DIRECTIVE);
            payload.NonceCount = dpspResponse.GetAttributeValue(DpspUtility.NONCE_COUNT_DIRECTIVE);
            payload.QOP        = dpspResponse.GetAttributeValue(DpspUtility.MESSAGE_QOP_DIRECTIVE);
            payload.Response   = dpspResponse.GetAttributeValue(DpspUtility.RESPONSE_DIRECTIVE);

            payload.AccountName = accountName;;
            payload.ServerName  = serverName;
            payload.Domain      = domainName;
        }
        /// <summary>
        /// Encode common part of DigestValidationRequest
        /// </summary>
        /// <param name="serverName">server name</param>
        /// <param name="domainName">domain name</param>
        /// <param name="accountName">account name</param>
        /// <param name="digestType">digest type</param>
        /// <param name="digestChallengeAlgorithm">digest challenge algorithm</param>
        /// <param name="dpspResponse">dpspResponse</param>
        /// <param name="payload">DIGEST_VALIDATION_REQ_Payload structure</param>
        /// <param name="digestValidationReq">digestValidationReq</param>
        private static void EncodeCommonPartOfDigestValidationRequest(
            string serverName,
            string domainName,
            string accountName,
            DigestType_Values digestType,
            string digestChallengeAlgorithm,
            DpspResponse dpspResponse,
            ref DIGEST_VALIDATION_REQ_Payload payload,
            ref DIGEST_VALIDATION_REQ digestValidationReq
            )
        {
            digestValidationReq.MessageType = DIGEST_VALIDATION_REQ_MessageType_Values.Default;
            digestValidationReq.Version = DIGEST_VALIDATION_REQ_Version_Values.Default;
            digestValidationReq.DigestType = digestType;
            digestValidationReq = SetQopType(dpspResponse, digestValidationReq);
            digestValidationReq = SetAlgType(digestChallengeAlgorithm, digestValidationReq);
            digestValidationReq.CharsetType = CharsetType_Values.UTF8;
            digestValidationReq.NameFormat = NameFormat_Values.None;
            digestValidationReq.Flags =
                DIGEST_VALIDATION_FLAGS.FormatOfUserNameAndRealmIsDeterminedByDC
                | DIGEST_VALIDATION_FLAGS.RequestIsSentFromServer;

            digestValidationReq.Reserved3 = DIGEST_VALIDATION_REQ_Reserved3_Values.Default;
            digestValidationReq.Reserved4 = Reserved4_Values.Default;
            digestValidationReq.Pad1 = DIGEST_VALIDATION_REQ_Pad1_Values.Default;

            // Each of the strings MUST be included. If the string value is empty,
            // then a terminating null character MUST be used for the value.
            payload.Username = dpspResponse.GetAttributeValue(DpspUtility.USER_NAME_DIRECTIVE);
            payload.Realm = dpspResponse.GetAttributeValue(DpspUtility.REALM_DIRECTIVE);
            payload.Nonce = dpspResponse.GetAttributeValue(DpspUtility.NONCE_DIRECTIVE);
            payload.CNonce = dpspResponse.GetAttributeValue(DpspUtility.CNONCE_DIRECTIVE);
            payload.NonceCount = dpspResponse.GetAttributeValue(DpspUtility.NONCE_COUNT_DIRECTIVE);
            payload.QOP = dpspResponse.GetAttributeValue(DpspUtility.MESSAGE_QOP_DIRECTIVE);
            payload.Response = dpspResponse.GetAttributeValue(DpspUtility.RESPONSE_DIRECTIVE);

            payload.AccountName = accountName; ;
            payload.ServerName = serverName;
            payload.Domain = domainName;
        }
        /// <summary>
        /// Construct DIGEST_VALIDATION_REQ structure
        /// </summary>
        /// <param name="serverName">server name</param>
        /// <param name="domainName">domain name</param>
        /// <param name="accountName">account name</param>
        /// <param name="httpMethod">http method</param>
        /// <param name="digestType">digest type</param>
        /// <param name="digestChallengeAlgorithm">digest challenge algorithm</param>
        /// <param name="dpspResponse">dpspResponse class instance</param>
        /// <returns>DIGEST_VALIDATION_REQ structure</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when dpspResponse or httpMethod is null  
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when httpMethod or digestType input is invalid
        /// </exception>        
        public static DIGEST_VALIDATION_REQ CreateDigestValidationRequestPacket(
            string serverName,
            string domainName,
            string accountName,
            string httpMethod,
            DigestType_Values digestType,
            string digestChallengeAlgorithm,
            DpspResponse dpspResponse)
        {
            if (dpspResponse == null)
            {
                throw new ArgumentNullException("dpspResponse");
            }

            if (httpMethod == null)
            {
                throw new ArgumentNullException("httpMethod");
            }

            DIGEST_VALIDATION_REQ_Payload payload = new DIGEST_VALIDATION_REQ_Payload();

            DIGEST_VALIDATION_REQ digestValidationReq = new DIGEST_VALIDATION_REQ();
            if (digestType == DigestType_Values.Basic)
            {
                EncodeCommonPartOfDigestValidationRequest(
                    serverName,
                    domainName,
                    accountName,
                    digestType,
                    digestChallengeAlgorithm,
                    dpspResponse,
                    ref payload,
                    ref digestValidationReq);

                payload.Algorithm = dpspResponse.GetAttributeValue(DpspUtility.ALGORITHM_DIRECTIVE);
                payload.URI = dpspResponse.GetAttributeValue(DpspUtility.BASIC_DIGEST_URI_DIRECTIVE);
                if (httpMethod.ToUpper().Equals(HTTP_GET) || httpMethod.ToLower().Equals(HTTP_PUT))
                {
                    payload.Method = httpMethod;
                }
                else
                {
                    throw new ArgumentException("invalid http method", "httpMethod");
                }
            }
            else if (digestType == DigestType_Values.SASL)
            {
                EncodeCommonPartOfDigestValidationRequest(
                   serverName,
                   domainName,
                   accountName,
                   digestType,
                   digestChallengeAlgorithm,
                   dpspResponse,
                   ref payload,
                   ref digestValidationReq);

                payload.Method = SASL_AUTHENTICATE;
                payload.URI = dpspResponse.GetAttributeValue(DpspUtility.SASL_DIGEST_URI_DIRECTIVE);
                payload.Authzid = dpspResponse.GetAttributeValue(DpspUtility.AUTHZID_DIRECTIVE);
                payload.Hentity = dpspResponse.GetAttributeValue(DpspUtility.HENTITY_DIRECTIVE);

            }
            else
            {
                throw new ArgumentException(
                    "invalid digestType value",
                    "digestType");
            }

            digestValidationReq.Payload = payload.GetBytes();
            digestValidationReq = UpdatePacketInfo(digestValidationReq);

            return digestValidationReq;
        }
Ejemplo n.º 4
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;
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Construct DIGEST_VALIDATION_REQ structure
        /// </summary>
        /// <param name="serverName">server name</param>
        /// <param name="domainName">domain name</param>
        /// <param name="accountName">account name</param>
        /// <param name="httpMethod">http method</param>
        /// <param name="digestType">digest type</param>
        /// <param name="digestChallengeAlgorithm">digest challenge algorithm</param>
        /// <param name="dpspResponse">dpspResponse class instance</param>
        /// <returns>DIGEST_VALIDATION_REQ structure</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when dpspResponse or httpMethod is null
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when httpMethod or digestType input is invalid
        /// </exception>
        public static DIGEST_VALIDATION_REQ CreateDigestValidationRequestPacket(
            string serverName,
            string domainName,
            string accountName,
            string httpMethod,
            DigestType_Values digestType,
            string digestChallengeAlgorithm,
            DpspResponse dpspResponse)
        {
            if (dpspResponse == null)
            {
                throw new ArgumentNullException("dpspResponse");
            }

            if (httpMethod == null)
            {
                throw new ArgumentNullException("httpMethod");
            }

            DIGEST_VALIDATION_REQ_Payload payload = new DIGEST_VALIDATION_REQ_Payload();

            DIGEST_VALIDATION_REQ digestValidationReq = new DIGEST_VALIDATION_REQ();

            if (digestType == DigestType_Values.Basic)
            {
                EncodeCommonPartOfDigestValidationRequest(
                    serverName,
                    domainName,
                    accountName,
                    digestType,
                    digestChallengeAlgorithm,
                    dpspResponse,
                    ref payload,
                    ref digestValidationReq);

                payload.Algorithm = dpspResponse.GetAttributeValue(DpspUtility.ALGORITHM_DIRECTIVE);
                payload.URI       = dpspResponse.GetAttributeValue(DpspUtility.BASIC_DIGEST_URI_DIRECTIVE);
                if (httpMethod.ToUpper().Equals(HTTP_GET) || httpMethod.ToLower().Equals(HTTP_PUT))
                {
                    payload.Method = httpMethod;
                }
                else
                {
                    throw new ArgumentException("invalid http method", "httpMethod");
                }
            }
            else if (digestType == DigestType_Values.SASL)
            {
                EncodeCommonPartOfDigestValidationRequest(
                    serverName,
                    domainName,
                    accountName,
                    digestType,
                    digestChallengeAlgorithm,
                    dpspResponse,
                    ref payload,
                    ref digestValidationReq);

                payload.Method  = SASL_AUTHENTICATE;
                payload.URI     = dpspResponse.GetAttributeValue(DpspUtility.SASL_DIGEST_URI_DIRECTIVE);
                payload.Authzid = dpspResponse.GetAttributeValue(DpspUtility.AUTHZID_DIRECTIVE);
                payload.Hentity = dpspResponse.GetAttributeValue(DpspUtility.HENTITY_DIRECTIVE);
            }
            else
            {
                throw new ArgumentException(
                          "invalid digestType value",
                          "digestType");
            }

            digestValidationReq.Payload = payload.GetBytes();
            digestValidationReq         = UpdatePacketInfo(digestValidationReq);

            return(digestValidationReq);
        }