Skip to content

Non-encrypted case should be negotiated consistently when using dialect 3.1.1 #747

@turcsanyip

Description

@turcsanyip

SMBJ 0.11.x introduced SMB 3.x support with (optionally enabled) encryption feature, configurable via SmbConfig.Builder.withEncryptData(boolean).

When using 3.0 dialect, the encryption is negotiated properly with the server:

  • if withEncryptData is set to true, the library sends SMB2_GLOBAL_CAP_ENCRYPTION capability in the negotiate request to the server, and if the server also supports encryption (answers with the same capability), the client will use encryption
  • if withEncryptData is set to false (default), the library does not send the encryption capability and will not use encryption (regardless of the server's response)

So the library uses encryption only if both sides claimed that they support encryption during the protocol negotiation, which I believe the proper behaviour.

In case of 3.1.1 dialect, the library decides based on the servers response only and does not take into account whether the encryption was set via withEncryptData(true) and the capability was sent to the server, or not.

It works for the withEncryptData(true) case but leads to inconsistent behaviour with some servers when withEncryptData(false) (and therefore no encryption capability was sent from the client side):

  • Samba running on Ubuntu 20.04 does not send back encryption info in this case and smbj will not use encryption
  • Windows Server 2002 sends back the encryption info, and based on this smbj will turn on encryption (and the communication will be successful)
  • NetApp Files sends back the encryption info, and based on this smbj will turn on encryption but the communication will fail (it seems NetApp Files does not tolerate that the client does not claim encryption capability but then tries to use encryption, which sounds reasonable from the server's perspective)

The first 2 cases are just inconsistent but the 3rd one is a concrete failure in the communication between the client and the server.

For these reasons, I would suggest taking into account also the client side encryption setting (not just the server's response) when encryption is determined in case of 3.1.1 (similar to 3.0):
ConnectionContext. supportsEncryption()

    public boolean supportsEncryption() {
        SMB2Dialect dialect = negotiatedProtocol.getDialect();
        if (dialect == SMB2Dialect.SMB_3_1_1) {
            return cipherId != null; // clientCapabilities.contains(SMB2GlobalCapability.SMB2_GLOBAL_CAP_ENCRYPTION) should be checked here too
        } else {
            return clientCapabilities.contains(SMB2GlobalCapability.SMB2_GLOBAL_CAP_ENCRYPTION)
                && supports(SMB2GlobalCapability.SMB2_GLOBAL_CAP_ENCRYPTION);
        }
    }

Error stack trace (no useful info related to the root cause though):

12:02:09.704 [main] DEBUG com.hierynomus.smbj.connection.Connection - Granted 1 (out of 128) credits to Encrypted[SMB2_CREATE with message id << 4 >>]
12:02:09.704 [main] DEBUG com.hierynomus.smbj.transport.tcp.direct.DirectTcpTransport - Writing packet Encrypted[SMB2_CREATE with message id << 4 >>]
12:02:09.705 [main] DEBUG com.hierynomus.protocol.commons.concurrent.Promise - Awaiting << 4 >>
12:02:09.813 [Packet Reader for localhost] DEBUG com.hierynomus.smbj.transport.tcp.direct.DirectTcpPacketReader - Received packet Encrypted for session id << -7976719365003134876 >>
12:02:09.813 [Packet Reader for localhost] DEBUG com.hierynomus.smbj.connection.packet.SMB3DecryptingPacketHandler - Decrypting packet Encrypted for session id << -7976719365003134876 >>
12:02:09.814 [Packet Reader for localhost] DEBUG com.hierynomus.smbj.connection.packet.SMB3DecryptingPacketHandler - Decrypted packet Encrypted for session id << -7976719365003134876 >> is packet SMB2_CREATE with message id << 4 >>.
12:02:09.814 [Packet Reader for localhost] DEBUG com.hierynomus.smbj.connection.packet.SMB2SignatureVerificationPacketHandler - Passthrough Signature Verification as packet is decrypted
12:02:09.814 [Packet Reader for localhost] DEBUG com.hierynomus.smbj.connection.packet.SMB2CreditGrantingPacketHandler - Server granted us 1 credits for SMB2_CREATE with message id << 4 >>, now available: 128 credits
12:02:09.814 [Packet Reader for localhost] DEBUG com.hierynomus.protocol.commons.concurrent.Promise - Setting << 4 >> to `SMB2_CREATE with message id << 4 >>`
Exception in thread "main" com.hierynomus.mssmb2.SMBApiException: STATUS_ACCESS_DENIED (0xc0000022): Create failed for \\localhost\netapp-vol2
	at com.hierynomus.smbj.share.Share.receive(Share.java:380)
	at com.hierynomus.smbj.share.Share.sendReceive(Share.java:359)
	at com.hierynomus.smbj.share.Share.createFile(Share.java:156)
	at com.hierynomus.smbj.share.DiskShare.createFileAndResolve(DiskShare.java:75)
	at com.hierynomus.smbj.share.DiskShare.access$100(DiskShare.java:55)
	at com.hierynomus.smbj.share.DiskShare$2.apply(DiskShare.java:109)
	at com.hierynomus.smbj.share.DiskShare$2.apply(DiskShare.java:105)
	at com.hierynomus.smbj.paths.PathResolver$1.resolve(PathResolver.java:32)
	at com.hierynomus.smbj.paths.SymlinkPathResolver.resolve(SymlinkPathResolver.java:62)
	at com.hierynomus.smbj.share.DiskShare.resolveAndCreateFile(DiskShare.java:105)
	at com.hierynomus.smbj.share.DiskShare.open(DiskShare.java:65)
	at com.hierynomus.smbj.share.DiskShare.openDirectory(DiskShare.java:151)
	at ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions