From 4c27f85b79e853bf28e774638b4225dbc1defc4c Mon Sep 17 00:00:00 2001
From: Steve French <stfrench@microsoft.com>
Date: Sun, 27 Jun 2021 15:30:24 -0500
Subject: [PATCH] SMB3.1.1: Add support for negotiating signing algorithm
Support for faster packet signing (using GMAC instead of CMAC) can
now be negotiated to some newer servers, including Windows.
See MS-SMB2 section 2.2.3.17.
This patch adds support for sending the new negotiate context
and decoding the response. A followon patch will add support
for changing the signing algorithm used based on what was
negotiated.
To allow the client to request GMAC signing set module parameter
"enable_GMAC_signing" to 1.
Signed-off-by: Steve French <stfrench@microsoft.com>
---
fs/cifs/cifsfs.c | 4 +++
fs/cifs/cifsglob.h | 2 ++
fs/cifs/smb2pdu.c | 77 ++++++++++++++++++++++++++++++++++++++++------
fs/cifs/smb2pdu.h | 5 ++-
4 files changed, 77 insertions(+), 11 deletions(-)
@@ -65,6 +65,7 @@ bool lookupCacheEnabled = true;
bool disable_legacy_dialects; /* false by default */
bool enable_gcm_256 = true;
bool require_gcm_256; /* false by default */
+bool enable_GMAC_signing; /* false by default */
unsigned int global_secflags = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1;
@@ -104,6 +105,9 @@ MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encr
module_param(require_gcm_256, bool, 0644);
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");
+module_param(enable_GMAC_signing, bool, 0644);
+MODULE_PARM_DESC(enable_GMAC_signing, "Enable requesting faster (GMAC) packet signing. Default: n/N/0");
+
module_param(disable_legacy_dialects, bool, 0644);
MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be "
"helpful to restrict the ability to "
@@ -666,6 +666,7 @@ struct TCP_Server_Info {
unsigned int max_write;
unsigned int min_offload;
__le16 compress_algorithm;
+ __le16 signing_algorithm;
__le16 cipher_type;
/* save initital negprot hash */
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
@@ -1868,6 +1869,7 @@ extern unsigned int global_secflags; /* if on, session setup sent
extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */
extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */
+extern bool enable_GMAC_signing; /* request use of faster (GMAC) signing if available */
extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
extern unsigned int CIFSMaxBufSize; /* max size not including hdr */
extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
@@ -433,6 +433,18 @@ build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
}
+static void
+build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
+{
+ pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
+ pneg_ctxt->DataLength =
+ cpu_to_le16(sizeof(struct smb2_signing_capabilities)
+ - sizeof(struct smb2_neg_context));
+ pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(2);
+ pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
+ pneg_ctxt->SigningAlgorithms[1] = cpu_to_le16(SIGNING_ALG_AES_GMAC);
+}
+
static void
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
{
@@ -498,7 +510,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
struct TCP_Server_Info *server, unsigned int *total_len)
{
char *pneg_ctxt;
- unsigned int ctxt_len;
+ unsigned int ctxt_len, neg_context_count;
if (*total_len > 200) {
/* In case length corrupted don't want to overrun smb buffer */
@@ -525,6 +537,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
*total_len += ctxt_len;
pneg_ctxt += ctxt_len;
+ ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
+ server->hostname);
+ *total_len += ctxt_len;
+ pneg_ctxt += ctxt_len;
+
+ build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
+ *total_len += sizeof(struct smb2_posix_neg_context);
+ pneg_ctxt += sizeof(struct smb2_posix_neg_context);
+
+ neg_context_count = 4;
+
if (server->compress_algorithm) {
build_compression_ctxt((struct smb2_compression_capabilities_context *)
pneg_ctxt);
@@ -533,17 +556,24 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
8) * 8;
*total_len += ctxt_len;
pneg_ctxt += ctxt_len;
- req->NegotiateContextCount = cpu_to_le16(5);
- } else
- req->NegotiateContextCount = cpu_to_le16(4);
+ neg_context_count++;
+ }
- ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
- server->hostname);
- *total_len += ctxt_len;
- pneg_ctxt += ctxt_len;
+ if (enable_GMAC_signing) {
+ pr_warn_once("requesting GMAC signing is experimental\n");
+ build_signing_ctxt((struct smb2_signing_capabilities *)
+ pneg_ctxt);
+ ctxt_len = DIV_ROUND_UP(
+ sizeof(struct smb2_signing_capabilities),
+ 8) * 8;
+ *total_len += ctxt_len;
+ pneg_ctxt += ctxt_len;
+ neg_context_count++;
+ }
+
+ /* check for and add transport_capabilities and signing capabilities */
+ req->NegotiateContextCount = cpu_to_le16(neg_context_count);
- build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
- *total_len += sizeof(struct smb2_posix_neg_context);
}
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
@@ -632,6 +662,30 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
return 0;
}
+static void decode_signing_ctx(struct TCP_Server_Info *server,
+ struct smb2_signing_capabilities *pctxt)
+{
+ unsigned int len = le16_to_cpu(pctxt->DataLength);
+
+ if ((len < 4) || (len > 16)) {
+ pr_warn_once("server sent bad signing negcontext\n");
+ return;
+ }
+ if (le16_to_cpu(pctxt->SigningAlgorithmCount) != 1) {
+ pr_warn_once("Invalid signing algorithm count\n");
+ return;
+ }
+ if (le16_to_cpu(pctxt->SigningAlgorithms[0]) > 2) {
+ pr_warn_once("unknown signing algorithm\n");
+ return;
+ }
+ server->signing_algorithm = pctxt->SigningAlgorithms[0];
+
+ cifs_dbg(VFS, "GMAC signing is experimental. Algorithm %d chosen\n",
+ le16_to_cpu(server->signing_algorithm));
+}
+
+
static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
struct TCP_Server_Info *server,
unsigned int len_of_smb)
@@ -675,6 +729,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
(struct smb2_compression_capabilities_context *)pctx);
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
server->posix_ext_supported = true;
+ else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
+ decode_signing_ctx(server,
+ (struct smb2_signing_capabilities *)pctx);
else
cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
le16_to_cpu(pctx->ContextType));
@@ -394,6 +394,7 @@ struct smb2_compression_capabilities_context {
__u16 Padding;
__u32 Flags;
__le16 CompressionAlgorithms[3];
+ /* Check if pad needed */
} __packed;
/*
@@ -420,6 +421,7 @@ struct smb2_transport_capabilities_context {
__le16 DataLength;
__u32 Reserved;
__le32 Flags;
+ __u32 Pad;
} __packed;
/*
@@ -457,7 +459,8 @@ struct smb2_signing_capabilities {
__le16 DataLength;
__u32 Reserved;
__le16 SigningAlgorithmCount;
- __le16 SigningAlgorithms[];
+ __le16 SigningAlgorithms[2]; /* CMAC and GMAC */
+ __u16 Pad; /* Pad to 8 byte rounding */
} __packed;
#define POSIX_CTXT_DATA_LEN 16
--
2.30.2