3.3.5.5.3 Handling GSS-API Authentication

The server MUST extract the GSS token from the request. The token is SecurityBufferLength bytes in length and located SecurityBufferOffset bytes from the beginning of the SMB2 header. The server MUST invoke GSS_Accept_sec_context, as specified in [RFC2743], by passing the GSS token to obtain the next GSS output token for the authentication exchange.<291>

If the authentication protocol indicates an error, the server MUST fail the session setup request with the error received by placing the 32-bit NTSTATUS code received into the Status field of the SMB2 header. The server MUST remove the session object from GlobalSessionTable and Connection.SessionTable and deregister the session by invoking the event specified in [MS-SRVS] section 3.1.6.3, providing Session.SessionGlobalId as an input parameter. The server MUST remove the PreauthSession object from Connection.PreauthSessionTable. ServerStatistics.sts0_sopens MUST be decreased by 1. The server MUST close every Open in Session.OpenTable as specified in section 3.3.4.17. The server MUST deregister every TreeConnect in Session.TreeConnectTable by providing the tuple <TreeConnect.Share.ServerName, TreeConnect.Share.Name> and TreeConnect.TreeGlobalId as the input parameters and invoking the event specified in [MS-SRVS] section 3.1.6.7. For each deregistered TreeConnect, TreeConnect.Share.CurrentUses MUST be decreased by 1. All the tree connects in Session.TreeConnectTable MUST be removed and freed. The session object MUST also be freed, and the error response MUST be sent to the client. ServerStatistics.sts0_pwerrors MUST be increased by 1.

The following errors can be returned by the GSS-API interface as specified in [RFC2743]. STATUS_PASSWORD_EXPIRED SHOULD be treated as GSS_S_CREDENTIALS_EXPIRED, SEC_E_INVALID_TOKEN SHOULD be treated as GSS_S_DEFECTIVE_TOKEN, and SEC_E_NO_CREDENTIALS SHOULD be treated as GSS_S_NO_CRED. All other errors SHOULD be treated as a GSS_S_FAILURE error code. A detailed description of these errors is specified in [MS-ERREF].

  • STATUS_DOWNGRADE_DETECTED

  • STATUS_NO_SUCH_LOGON_SESSION

  • SEC_E_WRONG_PRINCIPAL

  • STATUS_NO_SUCH_USER

  • STATUS_ACCOUNT_DISABLED

  • STATUS_ACCOUNT_RESTRICTION

  • STATUS_ACCOUNT_LOCKED_OUT

  • STATUS_WRONG_PASSWORD

  • STATUS_SMARTCARD_WRONG_PIN

  • STATUS_ACCOUNT_EXPIRED

  • STATUS_PASSWORD_EXPIRED

  • STATUS_INVALID_LOGON_HOURS

  • STATUS_INVALID_WORKSTATION

  • STATUS_PASSWORD_MUST_CHANGE

  • STATUS_LOGON_TYPE_NOT_GRANTED

  • STATUS_PASSWORD_RESTRICTION

  • STATUS_SMARTCARD_SILENT_CONTEXT

  • STATUS_SMARTCARD_NO_CARD

  • STATUS_SMARTCARD_CARD_BLOCKED

  • STATUS_PKINIT_FAILURE

  • STATUS_PKINIT_CLIENT_FAILURE

  • STATUS_PKINIT_NAME_MISMATCH

  • STATUS_NETLOGON_NOT_STARTED

  • STATUS_DOMAIN_CONTROLLER_NOT_FOUND

  • STATUS_NO_SUCH_DOMAIN

  • STATUS_BAD_NETWORK_PATH

  • STATUS_TRUST_FAILURE

  • STATUS_TRUSTED_RELATIONSHIP_FAILURE

  • STATUS_NETWORK_UNREACHABLE

  • SEC_E_INVALID_TOKEN

  • SEC_E_NO_AUTHENTICATING_AUTHORITY

  • SEC_E_NO_CREDENTIALS

  • STATUS_INTERNAL_ERROR

  • STATUS_NO_MEMORY

  • SEC_E_NOT_OWNER

  • SEC_E_CERT_WRONG_USAGE

  • SEC_E_SMARTCARD_LOGON_REQUIRED

  • SEC_E_SHUTDOWN_IN_PROGRESS

  • STATUS_LOGON_FAILURE

If the authentication protocol indicates success, the server MUST construct an SMB2 SESSION_SETUP Response, specified in section 2.2.6, as described here:

  • SMB2_FLAGS_SERVER_TO_REDIR MUST be set in the Flags field of the SMB2 header.

  • The output token received from the GSS mechanism MUST be returned in the response. SecurityBufferLength indicates the length of the output token, and SecurityBufferOffset indicates its offset, in bytes, from the beginning of the SMB2 header.

  • Session.SessionId MUST be placed in the SessionId field of the SMB2 header.

If the GSS mechanism indicates that this is the final message in the authentication exchange, the server MUST verify the dialect as follows:

If the server implements the SMB 3.x dialect family and Session.Connection.Dialect is not “2.0.2”, the server MUST look up a client entry in GlobalClientTable using Session.Connection.ClientGuid. If no entry is found, the server MUST create a new Client entry by setting Client.ClientGuid to Session.Connection.ClientGuid and Client.Dialect to Session.Connection.Dialect. The server MUST insert the Client entry into GlobalClientTable. If an entry is found and Client.Dialect is not equal to Session.Connection.Dialect, the server MUST close the newly created Session, as specified in section 3.3.4.12, by providing Session.SessionGlobalId as the input parameter, and fail the session setup request with STATUS_USER_SESSION_DELETED.

If the dialect verification succeeds, the server MUST perform the following:

  1. If Connection.Dialect is "3.1.1" and SMB2_SESSION_FLAG_BINDING is set in the Flags field of the request, the server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating the PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue and the session setup request message, including all bytes from the request's SMB2 header to the last byte received from the network. The server MUST set PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue to the hash value generated above.

    Otherwise, the server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating Session.PreauthIntegrityHashValue and the session setup request message, including all bytes from the request's SMB2 header to the last byte received from the network. The server MUST set Session.PreauthIntegrityHashValue to the hash value generated above.

  2. The status code in the SMB2 header of the response MUST be set to STATUS_SUCCESS. If Connection.Dialect belongs to the SMB 3.x dialect family, the server MUST insert the Session into Connection.SessionTable. If Session.ChannelList does not have a channel entry for which Channel.Connection matches the connection on which this request is received, the server MUST allocate a new Channel object with the following values and insert it into Session.ChannelList:

    • Channel.SigningKey is set to NULL.

    • Channel.Connection is set to the connection on which this request is received.

  3. If Session.SecurityContext is NULL, it MUST be set to a value representing the user that successfully authenticated this connection. The security context MUST be obtained from the GSS authentication subsystem. If Session.SecurityContext is not NULL or the request is for binding the session, no changes are necessary. The server MUST invoke the GSS_Inquire_context call as specified in [RFC2743] section 2.2.6, passing the Session.SecurityContext as the input parameter, and set Session.UserName to the returned "src_name".

  4. The server MUST invoke the GSS_Inquire_context call as specified in [RFC2743] section 2.2.6, passing the Session.SecurityContext as the context_handle parameter.

    If the returned anon_state is TRUE, the server MUST set Session.IsAnonymous to TRUE and the server MAY set the SMB2_SESSION_FLAG_IS_NULL flag in the SessionFlags field of the SMB2 SESSION_SETUP Response.

    Otherwise, if the returned src_name corresponds to an implementation-specific guest user,<292> the server MUST set the SMB2_SESSION_FLAG_IS_GUEST in the SessionFlags field of the SMB2 SESSION_SETUP Response and MUST set Session.IsGuest to TRUE.

    If the server implements the SMB 3.x dialect family and Session.IsAnonymous is FALSE, the server MUST set Connection.ConstrainedConnection to FALSE.

  5. Session.SigningRequired MUST be set to TRUE under the following conditions:

    • If the SMB2_NEGOTIATE_SIGNING_REQUIRED bit is set in the SecurityMode field of the client request.

    • If the SMB2_SESSION_FLAG_IS_GUEST bit is not set in the SessionFlags field and Session.IsAnonymous is FALSE and either Connection.ShouldSign or global RequireMessageSigning is TRUE.

  6. The server MUST query the session key for this authentication from the underlying authentication protocol and store the session key in Session.SessionKey, if Session.SessionKey is NULL. Session.SessionKey MUST be set as specified in section 3.3.1.8, using the value queried from the GSS protocol. If Session.FullSessionKey is empty, Connection.Dialect is “3.1.1”, and Connection.CipherId is AES-256-CCM or AES-256-GCM, Session.FullSessionKey MUST be set to the cryptographic key as queried from the GSS protocol for this authenticated context. For how this value is calculated for Kerberos authentication via GSS-API, see [MS-KILE] section 3.1.1.2. When NTLM authentication via GSS-API is used, Session.SessionKey MUST be set to ExportedSessionKey, see [MS-NLMP] section 3.1.5.1. The server SHOULD choose an authentication mechanism that provides unique and randomly generated session keys in order to secure the integrity of the signing key, encryption key, and decryption key, which are derived using the session key.

  7. If Connection.Dialect belongs to the SMB 3.x dialect family, SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, and the request is not for session reauthentication, the server MUST generate Session.SigningKey as specified in section 3.1.4.2 by providing the following inputs:

    • Session.SessionKey as the key derivation key.

    • If Connection.Dialect is "3.1.1", the case-sensitive ASCII string "SMBSigningKey" as the label; otherwise, the case-sensitive ASCII string "SMB2AESCMAC" as the label.

    • The label buffer size in bytes, including the terminating null character. The size of "SMBSigningKey" is 14. The size of "SMB2AESCMAC" is 12.

    • If Connection.Dialect is "3.1.1", Session.PreauthIntegrityHashValue as the context; otherwise, the case-sensitive ASCII string "SmbSign" as context for the algorithm.

    • The context buffer size in bytes. If Connection.Dialect is "3.1.1", the size of Session.PreauthIntegrityHashValue. Otherwise, the size of "SmbSign", including the terminating null character, is 8.

  8. If Connection.Dialect belongs to the SMB 3.x dialect family, SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, and the request is not for session reauthentication, Session.ApplicationKey MUST be generated as specified in section 3.1.4.2 and passing the following inputs:

    • Session.SessionKey as the key derivation key.

    • If Connection.Dialect is "3.1.1", the case-sensitive ASCII string "SMBAppKey" as the label; otherwise, the case-sensitive ASCII string "SMB2APP" as the label.

    • The label buffer size in bytes, including the terminating null character. The size of "SMBAppKey" is 10. The size of "SMB2APP" is 8.

    • If Connection.Dialect is "3.1.1", Session.PreauthIntegrityHashValue as the context; otherwise, the case-sensitive ASCII string "SmbRpc" as context for the algorithm.

    • The context buffer size in bytes. If Connection.Dialect is "3.1.1", the size of Session.PreauthIntegrityHashValue. Otherwise, the size of "SmbRpc", including the terminating null character, is 7.

  9. If Connection.Dialect belongs to the SMB 3.x dialect family, SMB2_SESSION_FLAG_BINDING is set in the Flags field of the request, and the request is not for session reauthentication, the server MUST generate Channel.SigningKey by providing the following input values:

    • The session key returned by the authentication protocol (in step 6) as the key derivation key.

    • If Connection.Dialect is "3.1.1", the case-sensitive ASCII string "SMBSigningKey" as the label; otherwise, the case-sensitive ASCII string "SMB2AESCMAC" as the label.

    • The label buffer size in bytes, including the terminating null character. The size of "SMBSigningKey" is 14. The size of "SMB2AESCMAC" is 12.

    • If Connection.Dialect is "3.1.1", PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue as the context; otherwise, the case-sensitive ASCII string "SmbSign" as context for the algorithm.

    • The context buffer size in bytes. If Connection.Dialect is "3.1.1", the size of PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue. Otherwise, the size of "SmbSign", including the terminating null character, is 8.

    Otherwise, if Connection.Dialect belongs to the SMB 3.x dialect family and SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, the server MUST set Channel.SigningKey as Session.SigningKey.

    The server MUST remove the PreauthSession object identified by SessionId from Connection.PreauthSessionTable.

  10. If global EncryptData is TRUE, Connection.Dialect belongs to the SMB 3.x dialect family, Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION,  RejectUnencryptedAccess is TRUE, and SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, the server MUST do the following:

    • Set the SMB2_SESSION_FLAG_ENCRYPT_DATA flag in the SessionFlags field of the SMB2 SESSION_SETUP Response.

    • Set Session.SigningRequired to FALSE.

    • Set Session.EncryptData to TRUE.

      Otherwise,

    • Set Session.SigningRequired to TRUE.

    • Set Session.EncryptData to FALSE.

  11. If Connection.Dialect belongs to the SMB 3.x dialect family, SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, Session.IsAnonymous and Session.IsGuest are set to FALSE, Connection.ServerCapabilities includes the SMB2_GLOBAL_CAP_ENCRYPTION bit, and the request is not for session reauthentication, the server MUST do the following:

    • Generate Session.EncryptionKey as specified in section 3.1.4.2 by providing the following inputs:

      • If Connection.Dialect is “3.1.1” and Connection.CipherId is AES-256-CCM or AES-256-GCM, Session.FullSessionKey as the key derivation key. Otherwise, Session.SessionKey as the key derivation key.

      • If Connection.Dialect is "3.1.1", the case-sensitive ASCII string "SMBS2CCipherKey" as the label; otherwise, the case-sensitive ASCII string "SMB2AESCCM" as the label.

      • The label buffer length in bytes, including the terminating null character. The size of "SMBS2CCipherKey" is 16. The size of "SMB2AESCCM" is 11.

      • If Connection.Dialect is "3.1.1", Session.PreauthIntegrityHashValue as the context; otherwise, the case-sensitive ASCII string "ServerOut" as context for the algorithm.

      • The context buffer size in bytes. If Connection.Dialect is "3.1.1", the size of Session.PreauthIntegrityHashValue; otherwise, the size of "ServerOut", including the terminating null character, is 10.

    • Generate Session.DecryptionKey as specified in section 3.1.4.2 by providing the following inputs:

      • If Connection.Dialect is “3.1.1” and Connection.CipherId is AES-256-CCM or AES-256-GCM, Session.FullSessionKey as the key derivation key. Otherwise, Session.SessionKey as the key derivation key.

      • If Connection.Dialect is "3.1.1", the case-sensitive ASCII string "SMBC2SCipherKey" as the label; otherwise, the case-sensitive ASCII string "SMB2AESCCM" as the label.

      • The label buffer length in bytes, including the terminating null character. The size of "SMBC2SCipherKey" is 16. The size of "SMB2AESCCM" is 11.

      • If Connection.Dialect is "3.1.1", Session.PreauthIntegrityHashValue as the context; otherwise, the case-sensitive ASCII string "ServerIn " as context for the algorithm (note the blank space at the end.)

      • The context buffer size in bytes. If Connection.Dialect is "3.1.1", the size of Session.PreauthIntegrityHashValue; otherwise, the size of "ServerIn ", including the terminating null character, is 10.

  12. If the SMB2_SESSION_FLAG_IS_GUEST bit is not set in the SessionFlags field, and Session.IsAnonymous is FALSE, the server MUST sign the final session setup response before sending it to the client, as follows:

    • If Connection.Dialect belongs to the 3.x dialect family, and SMB2_SESSION_FLAG_BINDING is set in the Flags field of the request, the server MUST use Channel.SigningKey.

    • Otherwise, the server MUST use Session.SigningKey.

  13. If the PreviousSessionId field of the request is not equal to zero, the server MUST take the following actions:

    1. The server MUST look up the old session in GlobalSessionTable, where Session.SessionId matches PreviousSessionId. If no session is found, no other processing is necessary.

    2. If a session is found with Session.SessionId equal to PreviousSessionId, the server MUST determine if the old session and the newly established session are created by the same user by comparing the user identifiers obtained from the Session.SecurityContext on the new and old session.

      1. If the PreviousSessionId and SessionId values in the SMB2 header of the request are equal, the server SHOULD<293> ignore PreviousSessionId and no other processing is required.

      2. Otherwise, if the server determines the authentications were for the same user, the server MUST remove the old session from the GlobalSessionTable and also from the Connection.SessionTable, as specified in section 3.3.7.1.

      3. Otherwise, if the server determines that the authentications were for different users, the server MUST ignore the PreviousSessionId value.

  14. Session.State MUST be set to Valid.

  15. Session.ExpirationTime MUST be set to the expiration time returned by the GSS authentication subsystem. If the GSS authentication subsystem does not return an expiration time, the Session.ExpirationTime is set to infinity.

  16. If Connection.Dialect is “3.1.1” and IsServerToClientNotificationsSupported is TRUE, the server MUST set Session.SupportsNotifications to Connection.SupportsNotifications.

The GSS-API can indicate that this is not the final message in the authentication exchange by using the GSS_S_CONTINUE_NEEDED semantics as specified in [MS-SPNG] section 3.3.1. If the GSS mechanism indicates that this is not the final message of the authentication exchange, the following additional steps MUST be taken:

  • The status code in the SMB2 header of the response MUST be set to STATUS_MORE_PROCESSING_REQUIRED.

  • If Connection.Dialect belongs to the SMB 3.x dialect family, and if the SMB2_SESSION_FLAG_BINDING is set in the Flags field of the request, the server MUST sign the response by using Session.SigningKey.

  • If Connection.Dialect is "3.1.1", SMB2_SESSION_FLAG_BINDING is not set in the Flags field of the request, and this is not a session reauthentication request, the server MUST set the preauthentication hash as follows:

    • The server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating Session.PreauthIntegrityHashValue and the session setup request message, including all bytes from the request's SMB2 header to the last byte received from the network. The server MUST set Session.PreauthIntegrityHashValue to the hash value generated above.

    • The server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating Session.PreauthIntegrityHashValue and the session setup response message, including all bytes from the response's SMB2 header to the last byte sent to the network. The server MUST set Session.PreauthIntegrityHashValue to the hash value generated above.

    Otherwise, if Connection.Dialect is "3.1.1", SMB2_SESSION_FLAG_BINDING is set in the Flags field of the request, and the server MUST set the preauthentication hash as follows:

    • The server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue and the session setup request message, including all bytes from the request's SMB2 header to the last byte received from the network. The server MUST set PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue to the hash value generated above.

    • The server MUST generate a hash using the Connection.PreauthIntegrityHashId algorithm on the string constructed by concatenating PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue and the session setup response message, including all bytes from the response's SMB2 header to the last byte sent to the network. The server MUST set PreauthSessionTable.PreauthSession.PreauthIntegrityHashValue to the hash value generated above.