Commit cc92b479 authored by Eric Biggers's avatar Eric Biggers Committed by Steve French
Browse files

ksmbd: Use AES-CMAC library for SMB3 signature calculation



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.

Acked-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
Signed-off-by: default avatarEric Biggers <ebiggers@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent def036ef
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7,13 +7,13 @@ config SMB_SERVER
	select NLS_UTF8
	select NLS_UCS2_UTILS
	select CRYPTO
	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
+13 −38
Original line number Diff line number Diff line
@@ -11,8 +11,8 @@
#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>
@@ -490,46 +490,21 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
 * @sig:	signature value generated for client request packet
 *
 */
int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
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 {
+2 −2
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ 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,
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);
+0 −58
Original line number Diff line number Diff line
@@ -28,14 +28,6 @@ static inline void free_aead(struct crypto_aead *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;
@@ -60,37 +52,10 @@ 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);
@@ -153,29 +118,6 @@ void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
	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;
+0 −12
Original line number Diff line number Diff line
@@ -6,14 +6,8 @@
#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,
@@ -23,19 +17,13 @@ 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);
Loading