]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb: client: Use HMAC-SHA256 library for SMB2 signature calculation
authorEric Biggers <ebiggers@kernel.org>
Sun, 12 Oct 2025 01:57:33 +0000 (18:57 -0700)
committerSteve French <stfrench@microsoft.com>
Thu, 16 Oct 2025 03:10:28 +0000 (22:10 -0500)
Convert smb2_calc_signature() to use the HMAC-SHA256 library instead of
a "hmac(sha256)" crypto_shash.  This is simpler and faster.  With the
library there's no need to allocate memory, no need to handle errors,
and the HMAC-SHA256 code is accessed directly without inefficient
indirect calls and other unnecessary API overhead.

To make this possible, make __cifs_calc_signature() support both the
HMAC-SHA256 library and crypto_shash.  (crypto_shash is still needed for
HMAC-MD5 and AES-CMAC.  A later commit will switch HMAC-MD5 from shash
to the library.  I'd like to eventually do the same for AES-CMAC, but it
doesn't have a library API yet.  So for now, shash is still needed.)

Also remove the unnecessary 'sigptr' variable.

For now smb3_crypto_shash_allocate() still allocates a "hmac(sha256)"
crypto_shash.  It will be removed in a later commit.

Reviewed-by: Stefan Metzmacher <metze@samba.org>
Acked-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/cifsencrypt.c
fs/smb/client/cifsproto.h
fs/smb/client/smb2transport.c

index 7b7c8c38fdd08d725e5f69f5c1da0b114b363c30..9522088a1cfb72efa4c7ea7a3b2b5b5b931d9b54 100644 (file)
 #include <linux/iov_iter.h>
 #include <crypto/aead.h>
 #include <crypto/arc4.h>
+#include <crypto/sha2.h>
 
-static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
-                             void *priv, void *priv2)
+static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx,
+                          const u8 *data, size_t len)
 {
-       struct shash_desc *shash = priv;
+       if (ctx->hmac) {
+               hmac_sha256_update(ctx->hmac, data, len);
+               return 0;
+       }
+       return crypto_shash_update(ctx->shash, data, len);
+}
+
+static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
+{
+       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 = crypto_shash_update(shash, iter_base, len);
+       ret = cifs_sig_update(ctx, iter_base, len);
        if (ret < 0) {
                *pret = ret;
                return len;
@@ -42,21 +62,20 @@ static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
 /*
  * Pass the data from an iterator into a hash.
  */
-static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize,
-                          struct shash_desc *shash)
+static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
+                        struct cifs_calc_sig_ctx *ctx)
 {
        struct iov_iter tmp_iter = *iter;
        int err = -EIO;
 
-       if (iterate_and_advance_kernel(&tmp_iter, maxsize, shash, &err,
-                                      cifs_shash_step) != maxsize)
+       if (iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
+                                      cifs_sig_step) != maxsize)
                return err;
        return 0;
 }
 
-int __cifs_calc_signature(struct smb_rqst *rqst,
-                         struct TCP_Server_Info *server, char *signature,
-                         struct shash_desc *shash)
+int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+                         char *signature, struct cifs_calc_sig_ctx *ctx)
 {
        int i;
        ssize_t rc;
@@ -82,8 +101,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
                        return -EIO;
                }
 
-               rc = crypto_shash_update(shash,
-                                        iov[i].iov_base, iov[i].iov_len);
+               rc = cifs_sig_update(ctx, iov[i].iov_base, iov[i].iov_len);
                if (rc) {
                        cifs_dbg(VFS, "%s: Could not update with payload\n",
                                 __func__);
@@ -91,11 +109,11 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
                }
        }
 
-       rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash);
+       rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx);
        if (rc < 0)
                return rc;
 
-       rc = crypto_shash_final(shash, signature);
+       rc = cifs_sig_final(ctx, signature);
        if (rc)
                cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
 
@@ -134,7 +152,9 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
                return rc;
        }
 
-       return __cifs_calc_signature(rqst, server, signature, server->secmech.md5);
+       return __cifs_calc_signature(
+               rqst, server, signature,
+               &(struct cifs_calc_sig_ctx){ .shash = server->secmech.md5 });
 }
 
 /* must be called with server->srv_mutex held */
index e8fba98690ce388fd523894052bbca4b0ec23d11..3bb74eea0e4ff01e7b302840f78822a2ae1a39a8 100644 (file)
@@ -632,9 +632,12 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
                           struct cifs_sb_info *cifs_sb,
                           const unsigned char *path, char *pbuf,
                           unsigned int *pbytes_written);
-int __cifs_calc_signature(struct smb_rqst *rqst,
-                       struct TCP_Server_Info *server, char *signature,
-                       struct shash_desc *shash);
+struct cifs_calc_sig_ctx {
+       struct hmac_sha256_ctx *hmac;
+       struct shash_desc *shash;
+};
+int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+                         char *signature, struct cifs_calc_sig_ctx *ctx);
 enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
                                        enum securityEnum);
 
index bde96eace8c94ad9fd1ace90cb1f41b5f8cd699e..89258accc220341e1359ed3e6239f1b085a35f70 100644 (file)
@@ -254,10 +254,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 {
        int rc;
        unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
-       unsigned char *sigptr = smb2_signature;
        struct kvec *iov = rqst->rq_iov;
        struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-       struct shash_desc *shash = NULL;
+       struct hmac_sha256_ctx hmac_ctx;
        struct smb_rqst drqst;
        __u64 sid = le64_to_cpu(shdr->SessionId);
        u8 key[SMB2_NTLMV2_SESSKEY_SIZE];
@@ -272,30 +271,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
        memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
        memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
-       if (allocate_crypto) {
-               rc = cifs_alloc_hash("hmac(sha256)", &shash);
-               if (rc) {
-                       cifs_server_dbg(VFS,
-                                       "%s: sha256 alloc failed\n", __func__);
-                       goto out;
-               }
-       } else {
-               shash = server->secmech.hmacsha256;
-       }
-
-       rc = crypto_shash_setkey(shash->tfm, key, sizeof(key));
-       if (rc) {
-               cifs_server_dbg(VFS,
-                               "%s: Could not update with response\n",
-                               __func__);
-               goto out;
-       }
-
-       rc = crypto_shash_init(shash);
-       if (rc) {
-               cifs_server_dbg(VFS, "%s: Could not init sha256", __func__);
-               goto out;
-       }
+       hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key));
 
        /*
         * For SMB2+, __cifs_calc_signature() expects to sign only the actual
@@ -306,25 +282,17 @@ smb2_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;
-               }
+               hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len);
                drqst.rq_iov++;
                drqst.rq_nvec--;
        }
 
-       rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
+       rc = __cifs_calc_signature(
+               &drqst, server, smb2_signature,
+               &(struct cifs_calc_sig_ctx){ .hmac = &hmac_ctx });
        if (!rc)
-               memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+               memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE);
 
-out:
-       if (allocate_crypto)
-               cifs_free_hash(&shash);
        return rc;
 }
 
@@ -542,7 +510,6 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 {
        int rc;
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
-       unsigned char *sigptr = smb3_signature;
        struct kvec *iov = rqst->rq_iov;
        struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
        struct shash_desc *shash = NULL;
@@ -603,9 +570,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
                drqst.rq_nvec--;
        }
 
-       rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
+       rc = __cifs_calc_signature(
+               &drqst, server, smb3_signature,
+               &(struct cifs_calc_sig_ctx){ .shash = shash });
        if (!rc)
-               memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+               memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
 
 out:
        if (allocate_crypto)