]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: Use AES-CMAC library for SMB3 signature calculation
authorEric Biggers <ebiggers@kernel.org>
Sat, 18 Apr 2026 22:13:08 +0000 (15:13 -0700)
committerSteve French <stfrench@microsoft.com>
Wed, 22 Apr 2026 14:56:07 +0000 (09:56 -0500)
Convert smb3_calc_signature() to use the AES-CMAC library instead of a
"cmac(aes)" crypto_shash.

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

For now a "cmac(aes)" crypto_shash is still being allocated in
'struct cifs_secmech'.  Later commits will remove that, simplifying the
code even further.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/Kconfig
fs/smb/client/cifsencrypt.c
fs/smb/client/cifsglob.h
fs/smb/client/smb2transport.c

index 63831242fddfb201e6e5dab518df2307671c618d..029bbe595d5fa997ae3a03ee4b6de11e01b06cb9 100644 (file)
@@ -10,6 +10,7 @@ config CIFS
        select CRYPTO_CCM
        select CRYPTO_GCM
        select CRYPTO_AES
+       select CRYPTO_LIB_AES_CBC_MACS
        select CRYPTO_LIB_ARC4
        select CRYPTO_LIB_MD5
        select CRYPTO_LIB_SHA256
index 3d731f3af235f2fef4fc46c2fd84525d8c6f8a97..d092bca2df62dd66256139d51a6964126df3260e 100644 (file)
 #include <linux/fips.h>
 #include <linux/iov_iter.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/arc4.h>
 #include <crypto/md5.h>
 #include <crypto/sha2.h>
 
-static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx,
-                          const u8 *data, size_t len)
+static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
+                           void *priv, void *priv2)
 {
-       if (ctx->md5) {
-               md5_update(ctx->md5, data, len);
-               return 0;
-       }
-       if (ctx->hmac) {
-               hmac_sha256_update(ctx->hmac, data, len);
-               return 0;
-       }
-       return crypto_shash_update(ctx->shash, data, len);
+       struct cifs_calc_sig_ctx *ctx = priv;
+
+       if (ctx->md5)
+               md5_update(ctx->md5, iter_base, len);
+       else if (ctx->hmac)
+               hmac_sha256_update(ctx->hmac, iter_base, len);
+       else
+               aes_cmac_update(ctx->cmac, iter_base, len);
+       return 0; /* Return value is length *not* processed, i.e. 0. */
 }
 
-static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
+static void cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
 {
-       if (ctx->md5) {
+       if (ctx->md5)
                md5_final(ctx->md5, out);
-               return 0;
-       }
-       if (ctx->hmac) {
+       else if (ctx->hmac)
                hmac_sha256_final(ctx->hmac, out);
-               return 0;
-       }
-       return crypto_shash_final(ctx->shash, out);
-}
-
-static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
-                           void *priv, void *priv2)
-{
-       struct cifs_calc_sig_ctx *ctx = priv;
-       int ret, *pret = priv2;
-
-       ret = cifs_sig_update(ctx, iter_base, len);
-       if (ret < 0) {
-               *pret = ret;
-               return len;
-       }
-       return 0;
+       else
+               aes_cmac_final(ctx->cmac, out);
 }
 
 /*
@@ -75,9 +59,8 @@ static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
 {
        struct iov_iter tmp_iter = *iter;
        size_t did;
-       int err;
 
-       did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
+       did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, NULL,
                                         cifs_sig_step);
        if (did != maxsize)
                return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
@@ -108,11 +91,8 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
        if (rc < 0)
                return rc;
 
-       rc = cifs_sig_final(ctx, signature);
-       if (rc)
-               cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
-
-       return rc;
+       cifs_sig_final(ctx, signature);
+       return 0;
 }
 
 /* Build a proper attribute value/target info pairs blob.
index ccfde157d3befa2e0ec0d6dfdd598a1126164efe..74265d055c265ec7029babb22d1b7c16bbf351e4 100644 (file)
@@ -2324,7 +2324,7 @@ static inline void mid_execute_callback(struct TCP_Server_Info *server,
 struct cifs_calc_sig_ctx {
        struct md5_ctx *md5;
        struct hmac_sha256_ctx *hmac;
-       struct shash_desc *shash;
+       struct aes_cmac_ctx *cmac;
 };
 
 #define CIFS_RECONN_DELAY_SECS 30
index 81be2b226e2644284b9b3b5284c95a9034ca049d..b233e0cd9152949d273b5c02779bf0a06975e9c0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mempool.h>
 #include <linux/highmem.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/sha2.h>
 #include <crypto/utils.h>
 #include "cifsglob.h"
@@ -474,7 +475,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        struct kvec *iov = rqst->rq_iov;
        struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-       struct shash_desc *shash = NULL;
+       struct aes_cmac_key cmac_key;
+       struct aes_cmac_ctx cmac_ctx;
        struct smb_rqst drqst;
        u8 key[SMB3_SIGN_KEY_SIZE];
 
@@ -487,33 +489,16 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
                return rc;
        }
 
-       if (allocate_crypto) {
-               rc = cifs_alloc_hash("cmac(aes)", &shash);
-               if (rc)
-                       return rc;
-       } else {
-               shash = server->secmech.aes_cmac;
-       }
-
        memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
        memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
-       rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE);
+       rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
        if (rc) {
                cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
-               goto out;
+               return rc;
        }
 
-       /*
-        * we already allocate aes_cmac when we init smb3 signing key,
-        * so unlike smb2 case we do not have to check here if secmech are
-        * initialized
-        */
-       rc = crypto_shash_init(shash);
-       if (rc) {
-               cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
-               goto out;
-       }
+       aes_cmac_init(&cmac_ctx, &cmac_key);
 
        /*
         * For SMB2+, __cifs_calc_signature() expects to sign only the actual
@@ -524,26 +509,16 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
         */
        drqst = *rqst;
        if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
-               rc = crypto_shash_update(shash, iov[0].iov_base,
-                                        iov[0].iov_len);
-               if (rc) {
-                       cifs_server_dbg(VFS, "%s: Could not update with payload\n",
-                                __func__);
-                       goto out;
-               }
+               aes_cmac_update(&cmac_ctx, iov[0].iov_base, iov[0].iov_len);
                drqst.rq_iov++;
                drqst.rq_nvec--;
        }
 
        rc = __cifs_calc_signature(
                &drqst, server, smb3_signature,
-               &(struct cifs_calc_sig_ctx){ .shash = shash });
+               &(struct cifs_calc_sig_ctx){ .cmac = &cmac_ctx });
        if (!rc)
                memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
-
-out:
-       if (allocate_crypto)
-               cifs_free_hash(&shash);
        return rc;
 }