Skip to content

Commit 53d31a3

Browse files
committed
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 with the first of three supported signing algorithms (AES-CMAC) and decoding the response. A followon patch will add support for sending the other two (including AES-GMAC, which is fastest) and changing the signing algorithm used based on what was negotiated. To allow the client to request GMAC signing set module parameter "enable_negotiate_signing" to 1. Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent e0a3cbc commit 53d31a3

4 files changed

Lines changed: 86 additions & 11 deletions

File tree

fs/cifs/cifsfs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ bool lookupCacheEnabled = true;
6565
bool disable_legacy_dialects; /* false by default */
6666
bool enable_gcm_256 = true;
6767
bool require_gcm_256; /* false by default */
68+
bool enable_negotiate_signing; /* false by default */
6869
unsigned int global_secflags = CIFSSEC_DEF;
6970
/* unsigned int ntlmv2_support = 0; */
7071
unsigned int sign_CIFS_PDUs = 1;
@@ -104,6 +105,9 @@ MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encr
104105
module_param(require_gcm_256, bool, 0644);
105106
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");
106107

108+
module_param(enable_negotiate_signing, bool, 0644);
109+
MODULE_PARM_DESC(enable_negotiate_signing, "Enable negotiating packet signing algorithm with server. Default: n/N/0");
110+
107111
module_param(disable_legacy_dialects, bool, 0644);
108112
MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be "
109113
"helpful to restrict the ability to "

fs/cifs/cifsglob.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,9 +667,11 @@ struct TCP_Server_Info {
667667
unsigned int max_write;
668668
unsigned int min_offload;
669669
__le16 compress_algorithm;
670+
__u16 signing_algorithm;
670671
__le16 cipher_type;
671672
/* save initital negprot hash */
672673
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
674+
bool signing_negotiated; /* true if valid signing context rcvd from server */
673675
bool posix_ext_supported;
674676
struct delayed_work reconnect; /* reconnect workqueue job */
675677
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
@@ -1869,6 +1871,7 @@ extern unsigned int global_secflags; /* if on, session setup sent
18691871
extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
18701872
extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */
18711873
extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */
1874+
extern bool enable_negotiate_signing; /* request use of faster (GMAC) signing if available */
18721875
extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
18731876
extern unsigned int CIFSMaxBufSize; /* max size not including hdr */
18741877
extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */

fs/cifs/smb2pdu.c

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,29 @@ build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
433433
pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
434434
}
435435

436+
static unsigned int
437+
build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
438+
{
439+
unsigned int ctxt_len = sizeof(struct smb2_signing_capabilities);
440+
unsigned short num_algs = 1; /* number of signing algorithms sent */
441+
442+
pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
443+
/*
444+
* Context Data length must be rounded to multiple of 8 for some servers
445+
*/
446+
pneg_ctxt->DataLength = cpu_to_le16(DIV_ROUND_UP(
447+
sizeof(struct smb2_signing_capabilities) -
448+
sizeof(struct smb2_neg_context) +
449+
(num_algs * 2 /* sizeof u16 */), 8) * 8);
450+
pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs);
451+
pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
452+
453+
ctxt_len += 2 /* sizeof le16 */ * num_algs;
454+
ctxt_len = DIV_ROUND_UP(ctxt_len, 8) * 8;
455+
return ctxt_len;
456+
/* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */
457+
}
458+
436459
static void
437460
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
438461
{
@@ -498,7 +521,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
498521
struct TCP_Server_Info *server, unsigned int *total_len)
499522
{
500523
char *pneg_ctxt;
501-
unsigned int ctxt_len;
524+
unsigned int ctxt_len, neg_context_count;
502525

503526
if (*total_len > 200) {
504527
/* In case length corrupted don't want to overrun smb buffer */
@@ -525,6 +548,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
525548
*total_len += ctxt_len;
526549
pneg_ctxt += ctxt_len;
527550

551+
ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
552+
server->hostname);
553+
*total_len += ctxt_len;
554+
pneg_ctxt += ctxt_len;
555+
556+
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
557+
*total_len += sizeof(struct smb2_posix_neg_context);
558+
pneg_ctxt += sizeof(struct smb2_posix_neg_context);
559+
560+
neg_context_count = 4;
561+
528562
if (server->compress_algorithm) {
529563
build_compression_ctxt((struct smb2_compression_capabilities_context *)
530564
pneg_ctxt);
@@ -533,17 +567,20 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
533567
8) * 8;
534568
*total_len += ctxt_len;
535569
pneg_ctxt += ctxt_len;
536-
req->NegotiateContextCount = cpu_to_le16(5);
537-
} else
538-
req->NegotiateContextCount = cpu_to_le16(4);
570+
neg_context_count++;
571+
}
539572

540-
ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
541-
server->hostname);
542-
*total_len += ctxt_len;
543-
pneg_ctxt += ctxt_len;
573+
if (enable_negotiate_signing) {
574+
ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *)
575+
pneg_ctxt);
576+
*total_len += ctxt_len;
577+
pneg_ctxt += ctxt_len;
578+
neg_context_count++;
579+
}
580+
581+
/* check for and add transport_capabilities and signing capabilities */
582+
req->NegotiateContextCount = cpu_to_le16(neg_context_count);
544583

545-
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
546-
*total_len += sizeof(struct smb2_posix_neg_context);
547584
}
548585

549586
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
@@ -632,6 +669,31 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
632669
return 0;
633670
}
634671

672+
static void decode_signing_ctx(struct TCP_Server_Info *server,
673+
struct smb2_signing_capabilities *pctxt)
674+
{
675+
unsigned int len = le16_to_cpu(pctxt->DataLength);
676+
677+
if ((len < 4) || (len > 16)) {
678+
pr_warn_once("server sent bad signing negcontext\n");
679+
return;
680+
}
681+
if (le16_to_cpu(pctxt->SigningAlgorithmCount) != 1) {
682+
pr_warn_once("Invalid signing algorithm count\n");
683+
return;
684+
}
685+
if (le16_to_cpu(pctxt->SigningAlgorithms[0]) > 2) {
686+
pr_warn_once("unknown signing algorithm\n");
687+
return;
688+
}
689+
690+
server->signing_negotiated = true;
691+
server->signing_algorithm = le16_to_cpu(pctxt->SigningAlgorithms[0]);
692+
cifs_dbg(FYI, "signing algorithm %d chosen\n",
693+
server->signing_algorithm);
694+
}
695+
696+
635697
static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
636698
struct TCP_Server_Info *server,
637699
unsigned int len_of_smb)
@@ -675,6 +737,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
675737
(struct smb2_compression_capabilities_context *)pctx);
676738
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
677739
server->posix_ext_supported = true;
740+
else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
741+
decode_signing_ctx(server,
742+
(struct smb2_signing_capabilities *)pctx);
678743
else
679744
cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
680745
le16_to_cpu(pctx->ContextType));

fs/cifs/smb2pdu.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ struct smb2_neg_context {
329329
__le16 ContextType;
330330
__le16 DataLength;
331331
__le32 Reserved;
332-
/* Followed by array of data */
332+
/* Followed by array of data. NOTE: some servers require padding to 8 byte boundary */
333333
} __packed;
334334

335335
#define SMB311_LINUX_CLIENT_SALT_SIZE 32
@@ -394,6 +394,7 @@ struct smb2_compression_capabilities_context {
394394
__u16 Padding;
395395
__u32 Flags;
396396
__le16 CompressionAlgorithms[3];
397+
/* Check if pad needed */
397398
} __packed;
398399

399400
/*
@@ -420,6 +421,7 @@ struct smb2_transport_capabilities_context {
420421
__le16 DataLength;
421422
__u32 Reserved;
422423
__le32 Flags;
424+
__u32 Pad;
423425
} __packed;
424426

425427
/*
@@ -458,6 +460,7 @@ struct smb2_signing_capabilities {
458460
__u32 Reserved;
459461
__le16 SigningAlgorithmCount;
460462
__le16 SigningAlgorithms[];
463+
/* Followed by padding to 8 byte boundary (required by some servers) */
461464
} __packed;
462465

463466
#define POSIX_CTXT_DATA_LEN 16

0 commit comments

Comments
 (0)