3.3.5.4 Receiving an SMB2 NEGOTIATE Request

When the server receives a request with an SMB2 header with a Command value equal to SMB2 NEGOTIATE, it MUST process it as follows:

If Connection.NegotiateDialect is 0x0202, 0x0210, 0x0300, 0x0302, or 0x0311, the server MUST disconnect the connection, as specified in section 3.3.7.1, and not reply.

The server MUST set Connection.ClientCapabilities to the capabilities received in the SMB2 NEGOTIATE request.

If the server implements the SMB 3.x dialect family, the server MUST set Connection.ClientSecurityMode to the SecurityMode field of the SMB2 NEGOTIATE Request.

If the server implements the SMB2.1 or 3.x dialect family, the server MUST set Connection.ClientGuid to the ClientGuid field of the SMB2 NEGOTIATE Request.

If SMB2_NEGOTIATE_SIGNING_REQUIRED is set in SecurityMode, the server MUST set Connection.ShouldSign to TRUE.

If the DialectCount of the SMB2 NEGOTIATE Request is 0, the server MUST fail the request with STATUS_INVALID_PARAMETER.

The server MUST select the greatest common dialect between the dialects it implements and the Dialects array of the SMB2 NEGOTIATE request. If a common dialect is not found, the server MUST fail the request with STATUS_NOT_SUPPORTED.

If the server implements the SMB 3.1.1 dialect, the server MUST set Connection.ClientDialects to the Dialects field received in the SMB2 NEGOTIATE request.

If a common dialect is found, the server MUST set Connection.Dialect to "2.0.2", "2.1", "3.0", "3.0.2", or "3.1.1", and Connection.NegotiateDialect to 0x0202, 0x0210, 0x0300, 0x0302, or 0x0311, accordingly, to reflect the dialect selected.

If the Connection.Dialect is "3.1.1", then the server MUST process the NegotiateContextList that is specified by the request's NegotiateContextOffset and NegotiateContextCount fields as follows:

  • If the NegotiateContextList does not contain exactly one SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

  • If the NegotiateContextList contains more than one SMB2_ENCRYPTION_CAPABILITIES negotiate context, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

  • If the NegotiateContextList contains more than one SMB2_COMPRESSION_CAPABILITIES negotiate context, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

  • If the NegotiateContextList contains more than one SMB2_RDMA_TRANSFORM_CAPABILITIES negotiate context, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

  • If the NegotiateContextList contains more than one SMB2_SIGNING_CAPABILITIES negotiate context, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

  • For each context in the received NegotiateContextList, if the context is SMB2_NETNAME_NEGOTIATE_CONTEXT_ID or any negotiate context other than SMB2_PREAUTH_INTEGRITY_CAPABILITIES, SMB2_COMPRESSION_CAPABILITIES, SMB2_RDMA_TRANSFORM_CAPABILITIES, SMB2_SIGNING_CAPABILITIES, SMB2_TRANSPORT_CAPABILITIES, or SMB2_ENCRYPTION_CAPABILITIES, the server MUST ignore the negotiate context.

  • Processing the SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context:

    • If the DataLength of the negotiate context is less than the size of SMB2_PREAUTH_INTEGRITY_CAPABILITIES structure, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

    • If the SMB2_PREAUTH_INTEGRITY_CAPABILITIES HashAlgorithms array does not contain any hash algorithms that the server supports, the server MUST fail the negotiate request with STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP (0xC05D0000).

    • The server MUST set Connection.PreauthIntegrityHashId to one of the hash algorithms in the client's SMB2_PREAUTH_INTEGRITY_CAPABILITIES HashAlgorithms array. When more than one hash algorithm is supported by the server, the policy for selecting a hash algorithm from the set of hash algorithms that the client and server support is implementation-dependent.

    • The server MUST initialize Connection.PreauthIntegrityHashValue with zero.

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

  • Processing the SMB2_ENCRYPTION_CAPABILITIES negotiate context:

    • If the DataLength of the negotiate context is less than the size of the SMB2_ENCRYPTION_CAPABILITIES structure, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

    • The server MUST set Connection.CipherId to one of the ciphers in the client's SMB2_ENCRYPTION_CAPABILITIES Ciphers array in an implementation-specific manner. If the client and server have no common cipher, the server MUST set Connection.CipherId to 0.

  • Processing the SMB2_COMPRESSION_CAPABILITIES negotiate context:

    • If IsCompressionSupported is FALSE, the server MUST ignore the context.

    • The server MUST fail the negotiate request with STATUS_INVALID_PARAMETER if any of the following conditions are satisfied.

      • If the DataLength of the negotiate context is less than the size of the SMB2_COMPRESSION_CAPABILITIES structure.

      • If CompressionAlgorithmCount is equal to zero.

    • The server SHOULD<272> set Connection.CompressionIds to all the supported compression algorithms common to both client and server in the CompressionAlgorithms field, in the order they are received. If the server does not support any of the algorithms provided by the client, Connection.CompressionIds MUST be set to an empty list.

  • Processing the SMB2_RDMA_TRANSFORM_CAPABILITIES negotiate context:

    • If IsRDMATransformSupported is FALSE, the server MUST ignore the context.

    • The server MUST fail the negotiate request with STATUS_INVALID_PARAMETER if any of the following conditions are satisfied:

      • If the DataLength of the negotiate context is less than the size of the SMB2_RDMA_TRANSFORM_CAPABILITIES structure.

      • If TransformCount is equal to zero.

    • The server MUST set Connection.RDMATransformIds to all the supported RDMA transforms common to both client and server in the RDMATransformIds field. If the server does not support any of the RDMA transforms provided by the client, Connection.RDMATransformIds MUST be set to an empty list.

  • Processing the SMB2_SIGNING_CAPABILITIES negotiate context:

    • The server MUST fail the negotiate request with STATUS_INVALID_PARAMETER if any of the following conditions are satisfied:

      • If the DataLength of the negotiate context is less than the size of the SMB2_SIGNING_CAPABILITIES structure.

      • If SigningAlgorithmCount is equal to zero.

    • The server MUST set Connection.SigningAlgorithmId to the supported signing algorithm common to both client and server in the SigningAlgorithms field. If the server does not support any of the signing algorithms provided by the client, Connection.SigningAlgorithmId MUST be set to 1 (AES-CMAC).

  • Processing the SMB2_TRANSPORT_CAPABILITIES negotiate context:

    • If the DataLength of the negotiate context is less than the size of the SMB2_TRANSPORT_CAPABILITIES structure, the server MUST fail the negotiate request with STATUS_INVALID_PARAMETER.

    • If the underlying connection is over QUIC, DisableEncryptionOverSecureTransport is TRUE and SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY is set in the Flags field, the server MUST set Connection.AcceptTransportSecurity to TRUE.

The server MUST then construct an SMB2 NEGOTIATE Response, as specified in section 2.2.4, with the following specific values, and return STATUS_SUCCESS to the client.

If the common dialect is SMB 2.1 or 3.x dialect family and the underlying connection is either TCP port 445 or RDMA, Connection.SupportsMultiCredit MUST be set to TRUE; otherwise, it MUST be set to FALSE.

  • SecurityMode MUST have the SMB2_NEGOTIATE_SIGNING_ENABLED bit set.

  • If RequireMessageSigning is TRUE, the server MUST also set SMB2_NEGOTIATE_SIGNING_REQUIRED in the SecurityMode field.

  • DialectRevision MUST be set to the common dialect.

  • ServerGuid is set to the global ServerGuid value.

  • The Capabilities field MUST be set to a combination of zero or more of the following bit values, as specified in section 2.2.4:

    • SMB2_GLOBAL_CAP_DFS if the server supports the Distributed File System.

    • SMB2_GLOBAL_CAP_LEASING if the server supports leasing.

    • SMB2_GLOBAL_CAP_LARGE_MTU if Connection.SupportsMultiCredit is TRUE.

    • SMB2_GLOBAL_CAP_MULTI_CHANNEL if Connection.Dialect belongs to the SMB 3.x dialect family, IsMultiChannelCapable is TRUE, and SMB2_GLOBAL_CAP_MULTI_CHANNEL is set in the Capabilities field of the request.

    • SMB2_GLOBAL_CAP_DIRECTORY_LEASING if Connection.Dialect belongs to the SMB 3.x dialect family, the server supports directory leasing, and SMB2_GLOBAL_CAP_DIRECTORY_LEASING is set in the Capabilities field of the request.

    • SMB2_GLOBAL_CAP_PERSISTENT_HANDLES if Connection.Dialect belongs to the SMB 3.x dialect family, SMB2_GLOBAL_CAP_PERSISTENT_HANDLES is set in the Capabilities field of the request, and the server supports persistent handles.

    • SMB2_GLOBAL_CAP_ENCRYPTION if Connection.Dialect is "3.0" or "3.0.2", IsEncryptionSupported is TRUE, the server supports AES-128-CCM encryption algorithm and SMB2_GLOBAL_CAP_ENCRYPTION is set in the Capabilities field of the request.

  • MaxTransactSize is set to the maximum buffer size, in bytes, that the server will accept on this connection for QUERY_INFO, QUERY_DIRECTORY, SET_INFO and CHANGE_NOTIFY operations. This field is applicable only for buffers sent by the client in SET_INFO requests, or returned from the server in QUERY_INFO, QUERY_DIRECTORY, and CHANGE_NOTIFY responses. This value SHOULD<273> be greater than or equal to 65536. Connection.MaxTransactSize MUST be set to MaxTransactSize.

  • MaxReadSize is set to the maximum size, in bytes, of the Length in an SMB2 READ Request (section 2.2.19) that the server will accept on the transport that established this connection. This value SHOULD<274> be greater than or equal to 65536. Connection.MaxReadSize MUST be set to MaxReadSize.

  • MaxWriteSize is set to the maximum size, in bytes, of the Length in an SMB2 WRITE Request (section 2.2.21) that the server will accept on the transport that established this connection. This value SHOULD<275> be greater than or equal to 65536. Connection.MaxWriteSize MUST be set to MaxWriteSize.

  • SystemTime is set to the current time, in FILETIME format as specified in [MS-DTYP] section 2.3.3.

  • ServerStartTime SHOULD<276> be set to zero.

  • SecurityBufferOffset is set to the offset to the Buffer field in the response, in bytes, from the beginning of the SMB2 header.

  • SecurityBufferLength is set to the length of the data being returned in the Buffer field.

  • Buffer is filled with the GSS token, generated as follows. Alternatively, an empty Buffer MAY be returned, which elicits client-initiated authentication with an authentication protocol of the client's choice.

The generation of the GSS token for the SMB2 NEGOTIATE Response MUST be done as specified in [MS-SPNG] section 3.2.5.2. The server MUST initialize the mechanism with the Integrity, Confidentiality, and Delegate options and use the server-initiated variation as specified in [MS-SPNG] section 3.2.5.2.

If Connection.Dialect is "3.1.1", then the server MUST build a NegotiateContextList for its negotiate response as follows:

  • Building an SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context:

    • The server MUST add an SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate context to the response's NegotiateContextList.

    • HashAlgorithmCount MUST be set to 1.

    • SaltLength MUST be set to an implementation-specific<277> number of Salt bytes.

    • HashAlgorithms[0] MUST be set to Connection.PreauthIntegrityHashId.

    • The Salt buffer MUST be filled with SaltLength unique bytes that are generated for this response by a cryptographic secure pseudo-random number generator.

  • Building an SMB2_ENCRYPTION_CAPABILITIES negotiate response context:

    • If the server received an SMB2_ENCRYPTION_CAPABILITIES negotiate context in the client's negotiate request, the server MUST add an SMB2_ENCRYPTION_CAPABILITIES negotiate context to the response's NegotiateContextList. Note that the server MUST send an SMB2_ENCRYPTION_CAPABILITIES context even if the client and server have no common cipher. This is done so that the client can differentiate between a server that does not support encryption (no SMB2_ENCRYPTION_CAPABILITIES context in the response's NegotiateContextList) and a server that supports encryption but does not share a cipher with the client (an SMB2_ENCRYPTION_CAPABILITIES context in the response's NegotiateContextList that indicates a cipher of 0).

    • CipherCount MUST be set to 1.

    • Ciphers[0] MUST be set to Connection.CipherId.

  • Building an SMB2_COMPRESSION_CAPABILITIES negotiate response context:

    • If the server processed the SMB2_COMPRESSION_CAPABILITIES negotiate request context, then the server MUST build an SMB2_COMPRESSION_CAPABILITIES negotiate response context by setting the following:

      • If IsChainedCompressionSupported is TRUE and SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED bit is set in Flags field of negotiate request context, SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED bit MUST be set in Flags field and Connection.SupportsChainedCompression MUST be set to TRUE.

      • If Connection.CompressionIds is empty,

        • The server SHOULD<278> set CompressionAlgorithmCount to 1.

        • The server SHOULD<279> set CompressionAlgorithms to “NONE”.

      • Otherwise,

        • Set CompressionAlgorithmCount to the number of compression algorithms in Connection.CompressionIds.

        • Set CompressionAlgorithms to Connection.CompressionIds.

  • Building an SMB2_RDMA_TRANSFORM_CAPABILITIES negotiate response context:

    • If the server processed the SMB2_RDMA_TRANSFORM_CAPABILITIES negotiate request context, then the server MUST build an SMB2_RDMA_TRANSFORM_CAPABILITIES negotiate response context by setting the following:

      • If Connection.RDMATransformIds is empty, set TransformCount to 1 and set RDMATransformIds to SMB2_RDMA_TRANSFORM_NONE.

      • Otherwise, set RDMATransformIds to Connection.RDMATransformIds and set TransformCount to the number of elements in RDMATransformIds.

  • Building an SMB2_SIGNING_CAPABILITIES negotiate response context:

    • If the server processed the SMB2_SIGNING_CAPABILITIES negotiate request context, then the server MUST build an SMB2_SIGNING_CAPABILITIES negotiate response context by setting the following:

      • SigningAlgorithms MUST be set to Connection.SigningAlgorithmId.

      • SigningAlgorithmCount MUST be set to 1.

  • Building an SMB2_TRANSPORT_CAPABILITIES negotiate response context:

    • If the server processed the SMB2_TRANSPORT_CAPABILITIES negotiate request context, then the server MUST build an SMB2_TRANSPORT_CAPABILITIES negotiate response context by setting the following:

    • If Connection.AcceptTransportSecurity is TRUE, Flags MUST be set to SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY.

The status code returned by this operation MUST be one of those defined in [MS-ERREF]. Common status codes returned by this operation include:

  • STATUS_SUCCESS

  • STATUS_INSUFFICIENT_RESOURCES

  • STATUS_INVALID_PARAMETER

  • STATUS_NOT_SUPPORTED

If the server implements the SMB 3.x dialect family, the server MUST store the value of the SecurityMode field in Connection.ServerSecurityMode and MUST store the value of the Capabilities field in Connection.ServerCapabilities.

If Connection.Dialect is "3.1.1", the server MUST do the following:

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

  • If Connection.CipherId is nonzero, the server MUST set the SMB2_GLOBAL_CAP_ENCRYPTION flag in Connection.ServerCapabilities.