Beispiel #1
0
        /// <summary>
        /// accept the authenticate packet, if failed, throw exception.
        /// </summary>
        /// <param name="authenticatePacket">authenciate packet</param>
        /// <exception cref="InvalidOperationException">INVALID message error</exception>
        /// <exception cref="InvalidOperationException">mic of authenticate packet is invalid</exception>
        private void AcceptAuthenticatePacket(NlmpAuthenticatePacket authenticatePacket)
        {
            // save the authenticate to valid the mic.
            this.authenticate = authenticatePacket;

            // retrieve the client authenticate information
            ClientAuthenticateInfomation authenticateInformation =
                RetrieveClientAuthenticateInformation(authenticatePacket);

            // update the version of context
            this.version = authenticateInformation.Version;

            if (authenticateInformation.ClientTime != 0)
            {
                this.systemTime = authenticateInformation.ClientTime;
            }


            byte[] exportedSessionKey = null;
            if (this.nlmpServer.Context.ClientCredential == null)
            {
                if (verifyAuthenticatePacketInDc == null)
                {
                    throw new InvalidOperationException(
                              "In domain environment, the delegate method " +
                              "VerifyAuthenticatePacketInDcMethod should not be null");
                }

                // in domain environment, the authentication is hosted in Active Directory,
                // the response pair MUST be sent to DC to verify [MS-APDS] section 3.1.5
                // DC will return the authentication result and the session key
                DcValidationInfo dcValidationInfo = verifyAuthenticatePacketInDc(
                    authenticatePacket,
                    this.challenge.Payload.ServerChallenge);

                if (dcValidationInfo.status != NtStatus.STATUS_SUCCESS)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  "verify authentication packet in DC failed, NtStatus value ={0}",
                                  dcValidationInfo.status.ToString()));
                }
                exportedSessionKey = dcValidationInfo.sessionKey;
            }
            else
            {
                // in workgroup environment. the authentication is hosted locally.
                authenticateInformation = VerifyAuthenticatePacketLocally(
                    authenticatePacket,
                    authenticateInformation,
                    out exportedSessionKey);
            }

            // save keys
            this.nlmpServer.Context.ExportedSessionKey = exportedSessionKey;

            // initialize keys and handles
            InitializeKeys(exportedSessionKey);
        }
Beispiel #2
0
        /// <summary>
        /// retrieve the domain name from client. client encode the domain name in the authenticate packet.
        /// </summary>
        /// <param name="authenticatePacket">the authenticate packet contains the domain name</param>
        /// <returns>the authentication information of client</returns>
        private ClientAuthenticateInfomation RetrieveClientAuthenticateInformation(
            NlmpAuthenticatePacket authenticatePacket)
        {
            ClientAuthenticateInfomation authenticateInformation = new ClientAuthenticateInfomation();

            // retrieve the version of client
            if (authenticatePacket.Payload.NtChallengeResponseFields.Len == NTLM_V1_NT_CHALLENGE_RESPONSE_LENGTH)
            {
                authenticateInformation.Version = NlmpVersion.v1;
            }
            else
            {
                authenticateInformation.Version = NlmpVersion.v2;
            }

            // retrieve the client challenge
            if (authenticateInformation.Version == NlmpVersion.v1)
            {
                authenticateInformation.ClientChallenge = BitConverter.ToUInt64(ArrayUtility.SubArray <byte>(
                                                                                    authenticatePacket.Payload.LmChallengeResponse, 0, TIME_CLIENT_CHALLENGE_LENGTH), 0);
            }
            else
            {
                authenticateInformation.ClientChallenge = BitConverter.ToUInt64(
                    ArrayUtility.SubArray <byte>(authenticatePacket.Payload.NtChallengeResponse,
                                                 NTLM_V2_CLIENT_CHALLENGE_OFFSET_IN_NT_CHALLENGE_RESPONSE, TIME_CLIENT_CHALLENGE_LENGTH), 0);
            }

            // retrieve the domain name of client
            if (NlmpUtility.IsUnicode(authenticatePacket.Payload.NegotiateFlags))
            {
                authenticateInformation.DomainName = Encoding.Unicode.GetString(authenticatePacket.Payload.DomainName);
            }
            else
            {
                authenticateInformation.DomainName = Encoding.ASCII.GetString(authenticatePacket.Payload.DomainName);
            }

            // retrieve the user name of client
            if (NlmpUtility.IsUnicode(authenticatePacket.Payload.NegotiateFlags))
            {
                authenticateInformation.UserName = Encoding.Unicode.GetString(authenticatePacket.Payload.UserName);
            }
            else
            {
                authenticateInformation.UserName = Encoding.ASCII.GetString(authenticatePacket.Payload.UserName);
            }

            // retrieve the server name of client
            if (authenticateInformation.Version == NlmpVersion.v2)
            {
                authenticateInformation.ServerName =
                    ArrayUtility.SubArray <byte>(authenticatePacket.Payload.NtChallengeResponse,
                                                 NTLM_V2_SERVER_NAME_OFFSET_IN_NT_CHALLENGE_RESPONSE,
                                                 authenticatePacket.Payload.NtChallengeResponseFields.Len -
                                                 NTLM_V2_SERVER_NAME_OFFSET_IN_NT_CHALLENGE_RESPONSE -
                                                 NTLM_V2_SERVER_NAME_RESERVED_LENGTH_IN_NT_CHALLENGE_RESPONSE);
            }

            // retrieve the time of client
            ICollection <AV_PAIR> targetInfo =
                NlmpUtility.BytesGetAvPairCollection(this.challenge.Payload.TargetInfo);

            // retrieve the time
            authenticateInformation.ClientTime = NlmpUtility.GetTime(targetInfo);

            // if server did not response the timestamp, use the client time stamp
            if (!NlmpUtility.AvPairContains(targetInfo, AV_PAIR_IDs.MsvAvTimestamp) &&
                authenticateInformation.Version == NlmpVersion.v2)
            {
                authenticateInformation.ClientTime = BitConverter.ToUInt64(
                    ArrayUtility.SubArray <byte>(authenticatePacket.Payload.NtChallengeResponse,
                                                 NTLM_V2_TIME_STAMP_OFFSET_IN_NT_CHALLENGE_RESPONSE, TIME_STAMP_LENGTH), 0);
            }

            return(authenticateInformation);
        }
Beispiel #3
0
        /// <summary>
        /// Verify the authenticate packet locally
        /// </summary>
        /// <param name="authenticatePacket">actual authenticate packet</param>
        /// <param name="authenticateInformation">expected authenticate information</param>
        /// <param name="exportedSessionKey">exported session key</param>
        /// <returns></returns>
        private ClientAuthenticateInfomation VerifyAuthenticatePacketLocally(
            NlmpAuthenticatePacket authenticatePacket,
            ClientAuthenticateInfomation authenticateInformation,
            out byte[] exportedSessionKey)
        {
            // valid user name
            if (authenticateInformation.UserName.ToUpper() != this.nlmpServer.Context.ClientCredential.AccountName.ToUpper())
            {
                throw new InvalidOperationException(
                          "the user name is invalid!"
                          + " the user name retrieved form authenticate packet is not equal to the context.");
            }

            // calc the basekeys
            byte[] responseKeyLm;
            byte[] expectedNtChallengeResponse;
            byte[] expectedLmChallengeResponse;
            byte[] sessionBaseKey;
            byte[] keyExchangeKey;
            CalculateBaseKeys(
                authenticateInformation.ClientChallenge,
                this.systemTime,
                authenticateInformation.ServerName,
                authenticateInformation.DomainName,
                authenticateInformation.UserName,
                this.nlmpServer.Context.ClientCredential.Password,
                out responseKeyLm, out expectedNtChallengeResponse, out expectedLmChallengeResponse,
                out sessionBaseKey, out keyExchangeKey);

            // valid message
            ValidAuthenticateMessage(authenticatePacket, expectedNtChallengeResponse, expectedLmChallengeResponse);

            // generate keys.
            if (NlmpUtility.IsKeyExch(this.nlmpServer.Context.NegFlg))
            {
                exportedSessionKey = NlmpUtility.RC4(
                    keyExchangeKey, authenticatePacket.Payload.EncryptedRandomSessionKey);
            }
            else
            {
                exportedSessionKey = keyExchangeKey;
            }

            // validate mic
            byte[] messageMic = authenticatePacket.Payload.MIC;
            byte[] zeroMic    = new byte[16];
            if (messageMic != null && !ArrayUtility.CompareArrays <byte>(messageMic, zeroMic))
            {
                AUTHENTICATE_MESSAGE payload = authenticatePacket.Payload;
                payload.MIC = zeroMic;
                authenticatePacket.Payload = payload;

                byte[] mic = NlmpUtility.GetMic(exportedSessionKey, this.negotiate, this.challenge, this.authenticate);

                if (!ArrayUtility.CompareArrays <byte>(messageMic, mic))
                {
                    throw new InvalidOperationException("mic of authenticate packet is invalid");
                }
            }
            return(authenticateInformation);
        }
        /// <summary>
        /// Verify the authenticate packet locally
        /// </summary>
        /// <param name="authenticatePacket">actual authenticate packet</param>
        /// <param name="authenticateInformation">expected authenticate information</param>
        /// <param name="exportedSessionKey">exported session key</param>
        /// <returns></returns>
        private ClientAuthenticateInfomation VerifyAuthenticatePacketLocally(
            NlmpAuthenticatePacket authenticatePacket,
            ClientAuthenticateInfomation authenticateInformation,
            out byte[] exportedSessionKey)
        {
            // valid user name
            if (authenticateInformation.UserName.ToUpper() != this.nlmpServer.Context.ClientCredential.AccountName.ToUpper())
            {
                throw new InvalidOperationException(
                    "the user name is invalid!"
                    + " the user name retrieved form authenticate packet is not equal to the context.");
            }

            // calc the basekeys
            byte[] responseKeyLm;
            byte[] expectedNtChallengeResponse;
            byte[] expectedLmChallengeResponse;
            byte[] sessionBaseKey;
            byte[] keyExchangeKey;
            CalculateBaseKeys(
                authenticateInformation.ClientChallenge,
                this.systemTime,
                authenticateInformation.ServerName,
                authenticateInformation.DomainName,
                authenticateInformation.UserName,
                this.nlmpServer.Context.ClientCredential.Password,
                out responseKeyLm, out expectedNtChallengeResponse, out expectedLmChallengeResponse,
                out sessionBaseKey, out keyExchangeKey);

            // valid message
            ValidAuthenticateMessage(authenticatePacket, expectedNtChallengeResponse, expectedLmChallengeResponse);

            // generate keys.
            if (NlmpUtility.IsKeyExch(this.nlmpServer.Context.NegFlg))
            {
                exportedSessionKey = NlmpUtility.RC4(
                    keyExchangeKey, authenticatePacket.Payload.EncryptedRandomSessionKey);
            }
            else
            {
                exportedSessionKey = keyExchangeKey;
            }

            // validate mic
            byte[] messageMic = authenticatePacket.Payload.MIC;
            byte[] zeroMic = new byte[16];
            if (messageMic != null && !ArrayUtility.CompareArrays<byte>(messageMic, zeroMic))
            {
                AUTHENTICATE_MESSAGE payload = authenticatePacket.Payload;
                payload.MIC = zeroMic;
                authenticatePacket.Payload = payload;

                byte[] mic = NlmpUtility.GetMic(exportedSessionKey, this.negotiate, this.challenge, this.authenticate);

                if (!ArrayUtility.CompareArrays<byte>(messageMic, mic))
                {
                    throw new InvalidOperationException("mic of authenticate packet is invalid");
                }
            }
            return authenticateInformation;
        }
        /// <summary>
        /// retrieve the domain name from client. client encode the domain name in the authenticate packet.
        /// </summary>
        /// <param name="authenticatePacket">the authenticate packet contains the domain name</param>
        /// <returns>the authentication information of client</returns>
        private ClientAuthenticateInfomation RetrieveClientAuthenticateInformation(
            NlmpAuthenticatePacket authenticatePacket)
        {
            ClientAuthenticateInfomation authenticateInformation = new ClientAuthenticateInfomation();

            // retrieve the version of client
            if (authenticatePacket.Payload.NtChallengeResponseFields.Len == NTLM_V1_NT_CHALLENGE_RESPONSE_LENGTH)
            {
                authenticateInformation.Version = NlmpVersion.v1;
            }
            else
            {
                authenticateInformation.Version = NlmpVersion.v2;
            }

            // retrieve the client challenge
            if (authenticateInformation.Version == NlmpVersion.v1)
            {
                authenticateInformation.ClientChallenge = BitConverter.ToUInt64(ArrayUtility.SubArray<byte>(
                    authenticatePacket.Payload.LmChallengeResponse, 0, TIME_CLIENT_CHALLENGE_LENGTH), 0);
            }
            else
            {
                authenticateInformation.ClientChallenge = BitConverter.ToUInt64(
                    ArrayUtility.SubArray<byte>(authenticatePacket.Payload.NtChallengeResponse,
                    NTLM_V2_CLIENT_CHALLENGE_OFFSET_IN_NT_CHALLENGE_RESPONSE, TIME_CLIENT_CHALLENGE_LENGTH), 0);
            }

            // retrieve the domain name of client
            if (NlmpUtility.IsUnicode(authenticatePacket.Payload.NegotiateFlags))
            {
                authenticateInformation.DomainName = Encoding.Unicode.GetString(authenticatePacket.Payload.DomainName);
            }
            else
            {
                authenticateInformation.DomainName = Encoding.ASCII.GetString(authenticatePacket.Payload.DomainName);
            }

            // retrieve the user name of client
            if (NlmpUtility.IsUnicode(authenticatePacket.Payload.NegotiateFlags))
            {
                authenticateInformation.UserName = Encoding.Unicode.GetString(authenticatePacket.Payload.UserName);
            }
            else
            {
                authenticateInformation.UserName = Encoding.ASCII.GetString(authenticatePacket.Payload.UserName);
            }

            // retrieve the server name of client
            if (authenticateInformation.Version == NlmpVersion.v2)
            {
                authenticateInformation.ServerName =
                    ArrayUtility.SubArray<byte>(authenticatePacket.Payload.NtChallengeResponse,
                     NTLM_V2_SERVER_NAME_OFFSET_IN_NT_CHALLENGE_RESPONSE,
                     authenticatePacket.Payload.NtChallengeResponseFields.Len -
                     NTLM_V2_SERVER_NAME_OFFSET_IN_NT_CHALLENGE_RESPONSE -
                     NTLM_V2_SERVER_NAME_RESERVED_LENGTH_IN_NT_CHALLENGE_RESPONSE);
            }

            // retrieve the time of client
            ICollection<AV_PAIR> targetInfo =
                NlmpUtility.BytesGetAvPairCollection(this.challenge.Payload.TargetInfo);

            // retrieve the time
            authenticateInformation.ClientTime = NlmpUtility.GetTime(targetInfo);

            // if server did not response the timestamp, use the client time stamp
            if (!NlmpUtility.AvPairContains(targetInfo, AV_PAIR_IDs.MsvAvTimestamp)
                && authenticateInformation.Version == NlmpVersion.v2)
            {
                authenticateInformation.ClientTime = BitConverter.ToUInt64(
                    ArrayUtility.SubArray<byte>(authenticatePacket.Payload.NtChallengeResponse,
                    NTLM_V2_TIME_STAMP_OFFSET_IN_NT_CHALLENGE_RESPONSE, TIME_STAMP_LENGTH), 0);
            }

            return authenticateInformation;
        }