Subject: [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation

From: Eric Biggers <[email-masked]>
Date: Wed, 18 Feb 2026 13:34:58 -0800

Now that AES-CMAC has a library API, convert ksmbd_sign_smb3_pdu() to
use it instead of a "cmac(aes)" crypto_shash.

The result is simpler and faster code.  With the library there's no need
to dynamically allocate memory, no need to handle errors, and the
AES-CMAC code is accessed directly without inefficient indirect calls
and other unnecessary API overhead.

Signed-off-by: Eric Biggers <[email-masked]>
---
 fs/smb/server/Kconfig      |  2 +-
 fs/smb/server/auth.c       | 51 +++++++++------------------------
 fs/smb/server/auth.h       |  4 +--
 fs/smb/server/crypto_ctx.c | 58 --------------------------------------
 fs/smb/server/crypto_ctx.h | 12 --------
 fs/smb/server/server.c     |  1 -
 fs/smb/server/smb2pdu.c    |  8 ++----
 7 files changed, 19 insertions(+), 117 deletions(-)

diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig
index 12594879cb64..eae3728cff54 100644
--- a/fs/smb/server/Kconfig
+++ b/fs/smb/server/Kconfig
@@ -6,17 +6,17 @@ config SMB_SERVER
 	select NLS
 	select NLS_UTF8
 	select NLS_UCS2_UTILS
 	select CRYPTO
 	select CRYPTO_ECB
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_LIB_ARC4
 	select CRYPTO_LIB_DES
 	select CRYPTO_LIB_MD5
 	select CRYPTO_LIB_SHA256
 	select CRYPTO_LIB_SHA512
 	select CRYPTO_LIB_UTILS
-	select CRYPTO_CMAC
 	select CRYPTO_AEAD2
 	select CRYPTO_CCM
 	select CRYPTO_GCM
 	select ASN1
 	select OID_REGISTRY
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index a69e8694605a..05234e5bd16e 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -9,12 +9,12 @@
 #include <linux/uaccess.h>
 #include <linux/backing-dev.h>
 #include <linux/writeback.h>
 #include <linux/uio.h>
 #include <linux/xattr.h>
-#include <crypto/hash.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/md5.h>
 #include <crypto/sha2.h>
 #include <crypto/utils.h>
 #include <linux/random.h>
 #include <linux/scatterlist.h>
@@ -488,50 +488,25 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
  * @iov:        buffer iov array
  * @n_vec:	number of iovecs
  * @sig:	signature value generated for client request packet
  *
  */
-int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
-			int n_vec, char *sig)
+void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+			 int n_vec, char *sig)
 {
-	struct ksmbd_crypto_ctx *ctx;
-	int rc, i;
-
-	ctx = ksmbd_crypto_ctx_find_cmacaes();
-	if (!ctx) {
-		ksmbd_debug(AUTH, "could not crypto alloc cmac\n");
-		return -ENOMEM;
-	}
-
-	rc = crypto_shash_setkey(CRYPTO_CMACAES_TFM(ctx),
-				 key,
-				 SMB2_CMACAES_SIZE);
-	if (rc)
-		goto out;
-
-	rc = crypto_shash_init(CRYPTO_CMACAES(ctx));
-	if (rc) {
-		ksmbd_debug(AUTH, "cmaces init error %d\n", rc);
-		goto out;
-	}
+	struct aes_cmac_key cmac_key;
+	struct aes_cmac_ctx cmac_ctx;
+	int i;
 
-	for (i = 0; i < n_vec; i++) {
-		rc = crypto_shash_update(CRYPTO_CMACAES(ctx),
-					 iov[i].iov_base,
-					 iov[i].iov_len);
-		if (rc) {
-			ksmbd_debug(AUTH, "cmaces update error %d\n", rc);
-			goto out;
-		}
-	}
+	/* This cannot fail, since we always pass a valid key length. */
+	static_assert(SMB2_CMACAES_SIZE == AES_KEYSIZE_128);
+	aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
 
-	rc = crypto_shash_final(CRYPTO_CMACAES(ctx), sig);
-	if (rc)
-		ksmbd_debug(AUTH, "cmaces generation error %d\n", rc);
-out:
-	ksmbd_release_crypto_ctx(ctx);
-	return rc;
+	aes_cmac_init(&cmac_ctx, &cmac_key);
+	for (i = 0; i < n_vec; i++)
+		aes_cmac_update(&cmac_ctx, iov[i].iov_base, iov[i].iov_len);
+	aes_cmac_final(&cmac_ctx, sig);
 }
 
 struct derivation {
 	struct kvec label;
 	struct kvec context;
diff --git a/fs/smb/server/auth.h b/fs/smb/server/auth.h
index 6d351d61b0e5..5767aabc63c9 100644
--- a/fs/smb/server/auth.h
+++ b/fs/smb/server/auth.h
@@ -52,12 +52,12 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
 				   struct ksmbd_conn *conn);
 int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
 			    int in_len,	char *out_blob, int *out_len);
 void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
 			 int n_vec, char *sig);
-int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
-			int n_vec, char *sig);
+void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+			 int n_vec, char *sig);
 int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
 			       struct ksmbd_conn *conn);
 int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
 				struct ksmbd_conn *conn);
 void ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c
index fe29d186baf6..1cb0ea2042b5 100644
--- a/fs/smb/server/crypto_ctx.c
+++ b/fs/smb/server/crypto_ctx.c
@@ -26,18 +26,10 @@ static inline void free_aead(struct crypto_aead *aead)
 {
 	if (aead)
 		crypto_free_aead(aead);
 }
 
-static void free_shash(struct shash_desc *shash)
-{
-	if (shash) {
-		crypto_free_shash(shash->tfm);
-		kfree(shash);
-	}
-}
-
 static struct crypto_aead *alloc_aead(int id)
 {
 	struct crypto_aead *tfm = NULL;
 
 	switch (id) {
@@ -58,41 +50,14 @@ static struct crypto_aead *alloc_aead(int id)
 	}
 
 	return tfm;
 }
 
-static struct shash_desc *alloc_shash_desc(int id)
-{
-	struct crypto_shash *tfm = NULL;
-	struct shash_desc *shash;
-
-	switch (id) {
-	case CRYPTO_SHASH_CMACAES:
-		tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
-		break;
-	default:
-		return NULL;
-	}
-
-	if (IS_ERR(tfm))
-		return NULL;
-
-	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
-			KSMBD_DEFAULT_GFP);
-	if (!shash)
-		crypto_free_shash(tfm);
-	else
-		shash->tfm = tfm;
-	return shash;
-}
-
 static void ctx_free(struct ksmbd_crypto_ctx *ctx)
 {
 	int i;
 
-	for (i = 0; i < CRYPTO_SHASH_MAX; i++)
-		free_shash(ctx->desc[i]);
 	for (i = 0; i < CRYPTO_AEAD_MAX; i++)
 		free_aead(ctx->ccmaes[i]);
 	kfree(ctx);
 }
 
@@ -151,33 +116,10 @@ void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
 	ctx_list.avail_ctx--;
 	spin_unlock(&ctx_list.ctx_lock);
 	ctx_free(ctx);
 }
 
-static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id)
-{
-	struct ksmbd_crypto_ctx *ctx;
-
-	if (id >= CRYPTO_SHASH_MAX)
-		return NULL;
-
-	ctx = ksmbd_find_crypto_ctx();
-	if (ctx->desc[id])
-		return ctx;
-
-	ctx->desc[id] = alloc_shash_desc(id);
-	if (ctx->desc[id])
-		return ctx;
-	ksmbd_release_crypto_ctx(ctx);
-	return NULL;
-}
-
-struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
-{
-	return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES);
-}
-
 static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)
 {
 	struct ksmbd_crypto_ctx *ctx;
 
 	if (id >= CRYPTO_AEAD_MAX)
diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h
index b9476ed520ae..02d2893665a4 100644
--- a/fs/smb/server/crypto_ctx.h
+++ b/fs/smb/server/crypto_ctx.h
@@ -4,18 +4,12 @@
  */
 
 #ifndef __CRYPTO_CTX_H__
 #define __CRYPTO_CTX_H__
 
-#include <crypto/hash.h>
 #include <crypto/aead.h>
 
-enum {
-	CRYPTO_SHASH_CMACAES	= 0,
-	CRYPTO_SHASH_MAX,
-};
-
 enum {
 	CRYPTO_AEAD_AES_GCM = 16,
 	CRYPTO_AEAD_AES_CCM,
 	CRYPTO_AEAD_MAX,
 };
@@ -26,23 +20,17 @@ enum {
 };
 
 struct ksmbd_crypto_ctx {
 	struct list_head		list;
 
-	struct shash_desc		*desc[CRYPTO_SHASH_MAX];
 	struct crypto_aead		*ccmaes[CRYPTO_AEAD_MAX];
 };
 
-#define CRYPTO_CMACAES(c)	((c)->desc[CRYPTO_SHASH_CMACAES])
-
-#define CRYPTO_CMACAES_TFM(c)	((c)->desc[CRYPTO_SHASH_CMACAES]->tfm)
-
 #define CRYPTO_GCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_GCM])
 #define CRYPTO_CCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_CCM])
 
 void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx);
-struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void);
 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void);
 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void);
 void ksmbd_crypto_destroy(void);
 int ksmbd_crypto_create(void);
 
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index c2c074346da1..cc15d9d8468f 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -631,11 +631,10 @@ MODULE_AUTHOR("Namjae Jeon <[email-masked]>");
 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
 MODULE_LICENSE("GPL");
 MODULE_SOFTDEP("pre: ecb");
 MODULE_SOFTDEP("pre: nls");
 MODULE_SOFTDEP("pre: aes");
-MODULE_SOFTDEP("pre: cmac");
 MODULE_SOFTDEP("pre: aead2");
 MODULE_SOFTDEP("pre: ccm");
 MODULE_SOFTDEP("pre: gcm");
 module_init(ksmbd_server_init)
 module_exit(ksmbd_server_exit)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 7a88cf3bd29e..02bfe15edcab 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8964,12 +8964,11 @@ int smb3_check_sign_req(struct ksmbd_work *work)
 	memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 	iov[0].iov_base = (char *)&hdr->ProtocolId;
 	iov[0].iov_len = len;
 
-	if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))
-		return 0;
+	ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature);
 
 	if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
 		pr_err("bad smb2 signature\n");
 		return 0;
 	}
@@ -9016,13 +9015,12 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 		n_vec++;
 	} else {
 		iov = &work->iov[work->iov_idx];
 	}
 
-	if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec,
-				 signature))
-		memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
+	ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature);
+	memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
 }
 
 /**
  * smb3_preauth_hash_rsp() - handler for computing preauth hash on response
  * @work:   smb work containing response buffer
-- 
2.53.0