diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 4c10f6d681..0e58d4f11b 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -63,6 +63,7 @@ CONFIG_COMPILER_OPTIMIZATION_PERF CONFIG_COMPILER_OPTIMIZATION_SIZE CONFIG_CRYPTO_AES CONFIG_CRYPTO_CBC +CONFIG_CRYPTO_CCM CONFIG_CRYPTO_CTR CONFIG_CRYPTO_DH CONFIG_CRYPTO_DH_RFC7919_GROUPS diff --git a/configure.ac b/configure.ac index e1e142174f..542151e22c 100644 --- a/configure.ac +++ b/configure.ac @@ -10252,6 +10252,10 @@ then AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_AESGCM" ;; 'rfc4106(gcm(aes))') test "$ENABLED_AESGCM" != "no" || AC_MSG_ERROR([linuxkm-lkcapi-register ${lkcapi_alg}: AES-GCM implementation not enabled.]) AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106" ;; + 'ccm(aes)') test "$ENABLED_AESCCM" != "no" || AC_MSG_ERROR([linuxkm-lkcapi-register ${lkcapi_alg}: AES-CCM implementation not enabled.]) + AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_AESCCM" ;; + 'rfc4309(ccm(aes))') test "$ENABLED_AESCCM" != "no" || AC_MSG_ERROR([linuxkm-lkcapi-register ${lkcapi_alg}: AES-CCM implementation not enabled.]) + AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309" ;; 'xts(aes)') test "$ENABLED_AESXTS" != "no" || AC_MSG_ERROR([linuxkm-lkcapi-register ${lkcapi_alg}: AES-XTS implementation not enabled.]) test "$ENABLED_AESXTS_STREAM" != "no" || AC_MSG_ERROR([linuxkm-lkcapi-register ${lkcapi_alg}: --enable-aesxts-stream is required for LKCAPI.]) AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_AESXTS" ;; @@ -10296,6 +10300,9 @@ then '-gcm(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESGCM" ;; '-rfc4106(gcm(aes))') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESGCM_RFC4106" ;; + '-ccm(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESCCM" ;; + '-rfc4309(ccm(aes))') + AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESCCM_RFC4309" ;; '-xts(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESXTS" ;; '-ctr(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESCTR" ;; '-ofb(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESOFB" ;; diff --git a/linuxkm/lkcapi_aes_glue.c b/linuxkm/lkcapi_aes_glue.c index 7cd572bb22..78f5d0842b 100644 --- a/linuxkm/lkcapi_aes_glue.c +++ b/linuxkm/lkcapi_aes_glue.c @@ -38,6 +38,8 @@ defined(LINUXKM_LKCAPI_REGISTER_AESCFB) || \ defined(LINUXKM_LKCAPI_REGISTER_AESGCM) || \ defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) || \ defined(LINUXKM_LKCAPI_REGISTER_AESXTS) || \ defined(LINUXKM_LKCAPI_REGISTER_AESCTR) || \ defined(LINUXKM_LKCAPI_REGISTER_AESOFB) || \ @@ -87,6 +89,8 @@ #define WOLFKM_AESCFB_NAME "cfb(aes)" #define WOLFKM_AESGCM_NAME "gcm(aes)" #define WOLFKM_AESGCM_RFC4106_NAME "rfc4106(gcm(aes))" +#define WOLFKM_AESCCM_NAME "ccm(aes)" +#define WOLFKM_AESCCM_RFC4309_NAME "rfc4309(ccm(aes))" #define WOLFKM_AESXTS_NAME "xts(aes)" #define WOLFKM_AESCTR_NAME "ctr(aes)" #define WOLFKM_AESOFB_NAME "ofb(aes)" @@ -107,6 +111,8 @@ #define WOLFKM_AESCFB_DRIVER ("cfb-aes" WOLFKM_AES_DRIVER_SUFFIX) #define WOLFKM_AESGCM_DRIVER ("gcm-aes" WOLFKM_AES_DRIVER_SUFFIX) #define WOLFKM_AESGCM_RFC4106_DRIVER ("rfc4106-gcm-aes" WOLFKM_AES_DRIVER_SUFFIX) +#define WOLFKM_AESCCM_DRIVER ("ccm-aes" WOLFKM_AES_DRIVER_SUFFIX) +#define WOLFKM_AESCCM_RFC4309_DRIVER ("rfc4309-ccm-aes" WOLFKM_AES_DRIVER_SUFFIX) #define WOLFKM_AESXTS_DRIVER ("xts-aes" WOLFKM_AES_DRIVER_SUFFIX) #define WOLFKM_AESCTR_DRIVER ("ctr-aes" WOLFKM_AES_DRIVER_SUFFIX) #define WOLFKM_AESOFB_DRIVER ("ofb-aes" WOLFKM_AES_DRIVER_SUFFIX) @@ -146,7 +152,8 @@ #define LINUXKM_LKCAPI_REGISTER_AESGCM #endif #if ((defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ - defined(LINUXKM_LKCAPI_REGISTER_AES_ALL)) && \ + defined(LINUXKM_LKCAPI_REGISTER_AES_ALL) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_GCM))) && \ !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESGCM_RFC4106)) && \ !defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) #define LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 @@ -159,6 +166,29 @@ #undef LINUXKM_LKCAPI_REGISTER_AESGCM #undef LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 #endif +#ifdef HAVE_AESCCM + #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_AES_ALL) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CCM))) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESCCM) && \ + !defined(LINUXKM_LKCAPI_REGISTER_AESCCM) + #define LINUXKM_LKCAPI_REGISTER_AESCCM + #endif + #if ((defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_AES_ALL) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CCM))) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESCCM_RFC4309)) && \ + !defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) + #define LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + #endif +#else + #if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_CCM) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_AESCCM) + #error Config conflict: target kernel has CONFIG_CRYPTO_CCM, but module is missing HAVE_AESCCM. + #endif + #undef LINUXKM_LKCAPI_REGISTER_AESCCM + #undef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 +#endif #ifdef WOLFSSL_AES_XTS #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ defined(LINUXKM_LKCAPI_REGISTER_AES_ALL) || \ @@ -227,6 +257,12 @@ #ifdef LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 static int linuxkm_test_aesgcm_rfc4106(void); #endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + static int linuxkm_test_aesccm(void); +#endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + static int linuxkm_test_aesccm_rfc4309(void); +#endif #ifdef LINUXKM_LKCAPI_REGISTER_AESXTS static int linuxkm_test_aesxts(void); #endif @@ -246,7 +282,9 @@ defined(LINUXKM_LKCAPI_REGISTER_AESOFB) || \ defined(LINUXKM_LKCAPI_REGISTER_AESECB) || \ defined(LINUXKM_LKCAPI_REGISTER_AESGCM) || \ - defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) + defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) #define LINUXKM_LKCAPI_NEED_AES_COMMON_FUNCS #endif @@ -259,7 +297,9 @@ #endif #if defined(LINUXKM_LKCAPI_REGISTER_AESGCM) || \ - defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) + defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) #define LINUXKM_LKCAPI_REGISTER_AEADS #endif @@ -275,8 +315,12 @@ struct km_AesCtx { Aes *aes_encrypt_C; /* fallback if vector registers aren't available. */ Aes *aes_decrypt_C; #endif -#ifdef LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 - byte rfc4106_nonce[4]; +#if defined(LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) + union { + byte rfc4106_nonce[4]; + byte rfc4309_nonce[3]; + }; #endif }; @@ -1551,6 +1595,493 @@ static int gcmAesAead_rfc4106_loaded = 0; #endif /* LINUXKM_LKCAPI_REGISTER_AESGCM || LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 */ +#if defined(LINUXKM_LKCAPI_REGISTER_AESCCM) || \ + defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) + +static int km_AesCcmInit(struct crypto_aead * tfm) +{ + struct km_AesCtx * ctx = crypto_aead_ctx(tfm); + return km_AesInitCommon(ctx, WOLFKM_AESCCM_DRIVER, 0); +} + +static void km_AesCcmExit(struct crypto_aead * tfm) +{ + struct km_AesCtx * ctx = crypto_aead_ctx(tfm); + km_AesExitCommon(ctx); +} + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + +static int km_AesCcmSetKey(struct crypto_aead *tfm, const u8 *in_key, + unsigned int key_len) +{ + int err; + struct km_AesCtx * ctx = crypto_aead_ctx(tfm); + + err = wc_AesCcmSetKey(ctx->aes_encrypt, in_key, key_len); + + if (unlikely(err)) { + if ((! disable_setkey_warnings) && ((key_len == 16) || (key_len == 24) || (key_len == 32))) + pr_err("%s: wc_AesCcmSetKey failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); + return -EINVAL; + } + +#ifdef WC_LINUXKM_C_FALLBACK_IN_SHIMS + if (ctx->aes_encrypt->use_aesni) { + ctx->aes_encrypt_C->use_aesni = WC_FLAG_DONT_USE_VECTOR_OPS; + + err = wc_AesCcmSetKey(ctx->aes_encrypt_C, in_key, key_len); + + if (unlikely(err)) { + if ((! disable_setkey_warnings) && ((key_len == 16) || (key_len == 24) || (key_len == 32))) + pr_err("%s: wc_AesCcmSetKey failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); + return -EINVAL; + } + + if (ctx->aes_encrypt_C->use_aesni) + pr_err("%s: after wc_AesCcmSetKey, ctx->aes_encrypt_C has AES-NI asserted.\n", WOLFKM_AESCCM_DRIVER); + } +#endif + + #ifdef WOLFKM_DEBUG_AES + pr_info("info: exiting km_AesCcmSetKey: %d\n", key_len); + #endif /* WOLFKM_DEBUG_AES */ + return 0; +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM */ + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + +static int km_AesCcmSetKey_Rfc4309(struct crypto_aead *tfm, const u8 *in_key, + unsigned int key_len) +{ + int err; + struct km_AesCtx * ctx = crypto_aead_ctx(tfm); + + if (key_len < 3) + return -EINVAL; + key_len -= 3; + memcpy(ctx->rfc4309_nonce, in_key + key_len, 3); + + err = wc_AesCcmSetKey(ctx->aes_encrypt, in_key, key_len); + + if (unlikely(err)) { + if ((! disable_setkey_warnings) && ((key_len == 16) || (key_len == 24) || (key_len == 32))) + pr_err("%s: wc_AesCcmSetKey failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); + return -EINVAL; + } + +#ifdef WC_LINUXKM_C_FALLBACK_IN_SHIMS + if (ctx->aes_encrypt->use_aesni) { + ctx->aes_encrypt_C->use_aesni = WC_FLAG_DONT_USE_VECTOR_OPS; + + err = wc_AesCcmSetKey(ctx->aes_encrypt_C, in_key, key_len); + + if (unlikely(err)) { + if ((! disable_setkey_warnings) && ((key_len == 16) || (key_len == 24) || (key_len == 32))) + pr_err("%s: wc_AesCcmSetKey failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); + return -EINVAL; + } + + if (ctx->aes_encrypt_C->use_aesni) + pr_err("%s: after wc_AesCcmSetKey, ctx->aes_encrypt_C has AES-NI asserted.\n", WOLFKM_AESCCM_RFC4309_DRIVER); + } +#endif + + #ifdef WOLFKM_DEBUG_AES + pr_info("info: exiting km_AesCcmSetKey_Rfc4309: %d\n", key_len); + #endif /* WOLFKM_DEBUG_AES */ + return 0; +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + +static int km_AesCcmSetAuthsize(struct crypto_aead *tfm, unsigned int authsize) +{ + (void)tfm; + + /* RFC 3610 section 2 */ + switch (authsize) { + case 4: + case 6: + case 8: + case 10: + case 12: + case 14: + case 16: + return 0; + } + +#ifdef WOLFSSL_LINUXKM_VERBOSE_LKCAPI_DEBUG + pr_err("%s: invalid authsize: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), authsize); +#endif + return -EINVAL; +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM */ + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + +static int km_AesCcmSetAuthsize_Rfc4309(struct crypto_aead *tfm, unsigned int authsize) +{ + (void)tfm; + + /* RFC 4309 permits 8, 12, and 16; the kernel rfc4309 wrapper enforces + * the same set, so we match it. + */ + switch (authsize) { + case 8: + case 12: + case 16: + return 0; + } + +#ifdef WOLFSSL_LINUXKM_VERBOSE_LKCAPI_DEBUG + pr_err("%s: invalid authsize: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), authsize); +#endif + return -EINVAL; +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + +/* + * ccm(aes) -- the generic kernel CCM convention. ivsize is 16, + * and req->iv is a partially-formed B0 block where + * req->iv[0] = L - 1, req->iv[1 .. 15-L] = nonce N, + * and bytes [16-L .. 15] are scratch (the kernel's + * generic ccm() template would write the message + * length there before encrypting B0). We don't need + * that scratch region: wc_AesCcmEncrypt rebuilds B0 + * internally from (nonce, nonceSz, inSz, ...). + * So all we have to do is decode L from req->iv[0] + * and present (&req->iv[1], 15 - L) as the nonce. + * + * rfc4309(ccm(aes)) -- IPsec ESP convention per RFC 4309. The trailing + * three bytes of the key material are a per-SA salt + * that we stash at setkey time, and ivsize is 8 (the + * explicit per-packet IV). At request time we form + * an 11-byte nonce as salt(3) || req->iv(8), giving + * L = 4, matching RFC 4309 section 4. RFC 4309 + * also packs an extra 8 bytes (a copy of the + * explicit IV) into the AAD region between the real + * AAD and the ciphertext, so the real AAD length is + * req->assoclen - 8, and the ciphertext starts at + * offset req->assoclen. This mirrors what the GCM + * rfc4106 path does. + * + * aead ciphers receive data in scatterlists in the following order: + * encrypt + * req->src: aad||plaintext + * req->dst: aad||ciphertext||tag + * decrypt + * req->src: aad||ciphertext||tag + * req->dst: aad||plaintext, return 0 or -EBADMSG + * + * For rfc4309 the AAD region additionally contains an inline 8-byte copy of + * the explicit IV between the real AAD and the (cipher)text, so: + * real AAD length = req->assoclen - 8 + * (cipher)text offset = req->assoclen (skips the inline IV too) + * + * Note that wc_AesCcm has no streaming API, so we always linearize the + * scatterlists into a single bounce buffer when they aren't already + * contiguous, exactly as the !WOLFSSL_AESGCM_STREAM branch of the GCM glue + * does. + */ + +static int AesCcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4309_p) +{ + struct crypto_aead * tfm = NULL; + struct km_AesCtx * ctx = NULL; + struct skcipher_walk sk_walk; + struct scatter_walk in_walk, out_walk; + u8 *in_map = NULL, *out_map = NULL; + u8 authTag[WC_AES_BLOCK_SIZE]; + int err; + unsigned int assoclen = req->assoclen; + u8 * assoc = NULL; + u8 * sg_buf = NULL; + Aes *aes_copy = NULL; + u8 * in_text = NULL; + u8 * out_text = NULL; + const byte * nonce = NULL; + word32 nonceSz = 0; +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + byte rfc4309_iv[CCM_NONCE_MAX_SZ]; /* >= 11 */ +#endif + + tfm = crypto_aead_reqtfm(req); + ctx = crypto_aead_ctx(tfm); + + if (decrypt_p) { + /* Copy out the original auth tag from req->src. */ + scatterwalk_map_and_copy(authTag, req->src, + req->assoclen + req->cryptlen - tfm->authsize, + tfm->authsize, 0); + err = skcipher_walk_aead_decrypt(&sk_walk, req, false); + } + else { + err = skcipher_walk_aead_encrypt(&sk_walk, req, false); + } + + if (unlikely(err)) { + pr_err("%s: %s failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), + decrypt_p ? "skcipher_walk_aead_decrypt" : "skcipher_walk_aead_encrypt", + err); + return -EINVAL; + } + + err = km_AesGet(ctx, decrypt_p, 1 /* copy_p */, &aes_copy); + if (unlikely(err)) { + goto out; + } + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + if (rfc4309_p) { + if (unlikely(assoclen != 16 && assoclen != 20)) { + err = -EINVAL; + goto out; + } + assoclen -= 8; + + memcpy(rfc4309_iv, ctx->rfc4309_nonce, 3); + memcpy(rfc4309_iv + 3, sk_walk.iv, 8); + nonce = rfc4309_iv; + nonceSz = 11; + } + else +#else + (void)rfc4309_p; +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + { + /* Generic ccm(aes): req->iv is a 16-byte buffer. + * req->iv[0] = L - 1 (2 <= L <= 8) + * req->iv[1 .. 15-L] = nonce N (length 15 - L = nonceSz) + * req->iv[16-L .. 15] = scratch (we don't read it) + */ + unsigned int L_minus_1 = ((byte *)sk_walk.iv)[0]; + unsigned int L = L_minus_1 + 1U; + + if (unlikely(L < 2U || L > 8U)) { + err = -EINVAL; + goto out; + } + nonceSz = 15U - L; + nonce = &((byte *)sk_walk.iv)[1]; + } + + if ((req->src->length >= req->assoclen + req->cryptlen) && + (req->dst->length >= req->assoclen + req->cryptlen)) + { + scatterwalk_start(&in_walk, req->src); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) + scatterwalk_map(&in_walk); + in_map = in_walk.addr; +#else + in_map = scatterwalk_map(&in_walk); +#endif + if (unlikely(IS_ERR(in_map))) { + err = (int)PTR_ERR(in_map); + pr_err("%s: scatterwalk_map failed: %ld\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), + PTR_ERR(in_map)); + in_map = NULL; + goto out; + } + assoc = in_map; + in_text = in_map + req->assoclen; + + scatterwalk_start(&out_walk, req->dst); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) + scatterwalk_map(&out_walk); + out_map = out_walk.addr; +#else + out_map = scatterwalk_map(&out_walk); +#endif + if (unlikely(IS_ERR(out_map))) { + err = (int)PTR_ERR(out_map); + pr_err("%s: scatterwalk_map failed: %ld\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), + PTR_ERR(out_map)); + out_map = NULL; + goto out; + } + out_text = out_map + req->assoclen; + } + else { + sg_buf = malloc(req->assoclen + req->cryptlen); + if (unlikely(sg_buf == NULL)) { + err = -ENOMEM; + goto out; + } + if (decrypt_p) + scatterwalk_map_and_copy(sg_buf, req->src, 0, req->assoclen + req->cryptlen - tfm->authsize, 0); + else + scatterwalk_map_and_copy(sg_buf, req->src, 0, req->assoclen + req->cryptlen, 0); + assoc = sg_buf; + in_text = out_text = sg_buf + req->assoclen; + } + + if (decrypt_p) { + err = wc_AesCcmDecrypt(aes_copy, out_text, in_text, + req->cryptlen - tfm->authsize, + nonce, nonceSz, + authTag, tfm->authsize, + assoc, assoclen); + + if (unlikely(err)) { +#ifdef WOLFSSL_LINUXKM_VERBOSE_LKCAPI_DEBUG + pr_err("%s: wc_AesCcmDecrypt failed with return code %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); +#endif + + if (err == WC_NO_ERR_TRACE(AES_CCM_AUTH_E)) { + err = -EBADMSG; + goto out; + } + else { + err = -EINVAL; + goto out; + } + } + } + else { + err = wc_AesCcmEncrypt(aes_copy, out_text, in_text, req->cryptlen, + nonce, nonceSz, + authTag, tfm->authsize, + assoc, assoclen); + + if (unlikely(err)) { + pr_err("%s: wc_AesCcmEncrypt failed: %d\n", + crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)), err); + err = -EINVAL; + goto out; + } + } + + if (sg_buf) { + if (decrypt_p) + scatterwalk_map_and_copy(sg_buf, req->dst, 0, req->assoclen + req->cryptlen - tfm->authsize, 1); + else + scatterwalk_map_and_copy(sg_buf, req->dst, 0, req->assoclen + req->cryptlen, 1); + } + + if (! decrypt_p) { + /* Now copy the auth tag into the request scatterlist. */ + scatterwalk_map_and_copy(authTag, req->dst, + req->assoclen + req->cryptlen, + tfm->authsize, 1); + } + +out: + + if (sg_buf) { + free(sg_buf); + } + else { + if (in_map) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) + scatterwalk_unmap(&in_walk); +#else + scatterwalk_unmap(in_map); +#endif + } + if (out_map) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) + scatterwalk_unmap(&out_walk); +#else + scatterwalk_unmap(out_map); +#endif + } + } + + km_AesFree(&aes_copy); + + #ifdef WOLFKM_DEBUG_AES + pr_info("info: exiting AesCcmCrypt_1: err %d, dec %d, cryptlen %d, " + "assoclen %d\n", err, decrypt_p, + req->cryptlen, req->assoclen); + #endif /* WOLFKM_DEBUG_AES */ + + return err; +} + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + +static int km_AesCcmEncrypt(struct aead_request *req) { + return AesCcmCrypt_1(req, 0 /* decrypt_p */, 0 /* rfc4309_p */); +} + +static int km_AesCcmDecrypt(struct aead_request *req) { + return AesCcmCrypt_1(req, 1 /* decrypt_p */, 0 /* rfc4309_p */); +} + +static struct aead_alg ccmAesAead = { + .base.cra_name = WOLFKM_AESCCM_NAME, + .base.cra_driver_name = WOLFKM_AESCCM_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct km_AesCtx), + .base.cra_module = THIS_MODULE, + .init = km_AesCcmInit, + .exit = km_AesCcmExit, + .setkey = km_AesCcmSetKey, + .setauthsize = km_AesCcmSetAuthsize, + .encrypt = km_AesCcmEncrypt, + .decrypt = km_AesCcmDecrypt, + .ivsize = WC_AES_BLOCK_SIZE, + .maxauthsize = WC_AES_BLOCK_SIZE, + .chunksize = 1, +}; +static int ccmAesAead_loaded = 0; + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM */ + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + +static int km_AesCcmEncrypt_Rfc4309(struct aead_request *req) { + return AesCcmCrypt_1(req, 0 /* decrypt_p */, 1 /* rfc4309_p */); +} + +static int km_AesCcmDecrypt_Rfc4309(struct aead_request *req) { + return AesCcmCrypt_1(req, 1 /* decrypt_p */, 1 /* rfc4309_p */); +} + +static struct aead_alg ccmAesAead_rfc4309 = { + .base.cra_name = WOLFKM_AESCCM_RFC4309_NAME, + .base.cra_driver_name = WOLFKM_AESCCM_RFC4309_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct km_AesCtx), + .base.cra_module = THIS_MODULE, + .init = km_AesCcmInit, + .exit = km_AesCcmExit, + .setkey = km_AesCcmSetKey_Rfc4309, + .setauthsize = km_AesCcmSetAuthsize_Rfc4309, + .encrypt = km_AesCcmEncrypt_Rfc4309, + .decrypt = km_AesCcmDecrypt_Rfc4309, + .ivsize = 8, + .maxauthsize = WC_AES_BLOCK_SIZE, + .chunksize = 1, +}; +static int ccmAesAead_rfc4309_loaded = 0; + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM || LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + + + + #ifdef LINUXKM_LKCAPI_REGISTER_AESXTS #ifndef WOLFSSL_AESXTS_STREAM @@ -2692,9 +3223,9 @@ static int linuxkm_test_aescfb(void) if (aes == NULL) return MEMORY_E; - ret = aesofb_test(); + ret = aes_cfb_test(); if (ret) { - wc_test_render_error_message("aesgcm_test failed: ", ret); + wc_test_render_error_message("aes_cfb_test failed: ", ret); ret = WC_TEST_RET_DEC_EC(ret); goto test_cfb_end; } @@ -3165,6 +3696,36 @@ static int linuxkm_test_aesgcm_rfc4106(void) #endif /* LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 */ +#if defined(LINUXKM_LKCAPI_REGISTER_AESCCM) || defined(LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309) + +static int aesccm_test_once(void) { + static int once = 0; + static int ret; + if (! once) { + ret = aesccm_test(); + once = 1; + } + return ret; +} + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + +static int linuxkm_test_aesccm(void) { + return aesccm_test_once(); +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM */ + +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + +static int linuxkm_test_aesccm_rfc4309(void) { + return aesccm_test_once(); +} + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + +#endif /* LINUXKM_LKCAPI_REGISTER_AESCCM || LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 */ + #ifdef LINUXKM_LKCAPI_REGISTER_AESXTS /* test vectors from diff --git a/linuxkm/lkcapi_glue.c b/linuxkm/lkcapi_glue.c index a4c2559952..f88da9e2bb 100644 --- a/linuxkm/lkcapi_glue.c +++ b/linuxkm/lkcapi_glue.c @@ -431,7 +431,7 @@ static int linuxkm_lkcapi_register(void) (alg).base.cra_driver_name, ret); \ } \ (crypto_unregister_ ## alg_class)(&(alg)); \ - if (! (alg.base.cra_flags & CRYPTO_ALG_DEAD)) { \ + if (! ((alg).base.cra_flags & CRYPTO_ALG_DEAD)) { \ pr_err("ERROR: alg %s not _DEAD " \ "after crypto_unregister_%s -- " \ "marking as loaded despite test failure.", \ @@ -460,6 +460,12 @@ static int linuxkm_lkcapi_register(void) #ifdef LINUXKM_LKCAPI_REGISTER_AESGCM REGISTER_ALG(gcmAesAead, aead, linuxkm_test_aesgcm); #endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + REGISTER_ALG(ccmAesAead_rfc4309, aead, linuxkm_test_aesccm_rfc4309); +#endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + REGISTER_ALG(ccmAesAead, aead, linuxkm_test_aesccm); +#endif #ifdef LINUXKM_LKCAPI_REGISTER_AESXTS REGISTER_ALG(xtsAesAlg, skcipher, linuxkm_test_aesxts); #endif @@ -831,6 +837,12 @@ static int linuxkm_lkcapi_unregister(void) #ifdef LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 UNREGISTER_ALG(gcmAesAead_rfc4106, aead); #endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM + UNREGISTER_ALG(ccmAesAead, aead); +#endif +#ifdef LINUXKM_LKCAPI_REGISTER_AESCCM_RFC4309 + UNREGISTER_ALG(ccmAesAead_rfc4309, aead); +#endif #ifdef LINUXKM_LKCAPI_REGISTER_AESXTS UNREGISTER_ALG(xtsAesAlg, skcipher); #endif diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 68472f91c2..50b169fd08 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -1728,9 +1728,11 @@ static int updateFipsHash(void) FIPS_IN_CORE_DIGEST_SIZE, coreKey, desc, + /* NOLINTBEGIN(clang-diagnostic-cast-function-type-strict) */ (wc_fips_verifyCore_hmac_setkey_fn)linux_fips_hmac_setkey, (wc_fips_verifyCore_hmac_update_fn)linux_fips_hmac_update, (wc_fips_verifyCore_hmac_final_fn)linux_fips_hmac_final, + /* NOLINTEND(clang-diagnostic-cast-function-type-strict) */ verifyCore, &verifyCore_size, #if defined(DEBUG_LINUXKM_PIE_SUPPORT) && defined(WC_SYM_RELOC_TABLES)