smb: client: Use HMAC-SHA256 library for SMB2 signature calculation
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>
This commit is contained in:
committed by
Steve French
parent
4b4c6fdb25
commit
e05b3115e7
+36
-16
@@ -24,14 +24,34 @@
|
||||
#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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user