3.2.5.1.2 Server Receives an AUTHENTICATE_MESSAGE from the Client

Upon receipt of the embedded AUTHENTICATE_MESSAGE (section 2.2.1.3), the server MUST extract and decode the AUTHENTICATE_MESSAGE.

If ServerBlock is set to TRUE then the server MUST return STATUS_NOT_SUPPORTED ([MS-ERREF] section 2.3.1).<65>

If the user name and response are empty, the server authenticates the client as the ANONYMOUS user ([MS-DTYP] section 2.4.2.4). Regardless of whether or not the client is an ANONYMOUS user, if the security features selected by the client are not strong enough for the server security policy, the server MUST return an error to the calling application. Otherwise, the server obtains the response key by looking up the user name in a database. With the NT and LM responses keys and the client challenge, the server computes the expected response. If the expected response matches the actual response, then the server MUST generate session, signing, and sealing keys; otherwise, it MUST deny the client access.

NTLM servers SHOULD support NTLM clients which incorrectly use NIL for the UserDom for calculating ResponseKeyNT and ResponseKeyLM.

The keys MUST be computed with the following algorithm where all strings are encoded as RPC_UNICODE_STRING ([MS-DTYP] section 2.3.10).

 -- Input:
 --   CHALLENGE_MESSAGE.ServerChallenge - The ServerChallenge field
       from the server CHALLENGE_MESSAGE in section 3.2.5.1.1
 --   NegFlg - Defined in section 3.1.1.
 --   ServerName - The NETBIOS or the DNS name of the server.
 --   An NTLM NEGOTIATE_MESSAGE whose message fields are defined
      in section 2.2.1.1.
 --   An NTLM AUTHENTICATE_MESSAGE whose message fields are defined
      in section 2.2.1.3.
 ---  An NTLM AUTHENTICATE_MESSAGE whose message fields are
      defined in section 2.2.1.3 with the MIC field set to 0.
 --   OPTIONAL ServerChannelBindingsUnhashed - Defined in
      section 3.2.1.2
 ---- Output:      Result of authentication
 --    ClientHandle - The handle to a key state structure corresponding
 --    to the current state of the ClientSealingKey
 --    ServerHandle - The handle to a key state structure corresponding
 --    to the current state of the ServerSealingKey
 --    The following NTLM keys generated by the server are defined in
       section 3.1.1:
 --    ExportedSessionKey, ClientSigningKey, ClientSealingKey,
       ServerSigningKey, and ServerSealingKey.
 ---- Temporary variables that do not pass over the wire are defined
      below:
 --    KeyExchangeKey, ResponseKeyNT, ResponseKeyLM, SessionBaseKey 
 -       Temporary variables used to store 128-bit keys. 
 --    MIC - message integrity for the NTLM NEGOTIATE_MESSAGE,
       CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE
 --    MessageMIC - Temporary variable used to hold the original value of
       the MIC field to compare the computed value.
 --    Time - Temporary variable used to hold the 64-bit current time from the 
       NTLMv2_CLIENT_CHALLENGE.Timestamp, in the format of a
       FILETIME as defined in [MS-DTYP] section 2.3.1.
 --    ChallengeFromClient – Temporary variable to hold the client's 8-byte
       challenge, if used.
 --    ExpectedNtChallengeResponse
  - Temporary variable to hold results
       returned from ComputeResponse.
 --    ExpectedLmChallengeResponse
  - Temporary variable to hold results
       returned from ComputeResponse.
 --    NullSession – Temporary variable to denote whether client has
       explicitly requested to be anonymously authenticated.
 ---- Functions used:
 --    ComputeResponse
  - Defined in section 3.3
 --    KXKEY, SIGNKEY, SEALKEY
  - Defined in sections 3.4.5, 3.4.6, and 3.4.7 
 --    GetVersion(), NIL - Defined in section 6
 Set NullSession to FALSE
 Set GuestSession to FALSE
 If (AUTHENTICATE_MESSAGE.UserNameLen == 0 AND
     AUTHENTICATE_MESSAGE.NtChallengeResponse.Length == 0 AND
     (AUTHENTICATE_MESSAGE.LmChallengeResponse == Z(1)
       OR
      AUTHENTICATE_MESSAGE.LmChallengeResponse.Length == 0))    
 -- Special case: client requested anonymous authentication
     Set NullSession to TRUE
 Else
     Retrieve the ResponseKeyNT and ResponseKeyLM from the local user
      account database using the UserName and DomainName specified in the
      AUTHENTICATE_MESSAGE.
     If AUTHENTICATE_MESSAGE.NtChallengeResponseFields.NtChallengeResponseLen > 0x0018
       Set ChallengeFromClient to NTLMv2_RESPONSE.NTLMv2_CLIENT_CHALLENGE.ChallengeFromClient
     ElseIf NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set in NegFlg
       Set ChallengeFromClient to LM_RESPONSE.Response[0..7]
     Else
       Set ChallengeFromClient to NIL
     EndIf
     Set ExpectedNtChallengeResponse, ExpectedLmChallengeResponse,
      SessionBaseKey to ComputeResponse(NegFlg, ResponseKeyNT,
      ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge,
      ChallengeFromClient, Time, ServerName)
     Set KeyExchangeKey to KXKEY(SessionBaseKey,
      AUTHENTICATE_MESSAGE.LmChallengeResponse, CHALLENGE_MESSAGE.ServerChallenge)
     If (AUTHENTICATE_MESSAGE.NtChallengeResponse !=
      ExpectedNtChallengeResponse)
        If (AUTHENTICATE_MESSAGE.LmChallengeResponse !=
          ExpectedLmChallengeResponse)
           Retry using NIL for the domain name: Retrieve the ResponseKeyNT
            and ResponseKeyLM from the local user account database using
            the UserName specified in the AUTHENTICATE_MESSAGE and
            NIL for the DomainName.
           Set ExpectedNtChallengeResponse, ExpectedLmChallengeResponse,
            SessionBaseKey to ComputeResponse(NegFlg, ResponseKeyNT,
            ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge,
            ChallengeFromClient, Time, ServerName)
           Set KeyExchangeKey to KXKEY(SessionBaseKey,
            AUTHENTICATE_MESSAGE.LmChallengeResponse, 
            CHALLENGE_MESSAGE.ServerChallenge)
           If (AUTHENTICATE_MESSAGE.NtChallengeResponse !=
            ExpectedNtChallengeResponse)
              If (AUTHENTICATE_MESSAGE.LmChallengeResponse !=
               ExpectedLmChallengeResponse)
                 If (Guest user is not disabled AND Guest user has no password set AND
                   UserName does not exist in user account database)
                 --Special case: User can be logged in as Guest user
                   Set GuestSession to TRUE
                 Else
                  Return INVALID message error
                 EndIf
              EndIf
           EndIf
        EndIf
     EndIf
 EndIf
 Set MessageMIC to AUTHENTICATE_MESSAGE.MIC
 Set AUTHENTICATE_MESSAGE.MIC to Z(16)
 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg
   AND (NTLMSSP_NEGOTIATE_SIGN OR NTLMSSP_NEGOTIATE_SEAL are set in NegFlg) )
     Set ExportedSessionKey to RC4K(KeyExchangeKey,
      AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
 Else
     Set ExportedSessionKey to KeyExchangeKey
 EndIf
 Set MIC to HMAC_MD5(ExportedSessionKey, ConcatenationOf(
         NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE,
         AUTHENTICATE_MESSAGE))
  
 Set ClientSigningKey to SIGNKEY(NegFlg, ExportedSessionKey , "Client")
 Set ServerSigningKey to SIGNKEY(NegFlg, ExportedSessionKey , "Server")
 Set ClientSealingKey to SEALKEY(NegFlg, ExportedSessionKey , "Client")
 Set ServerSealingKey to SEALKEY(NegFlg, ExportedSessionKey , "Server")
 RC4Init(ClientHandle, ClientSealingKey)
 RC4Init(ServerHandle, ServerSealingKey)

If NullSession is TRUE, the server authenticates the client as the ANONYMOUS user account (see [MS-DTYP] section 2.4.2.4).

If NullSession is TRUE, a SessionBaseKey with all-zeroes, Z(16), is used.

If GuestSession is TRUE, the server authenticates the client as the Guest user account (see [MS-DTYP] section 2.4.2.4).

If GuestSession is TRUE, a SessionBaseKey with all-zeroes, Z(16), is used.

If NTLMSSP_NEGOTIATE_KEY_EXCH is set, the server MUST check if client supplied a valid EncryptedRandomSessionKey in the AUTHENTICATE_MESSAGE (section 2.2.1.3); otherwise, the server MUST return SEC_E_INVALID_TOKEN.

If NTLM v2 authentication is used and channel binding is provided by the application, then the server MUST verify the channel binding:<66>

  • If ServerChannelBindingsUnhashed (section 3.2.1.2) is not NULL

    • If the AUTHENTICATE_MESSAGE contains a nonzero MsvAvChannelBindings AV_PAIR

      • If MD5_HASH(ServerChannelBindingsUnhashed) != MsvAvChannelBindings.AvPair.Value)

        • The server MUST return GSS_S_BAD_BINDINGS

      • Else the server MUST return GSS_S_BAD_BINDINGS

    • Else If ApplicationRequiresCBT (section 3.2.1.2) == TRUE

      • If the AUTHENTICATE_MESSAGE does not contain a nonzero MsvAvChannelBindings AV_PAIR

        • The server MUST return GSS_S_BAD_BINDINGS

  • If the AUTHENTICATE_MESSAGE contains an MsvAvTargetName

    • If MsvAvFlags bit 0x00000004 is set, the server MUST set ClientSuppliedTargetName (section 3.1.1.2) to NULL.<67>

    • AvID == MsvAvTargetName

    • Value == ClientSuppliedTargetName

If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,<68> then the MIC value computed earlier MUST be compared to MessageMIC, and if the two MIC values are not equal, then an authentication failure MUST be returned. An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has an AV_PAIR structure whose two fields:

  • AvId == MsvAvFlags

  • Value bit 0x2 == 1

If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from the server time, then the server SHOULD return a failure.<69>

Both the client and the server now have the session, signing, and sealing keys. When the client runs an integrity check on the next message from the server, it detects that the server has determined (either directly or indirectly) the user password.

Note  User names MUST be case-insensitive. For additional information about the case sensitivity of user names, see [MS-AUTHSOD] section 1.1.1.2.