/* lkcapi_rsa_glue.c -- glue logic to register RSA wolfCrypt implementations * with the Linux Kernel Cryptosystem * * Copyright (C) 2006-2025 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #ifndef LINUXKM_LKCAPI_REGISTER #error lkcapi_rsa_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. #endif #if !defined(NO_RSA) && \ (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ defined(LINUXKM_LKCAPI_REGISTER_RSA)) #if defined(WOLFSSL_RSA_VERIFY_ONLY) || \ defined(WOLFSSL_RSA_PUBLIC_ONLY) #error LINUXKM_LKCAPI_REGISTER_RSA and RSA_VERIFY_ONLY not supported #endif /* WOLFSSL_RSA_VERIFY_ONLY || WOLFSSL_RSA_PUBLIC_ONLY */ #ifdef WC_RSA_NO_PADDING #define LINUXKM_DIRECT_RSA #endif /* WC_RSA_NO_PADDING */ #include #include #define WOLFKM_RSA_NAME ("rsa") #define WOLFKM_RSA_DRIVER ("rsa" WOLFKM_DRIVER_FIPS "-wolfcrypt") #define WOLFKM_PKCS1_SHA256_NAME ("pkcs1pad(rsa,sha256)") #define WOLFKM_PKCS1_SHA256_DRIVER ("pkcs1pad(rsa" WOLFKM_DRIVER_FIPS \ "-wolfcrypt,sha256)") #define WOLFKM_PKCS1_SHA512_NAME ("pkcs1pad(rsa,sha512)") #define WOLFKM_PKCS1_SHA512_DRIVER ("pkcs1pad(rsa" WOLFKM_DRIVER_FIPS \ "-wolfcrypt,sha512)") #if defined(WOLFSSL_KEY_GEN) #if defined(LINUXKM_DIRECT_RSA) static int linuxkm_test_rsa_driver(const char * driver, int nbits); #endif /* LINUXKM_DIRECT_RSA */ static int linuxkm_test_pkcs1_driver(const char * driver, int nbits, int hash_oid, word32 hash_len); #endif /* WOLFSSL_KEY_GEN */ #if defined(LINUXKM_DIRECT_RSA) static int direct_rsa_loaded = 0; #endif /* LINUXKM_DIRECT_RSA */ #ifndef NO_SHA256 static int pkcs1_sha256_loaded = 0; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 static int pkcs1_sha512_loaded = 0; #endif /* WOLFSSL_SHA512 */ struct km_rsa_ctx { WC_RNG rng; /* needed for pkcs1 padding, and blinding */ RsaKey * key; int hash_oid; /* hash_oid for wc_EncodeSignature */ unsigned int digest_len; word32 key_len; }; /* shared rsa callbacks */ static int km_rsa_init(struct crypto_akcipher *tfm, int hash_oid); static void km_rsa_exit(struct crypto_akcipher *tfm); static int km_rsa_set_priv(struct crypto_akcipher *tfm, const void *key, unsigned int keylen); static int km_rsa_set_pub(struct crypto_akcipher *tfm, const void *key, unsigned int keylen); static unsigned int km_rsa_max_size(struct crypto_akcipher *tfm); #if defined(LINUXKM_DIRECT_RSA) /* direct rsa callbacks */ static int km_direct_rsa_init(struct crypto_akcipher *tfm); static int km_direct_rsa_enc(struct akcipher_request *req); static int km_direct_rsa_dec(struct akcipher_request *req); #endif /* LINUXKM_DIRECT_RSA */ /* pkcs1 callbacks */ #ifndef NO_SHA256 static int km_pkcs1_sha256_init(struct crypto_akcipher *tfm); #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 static int km_pkcs1_sha512_init(struct crypto_akcipher *tfm); #endif /* WOLFSSL_SHA512 */ #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) static int km_pkcs1_sign(struct akcipher_request *req); static int km_pkcs1_verify(struct akcipher_request *req); #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ static int km_pkcs1_enc(struct akcipher_request *req); static int km_pkcs1_dec(struct akcipher_request *req); /* misc */ #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) static int get_hash_enc_len(int hash_oid); #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ #if defined(LINUXKM_DIRECT_RSA) static struct akcipher_alg direct_rsa = { .base.cra_name = WOLFKM_RSA_NAME, .base.cra_driver_name = WOLFKM_RSA_DRIVER, .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, .base.cra_module = THIS_MODULE, .base.cra_ctxsize = sizeof(struct km_rsa_ctx), .encrypt = km_direct_rsa_enc, .decrypt = km_direct_rsa_dec, .set_priv_key = km_rsa_set_priv, .set_pub_key = km_rsa_set_pub, .max_size = km_rsa_max_size, .init = km_direct_rsa_init, .exit = km_rsa_exit, }; #endif /* LINUXKM_DIRECT_RSA */ #ifndef NO_SHA256 static struct akcipher_alg pkcs1_sha256 = { .base.cra_name = WOLFKM_PKCS1_SHA256_NAME, .base.cra_driver_name = WOLFKM_PKCS1_SHA256_DRIVER, .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, .base.cra_module = THIS_MODULE, .base.cra_ctxsize = sizeof(struct km_rsa_ctx), #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) .sign = km_pkcs1_sign, .verify = km_pkcs1_verify, #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ .encrypt = km_pkcs1_enc, .decrypt = km_pkcs1_dec, .set_priv_key = km_rsa_set_priv, .set_pub_key = km_rsa_set_pub, .max_size = km_rsa_max_size, .init = km_pkcs1_sha256_init, .exit = km_rsa_exit, }; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 static struct akcipher_alg pkcs1_sha512 = { .base.cra_name = WOLFKM_PKCS1_SHA512_NAME, .base.cra_driver_name = WOLFKM_PKCS1_SHA512_DRIVER, .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, .base.cra_module = THIS_MODULE, .base.cra_ctxsize = sizeof(struct km_rsa_ctx), #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) .sign = km_pkcs1_sign, .verify = km_pkcs1_verify, #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ .encrypt = km_pkcs1_enc, .decrypt = km_pkcs1_dec, .set_priv_key = km_rsa_set_priv, .set_pub_key = km_rsa_set_pub, .max_size = km_rsa_max_size, .init = km_pkcs1_sha512_init, .exit = km_rsa_exit, }; #endif /* WOLFSSL_SHA512 */ static int km_rsa_init(struct crypto_akcipher *tfm, int hash_oid) { struct km_rsa_ctx * ctx = NULL; int ret = 0; ctx = akcipher_tfm_ctx(tfm); memset(ctx, 0, sizeof(struct km_rsa_ctx)); ctx->key = (RsaKey *)malloc(sizeof(RsaKey)); if (!ctx->key) { ret = -ENOMEM; goto out; } ret = wc_InitRng(&ctx->rng); if (ret) { pr_err("%s: init rng returned: %d\n", WOLFKM_RSA_DRIVER, ret); if (ret == WC_NO_ERR_TRACE(MEMORY_E)) ret = -ENOMEM; else ret = -EINVAL; goto out; } ret = wc_InitRsaKey(ctx->key, NULL); if (ret) { pr_err("%s: init rsa key returned: %d\n", WOLFKM_RSA_DRIVER, ret); ret = -EINVAL; goto out; } #ifdef WC_RSA_BLINDING ret = wc_RsaSetRNG(ctx->key, &ctx->rng); if (ret) { ret = -EINVAL; goto out; } #endif /* WC_RSA_BLINDING */ ctx->hash_oid = hash_oid; switch (ctx->hash_oid) { case 0: ctx->digest_len = 0; break; #ifndef NO_SHA256 case SHA256h: ctx->digest_len = WC_SHA256_DIGEST_SIZE; break; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 case SHA512h: ctx->digest_len = WC_SHA512_DIGEST_SIZE; break; #endif /* WOLFSSL_SHA512 */ default: pr_err("%s: init: unhandled hash_oid: %d\n", WOLFKM_RSA_DRIVER, hash_oid); ret = -EINVAL; goto out; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_rsa_init: hash_oid %d\n", ctx->hash_oid); #endif /* WOLFKM_DEBUG_RSA */ out: if (ret != 0) { if (ctx->key) { free(ctx->key); ctx->key = NULL; } wc_FreeRng(&ctx->rng); } return ret; } #if defined(LINUXKM_DIRECT_RSA) /* * RSA encrypt with public key. * * Requires that crypto_akcipher_set_pub_key has been called first. * * note: this matches behavior of kernel rsa-generic akcipher, which does * direct RSA without padding, and without requiring src_len matches RSA * key size. * * returns 0 on success * returns < 0 on error */ static int km_direct_rsa_enc(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; word32 out_len = 0; byte * dec = NULL; byte * enc = NULL; if (req->src == NULL || req->dst == NULL) { err = -EINVAL; goto rsa_enc_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); if (unlikely(ctx->key_len <= 0)) { err = -EINVAL; goto rsa_enc_out; } out_len = ctx->key_len; if (req->src_len > (unsigned int) ctx->key_len) { err = -EOVERFLOW; goto rsa_enc_out; } if (req->dst_len < (unsigned int) ctx->key_len) { req->dst_len = ctx->key_len; err = -EOVERFLOW; goto rsa_enc_out; } dec = malloc(req->src_len); if (unlikely(dec == NULL)) { err = -ENOMEM; goto rsa_enc_out; } enc = malloc(req->dst_len); if (unlikely(enc == NULL)) { err = -ENOMEM; goto rsa_enc_out; } /* copy req->src to dec */ memset(dec, 0, req->src_len); memset(enc, 0, req->dst_len); scatterwalk_map_and_copy(dec, req->src, 0, req->src_len, 0); /* note: matching behavior of kernel rsa-generic. */ err = wc_RsaFunction(dec, req->src_len, enc, &out_len, RSA_PUBLIC_ENCRYPT, ctx->key, &ctx->rng); if (unlikely(err || (out_len != ctx->key_len))) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: direct rsa pub enc returned: %d, %d, %d\n", WOLFKM_RSA_DRIVER, err, out_len, ctx->key_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto rsa_enc_out; } /* enc to req->dst */ scatterwalk_map_and_copy(enc, req->dst, 0, ctx->key_len, 1); err = 0; rsa_enc_out: if (enc != NULL) { free(enc); enc = NULL; } if (dec != NULL) { free(dec); dec = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_direct_rsa_enc\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } /* * RSA decrypt with private key. * * Requires that crypto_akcipher_set_priv_key has been called first. * * returns 0 on success * returns < 0 on error */ static int km_direct_rsa_dec(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; word32 out_len = 0; byte * enc = NULL; byte * dec = NULL; if (req->src == NULL || req->dst == NULL) { err = -EINVAL; goto rsa_dec_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); if (unlikely(ctx->key_len <= 0)) { err = -EINVAL; goto rsa_dec_out; } out_len = ctx->key_len; if (req->src_len != (unsigned int) ctx->key_len) { err = -EINVAL; goto rsa_dec_out; } if (req->dst_len <= 0 || req->dst_len > (unsigned int) ctx->key_len) { err = -EINVAL; goto rsa_dec_out; } enc = malloc(req->src_len); if (unlikely(enc == NULL)) { err = -ENOMEM; goto rsa_dec_out; } dec = malloc(req->dst_len); if (unlikely(dec == NULL)) { err = -ENOMEM; goto rsa_dec_out; } /* copy req->src to enc */ memset(enc, 0, req->src_len); memset(dec, 0, req->dst_len); scatterwalk_map_and_copy(enc, req->src, 0, req->src_len, 0); err = wc_RsaDirect(enc, ctx->key_len, dec, &out_len, ctx->key, RSA_PRIVATE_DECRYPT, &ctx->rng); if (unlikely(err != (int) ctx->key_len || ctx->key_len != out_len)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: rsa pub enc returned: %d, %d, %d\n", WOLFKM_RSA_DRIVER, err, out_len, ctx->key_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto rsa_dec_out; } if (out_len > req->dst_len) { err = -EOVERFLOW; goto rsa_dec_out; } /* copy dec to req->dst */ scatterwalk_map_and_copy(dec, req->dst, 0, ctx->key_len, 1); err = 0; rsa_dec_out: if (enc != NULL) { free(enc); enc = NULL; } if (dec != NULL) { free(dec); dec = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_direct_rsa_dec\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } #endif /* LINUXKM_DIRECT_RSA */ /* * Decodes and sets the RSA private key. * * param tfm the crypto_akcipher transform * param key BER encoded private key and parameters * param keylen key length */ static int km_rsa_set_priv(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { int err = 0; struct km_rsa_ctx * ctx = NULL; word32 idx = 0; int key_len = 0; ctx = akcipher_tfm_ctx(tfm); if (ctx->key_len) { /* Free old key. */ ctx->key_len = 0; wc_FreeRsaKey(ctx->key); err = wc_InitRsaKey(ctx->key, NULL); if (unlikely(err)) { return -ENOMEM; } #ifdef WC_RSA_BLINDING err = wc_RsaSetRNG(ctx->key, &ctx->rng); if (unlikely(err)) { return -ENOMEM; } #endif /* WC_RSA_BLINDING */ } err = wc_RsaPrivateKeyDecode(key, &idx, ctx->key, keylen); if (unlikely(err)) { if (!disable_setkey_warnings) { pr_err("%s: wc_RsaPrivateKeyDecode failed: %d\n", WOLFKM_RSA_DRIVER, err); } return -EINVAL; } key_len = wc_RsaEncryptSize(ctx->key); if (unlikely(key_len <= 0)) { pr_err("error: %s: rsa encrypt size returned: %d\n", WOLFKM_RSA_DRIVER, key_len); return -EINVAL; } ctx->key_len = (word32) key_len; #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_rsa_set_priv\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } /* * Decodes and sets the RSA pub key. * * param tfm the crypto_akcipher transform * param key BER encoded pub key and parameters * param keylen key length */ static int km_rsa_set_pub(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { int err = 0; struct km_rsa_ctx * ctx = NULL; word32 idx = 0; int key_len = 0; ctx = akcipher_tfm_ctx(tfm); if (ctx->key_len) { /* Free old key. */ ctx->key_len = 0; wc_FreeRsaKey(ctx->key); err = wc_InitRsaKey(ctx->key, NULL); if (unlikely(err)) { return -ENOMEM; } } err = wc_RsaPublicKeyDecode(key, &idx, ctx->key, keylen); if (unlikely(err)) { #ifdef WOLFKM_DEBUG_RSA pr_err("%s: wc_RsaPublicKeyDecode failed: %d\n", WOLFKM_RSA_DRIVER, err); #endif /* WOLFKM_DEBUG_RSA */ return -EINVAL; } key_len = wc_RsaEncryptSize(ctx->key); if (unlikely(key_len <= 0)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: rsa encrypt size returned: %d\n", WOLFKM_RSA_DRIVER, key_len); #endif /* WOLFKM_DEBUG_RSA */ return -EINVAL; } ctx->key_len = (word32) key_len; #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_rsa_set_pub\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } /* * Returns dest buffer size required for key. */ static unsigned int km_rsa_max_size(struct crypto_akcipher *tfm) { struct km_rsa_ctx * ctx = NULL; ctx = akcipher_tfm_ctx(tfm); return (unsigned int) ctx->key_len; } #if defined(LINUXKM_DIRECT_RSA) static int km_direct_rsa_init(struct crypto_akcipher *tfm) { return km_rsa_init(tfm, 0); } #endif /* LINUXKM_DIRECT_RSA */ static void km_rsa_exit(struct crypto_akcipher *tfm) { struct km_rsa_ctx * ctx = NULL; ctx = akcipher_tfm_ctx(tfm); if (ctx->key) { wc_FreeRsaKey(ctx->key); free(ctx->key); ctx->key = NULL; } wc_FreeRng(&ctx->rng); #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_rsa_exit\n"); #endif /* WOLFKM_DEBUG_RSA */ return; } #ifndef NO_SHA256 static int km_pkcs1_sha256_init(struct crypto_akcipher *tfm) { return km_rsa_init(tfm, SHA256h); } #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 static int km_pkcs1_sha512_init(struct crypto_akcipher *tfm) { return km_rsa_init(tfm, SHA512h); } #endif /* WOLFSSL_SHA512 */ #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) static int km_pkcs1_sign(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; word32 sig_len = 0; word32 enc_len = 0; int hash_enc_len = 0; byte * msg = NULL; byte * sig = NULL; if (req->src == NULL || req->dst == NULL) { err = -EINVAL; goto pkcs1_sign_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); if (ctx->key_len <= 0 || ctx->digest_len <= 0) { /* invalid key state */ err = -EINVAL; goto pkcs1_sign_out; } hash_enc_len = get_hash_enc_len(ctx->hash_oid); if (hash_enc_len <= 0) { err = -EINVAL; goto pkcs1_sign_out; } if (req->src_len + hash_enc_len + RSA_MIN_PAD_SZ > ctx->key_len) { err = -EOVERFLOW; goto pkcs1_sign_out; } if (req->dst_len < ctx->key_len) { err = -EOVERFLOW; goto pkcs1_sign_out; } /* allocate extra space for encoding. */ msg = malloc(ctx->key_len); if (unlikely(msg == NULL)) { err = -ENOMEM; goto pkcs1_sign_out; } sig = malloc(ctx->key_len); if (unlikely(sig == NULL)) { err = -ENOMEM; goto pkcs1_sign_out; } /* copy req->src to msg */ memset(msg, 0, ctx->key_len); memset(sig, 0, ctx->key_len); scatterwalk_map_and_copy(msg, req->src, 0, req->src_len, 0); /* encode message with hash oid. */ enc_len = wc_EncodeSignature(msg, msg, req->src_len, ctx->hash_oid); if (unlikely(enc_len <= 0)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: wc_EncodeSignature returned: %d\n", WOLFKM_RSA_DRIVER, enc_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto pkcs1_sign_out; } /* sign encoded message. */ sig_len = wc_RsaSSL_Sign(msg, enc_len, sig, ctx->key_len, ctx->key, &ctx->rng); if (unlikely(sig_len != ctx->key_len)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: wc_RsaSSL_Sign returned: %d\n", WOLFKM_RSA_DRIVER, sig_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto pkcs1_sign_out; } /* copy sig to req->dst */ scatterwalk_map_and_copy(sig, req->dst, 0, ctx->key_len, 1); err = 0; pkcs1_sign_out: if (msg != NULL) { free(msg); msg = NULL; } if (sig != NULL) { free(sig); sig = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_sign\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } /* * Verify a pkcs1 encoded signature. * * The total size of req->src is src_len + dst_len: * - src_len: signature * - dst_len: digest * * dst should be null. * See kernel: * - include/crypto/akcipher.h */ static int km_pkcs1_verify(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; word32 sig_len = 0; word32 dec_len = 0; word32 msg_len = 0; word32 enc_msg_len = 0; int hash_enc_len = 0; int n_diff = 0; byte * sig = NULL; byte * msg = NULL; if (req->src == NULL || req->dst != NULL) { err = -EINVAL; goto pkcs1_verify_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); msg_len = req->dst_len; sig_len = req->src_len; if (ctx->key_len <= 0 || ctx->digest_len <= 0) { /* invalid key state */ err = -EINVAL; goto pkcs1_verify_out; } hash_enc_len = get_hash_enc_len(ctx->hash_oid); if (hash_enc_len <= 0) { err = -EINVAL; goto pkcs1_verify_out; } if (msg_len != ctx->digest_len || sig_len != ctx->key_len) { /* invalid src or dst args */ err = -EINVAL; goto pkcs1_verify_out; } sig = malloc(ctx->key_len); if (unlikely(sig == NULL)) { err = -ENOMEM; goto pkcs1_verify_out; } /* allocate extra space for encoding. */ msg = malloc(ctx->key_len); if (unlikely(msg == NULL)) { err = -ENOMEM; goto pkcs1_verify_out; } /* copy sig from req->src to sig */ memset(sig, 0, ctx->key_len); memset(msg, 0, ctx->key_len); scatterwalk_map_and_copy(sig, req->src, 0, sig_len, 0); /* verify encoded message. */ dec_len = wc_RsaSSL_Verify(sig, sig_len, msg, sig_len, ctx->key); if (unlikely(dec_len <= 0)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: wc_RsaSSL_Verify returned: %d\n", WOLFKM_RSA_DRIVER, dec_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EBADMSG; goto pkcs1_verify_out; } /* reuse sig array for digest comparison */ memset(sig, 0, ctx->key_len); scatterwalk_map_and_copy(sig, req->src, sig_len, msg_len, 0); /* encode digest with hash oid. */ enc_msg_len = wc_EncodeSignature(sig, sig, msg_len, ctx->hash_oid); if (unlikely(enc_msg_len <= 0 || enc_msg_len != dec_len)) { err = -EINVAL; goto pkcs1_verify_out; } n_diff = memcmp(sig, msg, dec_len); if (unlikely(n_diff != 0)) { err = -EKEYREJECTED; goto pkcs1_verify_out; } err = 0; pkcs1_verify_out: if (msg != NULL) { free(msg); msg = NULL; } if (sig != NULL) { free(sig); sig = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_verify\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ static int km_pkcs1_enc(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; byte * dec = NULL; byte * enc = NULL; if (req->src == NULL || req->dst == NULL) { err = -EINVAL; goto pkcs1_enc_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); if (ctx->key_len <= 0 || ctx->digest_len <= 0) { /* invalid key state */ err = -EINVAL; goto pkcs1_enc_out; } if (req->src_len + RSA_MIN_PAD_SZ > ctx->key_len) { err = -EOVERFLOW; goto pkcs1_enc_out; } if (req->dst_len < ctx->key_len) { err = -EOVERFLOW; goto pkcs1_enc_out; } dec = malloc(req->src_len); if (unlikely(dec == NULL)) { err = -ENOMEM; goto pkcs1_enc_out; } enc = malloc(req->dst_len); if (unlikely(enc == NULL)) { err = -ENOMEM; goto pkcs1_enc_out; } /* copy req->src to dec */ memset(dec, 0, req->src_len); memset(enc, 0, req->dst_len); scatterwalk_map_and_copy(dec, req->src, 0, req->src_len, 0); err = wc_RsaPublicEncrypt(dec, req->src_len, enc, ctx->key_len, ctx->key, &ctx->rng); if (unlikely(err != (int) ctx->key_len)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: rsa pub enc returned: %d, %d\n", WOLFKM_RSA_DRIVER, err, ctx->key_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto pkcs1_enc_out; } /* copy enc to req->dst */ scatterwalk_map_and_copy(enc, req->dst, 0, ctx->key_len, 1); err = 0; pkcs1_enc_out: if (enc != NULL) { free(enc); enc = NULL; } if (dec != NULL) { free(dec); dec = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_enc\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } static int km_pkcs1_dec(struct akcipher_request *req) { struct crypto_akcipher * tfm = NULL; struct km_rsa_ctx * ctx = NULL; int err = 0; word32 dec_len = 0; byte * enc = NULL; byte * dec = NULL; if (req->src == NULL || req->dst == NULL) { err = -EINVAL; goto pkcs1_dec_out; } tfm = crypto_akcipher_reqtfm(req); ctx = akcipher_tfm_ctx(tfm); if (ctx->key_len <= 0) { err = -EINVAL; goto pkcs1_dec_out; } if (req->src_len != ctx->key_len) { err = -EINVAL; goto pkcs1_dec_out; } if (req->dst_len <= 0 || req->dst_len > (unsigned int) ctx->key_len) { err = -EINVAL; goto pkcs1_dec_out; } enc = malloc(req->src_len); if (unlikely(enc == NULL)) { err = -ENOMEM; goto pkcs1_dec_out; } dec = malloc(req->dst_len); if (unlikely(dec == NULL)) { err = -ENOMEM; goto pkcs1_dec_out; } /* copy req->src to enc */ memset(enc, 0, req->src_len); memset(dec, 0, req->dst_len); scatterwalk_map_and_copy(enc, req->src, 0, req->src_len, 0); dec_len = wc_RsaPrivateDecrypt(enc, ctx->key_len, dec, req->dst_len, ctx->key); if (unlikely(dec_len <= 0 || dec_len > ctx->key_len)) { #ifdef WOLFKM_DEBUG_RSA pr_err("error: %s: rsa private decrypt returned: %d, %d\n", WOLFKM_RSA_DRIVER, dec_len, ctx->key_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; goto pkcs1_dec_out; } if (dec_len > req->dst_len) { err = -EOVERFLOW; goto pkcs1_dec_out; } /* copy dec to req->dst */ scatterwalk_map_and_copy(dec, req->dst, 0, dec_len, 1); err = 0; pkcs1_dec_out: if (enc != NULL) { free(enc); enc = NULL; } if (dec != NULL) { free(dec); dec = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_dec\n"); #endif /* WOLFKM_DEBUG_RSA */ return err; } #if defined(LINUXKM_DIRECT_RSA) && defined(WC_RSA_NO_PADDING) /* * Tests implemented below. */ static int linuxkm_test_rsa(void) { int rc = 0; rc = rsa_no_pad_test(); if (rc != 0) { pr_err("rsa_no_pad_test() failed with retval %d.\n", rc); return rc; } #ifdef WOLFSSL_KEY_GEN /* test wolfcrypt RSA API vs wolfkm RSA driver. */ rc = linuxkm_test_rsa_driver(WOLFKM_RSA_DRIVER, 2048); if (rc) { return rc; } #ifdef WOLFKM_DEBUG_RSA rc = linuxkm_test_rsa_driver(WOLFKM_RSA_DRIVER, 3072); if (rc) { return rc; } rc = linuxkm_test_rsa_driver(WOLFKM_RSA_DRIVER, 4096); if (rc) { return rc; } /* repeat test against stock linux RSA akcipher. */ rc = linuxkm_test_rsa_driver("rsa-generic", 2048); if (rc) { return rc; } rc = linuxkm_test_rsa_driver("rsa-generic", 3072); if (rc) { return rc; } rc = linuxkm_test_rsa_driver("rsa-generic", 4096); if (rc) { return rc; } #endif /* WOLFKM_DEBUG_RSA */ #endif /* WOLFSSL_KEY_GEN */ return rc; } #endif /* LINUXKM_DIRECT_RSA */ #ifndef NO_SHA256 static int linuxkm_test_pkcs1_sha256(void) { int rc = 0; #ifdef WOLFSSL_KEY_GEN rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA256_DRIVER, 2048, SHA256h, 32); if (rc) { return rc; } #ifdef WOLFKM_DEBUG_RSA rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA256_DRIVER, 3072, SHA256h, 32); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA256_DRIVER, 4096, SHA256h, 32); if (rc) { return rc; } /* repeat test against stock linux pkcs1pad. */ rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha256)", 2048, SHA256h, 32); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha256)", 3072, SHA256h, 32); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha256)", 4096, SHA256h, 32); if (rc) { return rc; } #endif /* WOLFKM_DEBUG_RSA */ #endif /* WOLFSSL_KEY_GEN */ return rc; } #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA512 static int linuxkm_test_pkcs1_sha512(void) { int rc = 0; #ifdef WOLFSSL_KEY_GEN rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA512_DRIVER, 2048, SHA512h, 64); if (rc) { return rc; } #ifdef WOLFKM_DEBUG_RSA rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA512_DRIVER, 3072, SHA512h, 64); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver(WOLFKM_PKCS1_SHA512_DRIVER, 4096, SHA512h, 64); if (rc) { return rc; } /* repeat test against stock linux pkcs1pad. */ rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha512)", 2048, SHA512h, 64); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha512)", 3072, SHA512h, 64); if (rc) { return rc; } rc = linuxkm_test_pkcs1_driver("pkcs1pad(rsa-generic,sha512)", 4096, SHA512h, 64); if (rc) { return rc; } #endif /* WOLFKM_DEBUG_RSA */ #endif /* WOLFSSL_KEY_GEN */ return rc; } #endif /* WOLFSSL_SHA512 */ #if defined(LINUXKM_DIRECT_RSA) && defined(WOLFSSL_KEY_GEN) /* * Test linux kernel crypto driver: * 1. generate RSA key with wolfcrypt. * 2. sanity check wolfcrypt encrypt + decrypt. * 3. crypto_alloc_akcipher(driver) * 4. export wolfcrypt RSA der pub/priv, load to akcipher tfm with * crypto_akcipher_set_pub_key, crypto_akcipher_set_priv_key. * 5. test: kernel public encrypt + wolfcrypt private decrypt * 6. test: wolfcrypt public encrypt + kernel private decrypt */ static int linuxkm_test_rsa_driver(const char * driver, int nbits) { int test_rc = -1; int ret = 0; struct crypto_akcipher * tfm = NULL; struct akcipher_request * req = NULL; RsaKey * key = NULL; WC_RNG rng; byte * priv = NULL; /* priv der */ word32 priv_len = 0; byte * pub = NULL; /* pub der */ word32 pub_len = 0; byte init_rng = 0; byte init_key = 0; static const byte p_vector[] = /* Now is the time for all good men w/o trailing 0 */ { 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20, 0x67,0x6f,0x6f,0x64,0x20,0x6d,0x65,0x6e }; byte * enc = NULL; byte * dec = NULL; /* wc decrypt */ byte * plaintext = NULL; /* km decrypt */ word32 key_len = 0; word32 out_len = 0; int enc_ret = 0; int dec_ret = 0; int n_diff = 0; struct scatterlist src, dst; size_t i = 0; key = (RsaKey*)malloc(sizeof(RsaKey)); if (key == NULL) { pr_err("error: allocating key(%zu) failed\n", sizeof(RsaKey)); goto test_rsa_end; } memset(&rng, 0, sizeof(rng)); memset(key, 0, sizeof(RsaKey)); ret = wc_InitRng(&rng); if (ret) { pr_err("error: init rng returned: %d\n", ret); goto test_rsa_end; } init_rng = 1; ret = wc_InitRsaKey(key, NULL); if (ret) { pr_err("error: init rsa key returned: %d\n", ret); goto test_rsa_end; } init_key = 1; #ifdef WC_RSA_BLINDING ret = wc_RsaSetRNG(key, &rng); if (ret) { pr_err("error: rsa set rng returned: %d\n", ret); goto test_rsa_end; } #endif /* WC_RSA_BLINDING */ ret = wc_MakeRsaKey(key, nbits, WC_RSA_EXPONENT, &rng); if (ret) { pr_err("error: make rsa key returned: %d\n", ret); goto test_rsa_end; } key_len = wc_RsaEncryptSize(key); if (key_len <= 0) { pr_err("error: rsa encrypt size returned: %d\n", key_len); goto test_rsa_end; } /** * Allocate buffers based on the RsaKey key_len. * * Add +1 for dec and plaintext arrays to printf nicely. * */ enc = (byte*)malloc(key_len); if (enc == NULL) { pr_err("error: allocating enc(%d) failed\n", key_len); goto test_rsa_end; } dec = (byte*)malloc(key_len + 1); if (dec == NULL) { pr_err("error: allocating dec(%d) failed\n", key_len); goto test_rsa_end; } plaintext = (byte*)malloc(key_len + 1); if (plaintext == NULL) { pr_err("error: allocating plaintext(%d) failed\n", key_len); goto test_rsa_end; } memset(enc, 0, key_len); memset(dec, 0, key_len + 1); memset(plaintext, 0, key_len + 1); /* Fill up dec and plaintext with plaintext reference. */ for (i = 0; i < key_len / sizeof(p_vector); ++i) { memcpy(dec + i * sizeof(p_vector), p_vector, sizeof(p_vector)); memcpy(plaintext + i * sizeof(p_vector), p_vector, sizeof(p_vector)); } /** * Sanity test: first encrypt and decrypt with direct wolfcrypt API. * */ out_len = key_len; enc_ret = wc_RsaDirect(dec, key_len, enc, &out_len, key, RSA_PUBLIC_ENCRYPT, &rng); if (enc_ret != (int) key_len || key_len != out_len) { pr_err("error: rsa pub enc returned: %d, %d\n", enc_ret, out_len); ret = -1; goto test_rsa_end; } memset(dec, 0, key_len); dec_ret = wc_RsaDirect(enc, key_len, dec, &out_len, key, RSA_PRIVATE_DECRYPT, &rng); if (dec_ret != (int) key_len || key_len != out_len) { pr_err("error: rsa priv dec returned: %d, %d\n", dec_ret, out_len); goto test_rsa_end; } /* dec and plaintext should match now. */ n_diff = memcmp(dec, plaintext, key_len); if (n_diff) { pr_err("error: decrypt doesn't match plain: %d\n", n_diff); goto test_rsa_end; } /** * Now export Rsa Der to pub and priv. * */ priv_len = wc_RsaKeyToDer(key, NULL, 0); if (priv_len <= 0) { pr_err("error: rsa priv to der returned: %d\n", priv_len); goto test_rsa_end; } priv = (byte*)malloc(priv_len); if (priv == NULL) { pr_err("error: allocating priv(%d) failed\n", priv_len); goto test_rsa_end; } memset(priv, 0, priv_len); priv_len = wc_RsaKeyToDer(key, priv, priv_len); if (priv_len <= 0) { pr_err("error: rsa priv to der returned: %d\n", priv_len); goto test_rsa_end; } /* get rsa pub der */ pub_len = wc_RsaKeyToPublicDer(key, NULL, 0); if (pub_len <= 0) { pr_err("error: rsa pub to der returned: %d\n", pub_len); goto test_rsa_end; } pub = (byte*)malloc(pub_len); if (pub == NULL) { pr_err("error: allocating pub(%d) failed\n", pub_len); goto test_rsa_end; } memset(pub, 0, pub_len); pub_len = wc_RsaKeyToPublicDer(key, pub, pub_len); if (pub_len <= 0) { pr_err("error: rsa pub to der returned: %d\n", pub_len); goto test_rsa_end; } /** * Now allocate the akcipher transform, and set up * the akcipher request. * */ tfm = crypto_alloc_akcipher(driver, 0, 0); if (IS_ERR(tfm)) { pr_err("error: allocating akcipher algorithm %s failed: %ld\n", driver, PTR_ERR(tfm)); tfm = NULL; goto test_rsa_end; } req = akcipher_request_alloc(tfm, GFP_KERNEL); if (IS_ERR(req)) { pr_err("error: allocating akcipher request %s failed\n", driver); req = NULL; goto test_rsa_end; } /* now set pub key for verify test. */ ret = crypto_akcipher_set_pub_key(tfm, pub + 24, pub_len - 24); if (ret) { pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); goto test_rsa_end; } { unsigned int maxsize = crypto_akcipher_maxsize(tfm); if (maxsize != key_len) { pr_err("error: crypto_akcipher_maxsize " "returned %d, expected %d\n", maxsize, key_len); goto test_rsa_end; } } /* kernel module public encrypt */ sg_init_one(&src, dec, key_len); sg_init_one(&dst, enc, key_len); akcipher_request_set_crypt(req, &src, &dst, key_len, key_len); ret = crypto_akcipher_encrypt(req); if (ret) { pr_err("error: crypto_akcipher_encrypt returned: %d\n", ret); goto test_rsa_end; } /* wolfcrypt private decrypt */ memset(dec, 0, key_len + 1); dec_ret = wc_RsaDirect(enc, key_len, dec, &out_len, key, RSA_PRIVATE_DECRYPT, &rng); if (dec_ret != (int) key_len || key_len != out_len) { pr_err("error: rsa priv dec returned: %d, %d\n", dec_ret, out_len); goto test_rsa_end; } n_diff = memcmp(dec, plaintext, key_len); if (n_diff) { pr_err("error: decrypt doesn't match plain: %d\n", n_diff); goto test_rsa_end; } /* wolfcrypt public encrypt */ enc_ret = wc_RsaDirect(dec, key_len, enc, &out_len, key, RSA_PUBLIC_ENCRYPT, &rng); if (enc_ret != (int) key_len || key_len != out_len) { pr_err("error: rsa pub enc returned: %d, %d\n", enc_ret, out_len); ret = -1; goto test_rsa_end; } ret = crypto_akcipher_set_priv_key(tfm, priv, priv_len); if (ret) { pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", ret); goto test_rsa_end; } { unsigned int maxsize = crypto_akcipher_maxsize(tfm); if (maxsize != key_len) { pr_err("error: crypto_akcipher_maxsize " "returned %d, expected %d\n", maxsize, key_len); goto test_rsa_end; } } /* kernel module decrypt with rsa private key */ sg_init_one(&src, enc, key_len); sg_init_one(&dst, dec, key_len); akcipher_request_set_crypt(req, &src, &dst, key_len, key_len); memset(dec, 0, key_len); ret = crypto_akcipher_decrypt(req); if (ret) { pr_err("error: crypto_akcipher_decrypt returned: %d\n", ret); goto test_rsa_end; } n_diff = memcmp(dec, plaintext, key_len); if (n_diff) { pr_err("error: decrypt doesn't match plain: %d\n", n_diff); goto test_rsa_end; } test_rc = 0; test_rsa_end: if (req) { akcipher_request_free(req); req = NULL; } if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } if (pub) { free(pub); pub = NULL; } if (priv) { free(priv); priv = NULL; } if (plaintext) { free(plaintext); plaintext = NULL; } if (dec) { free(dec); dec = NULL; } if (enc) { free(enc); enc = NULL; } if (init_key) { wc_FreeRsaKey(key); init_key = 0; } if (init_rng) { wc_FreeRng(&rng); init_rng = 0; } if (key) { free(key); key = NULL; } #ifdef WOLFKM_DEBUG_RSA pr_info("info: %s, %d, %d: self test returned: %d\n", driver, nbits, key_len, ret); #endif /* WOLFKM_DEBUG_RSA */ return test_rc; } #endif /* LINUXKM_DIRECT_RSA */ #if (!defined(NO_SHA256) || defined(WOLFSSL_SHA512)) && \ defined(WOLFSSL_KEY_GEN) static int linuxkm_test_pkcs1_driver(const char * driver, int nbits, int hash_oid, word32 hash_len) { int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); int ret = 0; struct crypto_akcipher * tfm = NULL; struct akcipher_request * req = NULL; RsaKey * key = NULL; WC_RNG rng; byte * priv = NULL; /* priv der */ word32 priv_len = 0; byte * pub = NULL; /* pub der */ word32 pub_len = 0; byte init_rng = 0; byte init_key = 0; static const byte p_vector[] = /* Now is the time for all good men w/o trailing 0 */ { 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20, 0x67,0x6f,0x6f,0x64,0x20,0x6d,0x65,0x6e }; byte * hash = NULL; byte * sig = NULL; byte * km_sig = NULL; byte * dec = NULL; byte * enc = NULL; byte * dec2 = NULL; byte * enc2 = NULL; word32 key_len = 0; word32 sig_len = 0; word32 enc_len = 0; struct scatterlist src, dst; #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) struct scatterlist src_tab[2]; #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ int n_diff = 0; hash = malloc(WC_SHA512_DIGEST_SIZE); if (! hash) { pr_err("error: allocating hash buffer failed.\n"); test_rc = MEMORY_E; goto test_pkcs1_end; } /* hash the test msg with hash algo. */ ret = wc_Hash(wc_OidGetHash(hash_oid), p_vector, sizeof(p_vector), hash, hash_len); if (ret) { pr_err("error: wc_Hash returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } key = (RsaKey*)malloc(sizeof(RsaKey)); if (key == NULL) { pr_err("error: allocating key(%zu) failed\n", sizeof(RsaKey)); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(&rng, 0, sizeof(rng)); memset(key, 0, sizeof(RsaKey)); ret = wc_InitRng(&rng); if (ret) { pr_err("error: init rng returned: %d\n", ret); goto test_pkcs1_end; } init_rng = 1; ret = wc_InitRsaKey(key, NULL); if (ret) { pr_err("error: init rsa key returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } init_key = 1; #ifdef WC_RSA_BLINDING ret = wc_RsaSetRNG(key, &rng); if (ret) { pr_err("error: rsa set rng returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } #endif /* WC_RSA_BLINDING */ ret = wc_MakeRsaKey(key, nbits, WC_RSA_EXPONENT, &rng); if (ret) { pr_err("error: make rsa key returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } key_len = wc_RsaEncryptSize(key); if (key_len <= 0) { pr_err("error: rsa encrypt size returned: %d\n", key_len); test_rc = key_len; goto test_pkcs1_end; } sig = (byte*)malloc(key_len); if (sig == NULL) { pr_err("error: allocating sig(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(sig, 0, key_len); km_sig = (byte*)malloc(key_len); if (km_sig == NULL) { pr_err("error: allocating km_sig(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(km_sig, 0, key_len); enc = (byte*)malloc(key_len); if (enc == NULL) { pr_err("error: allocating enc(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(enc, 0, key_len); dec = (byte*)malloc(key_len + 1); if (dec == NULL) { pr_err("error: allocating dec(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(dec, 0, key_len + 1); enc2 = (byte*)malloc(key_len); if (enc2 == NULL) { pr_err("error: allocating enc2(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(enc2, 0, key_len); dec2 = (byte*)malloc(key_len + 1); if (dec2 == NULL) { pr_err("error: allocating dec2(%d) failed\n", key_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(dec2, 0, key_len + 1); /** * Now export Rsa Der to pub and priv. * */ priv_len = wc_RsaKeyToDer(key, NULL, 0); if (priv_len <= 0) { pr_err("error: rsa priv to der returned: %d\n", priv_len); test_rc = priv_len; goto test_pkcs1_end; } priv = (byte*)malloc(priv_len); if (priv == NULL) { pr_err("error: allocating priv(%d) failed\n", priv_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(priv, 0, priv_len); priv_len = wc_RsaKeyToDer(key, priv, priv_len); if (priv_len <= 0) { pr_err("error: rsa priv to der returned: %d\n", priv_len); test_rc = priv_len; goto test_pkcs1_end; } /* get rsa pub der */ pub_len = wc_RsaKeyToPublicDer(key, NULL, 0); if (pub_len <= 0) { pr_err("error: rsa pub to der returned: %d\n", pub_len); test_rc = pub_len; goto test_pkcs1_end; } pub = (byte*)malloc(pub_len); if (pub == NULL) { pr_err("error: allocating pub(%d) failed\n", pub_len); test_rc = MEMORY_E; goto test_pkcs1_end; } memset(pub, 0, pub_len); pub_len = wc_RsaKeyToPublicDer(key, pub, pub_len); if (pub_len <= 0) { pr_err("error: rsa pub to der returned: %d\n", pub_len); test_rc = pub_len; goto test_pkcs1_end; } /** * Sanity test: first sign and verify with direct wolfcrypt API. * */ /* encode the hash. */ enc_len = wc_EncodeSignature(enc, hash, hash_len, hash_oid); if (enc_len <= 0) { pr_err("error: wc_EncodeSignature returned: %d\n", enc_len); test_rc = enc_len; goto test_pkcs1_end; } sig_len = wc_RsaSSL_Sign(enc, enc_len, sig, key_len, key, &rng); if (sig_len <= 0) { pr_err("error: wc_RsaSSL_Sign returned: %d\n", sig_len); test_rc = sig_len; goto test_pkcs1_end; } memset(dec, 0, key_len + 1); ret = wc_RsaSSL_Verify(sig, key_len, dec, enc_len, key); if (ret <= 0 || ret != (int) enc_len) { pr_err("error: wc_RsaSSL_Verify returned %d, expected %d\n" , ret, enc_len); test_rc = ret; goto test_pkcs1_end; } /* dec and enc should match now. */ n_diff = memcmp(dec, enc, enc_len); if (n_diff) { pr_err("error: decrypt doesn't match plain: %d\n", n_diff); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } /** * Allocate the akcipher transform, and set up * the akcipher request. * */ tfm = crypto_alloc_akcipher(driver, 0, 0); if (IS_ERR(tfm)) { pr_err("error: allocating akcipher algorithm %s failed: %ld\n", driver, PTR_ERR(tfm)); if (PTR_ERR(tfm) == -ENOMEM) test_rc = MEMORY_E; else test_rc = BAD_FUNC_ARG; tfm = NULL; goto test_pkcs1_end; } req = akcipher_request_alloc(tfm, GFP_KERNEL); if (IS_ERR(req)) { pr_err("error: allocating akcipher request %s failed\n", driver); if (PTR_ERR(req) == -ENOMEM) test_rc = MEMORY_E; else test_rc = BAD_FUNC_ARG; req = NULL; goto test_pkcs1_end; } #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) /** * pkcs1 sign and verify test * */ ret = crypto_akcipher_set_priv_key(tfm, priv, priv_len); if (ret) { pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } { unsigned int maxsize = crypto_akcipher_maxsize(tfm); if (maxsize != key_len) { pr_err("error: crypto_akcipher_maxsize " "returned %d, expected %d\n", maxsize, key_len); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } } sg_init_one(&src, hash, hash_len); sg_init_one(&dst, km_sig, key_len); memset(km_sig, 0, key_len); akcipher_request_set_crypt(req, &src, &dst, hash_len, key_len); ret = crypto_akcipher_sign(req); if (ret) { pr_err("error: crypto_akcipher_sign returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } /* now set pub key for verify test. */ ret = crypto_akcipher_set_pub_key(tfm, pub + 24, pub_len - 24); if (ret) { pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } { unsigned int maxsize = crypto_akcipher_maxsize(tfm); if (maxsize != key_len) { pr_err("error: crypto_akcipher_maxsize " "returned %d, expected %d\n", maxsize, key_len); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } } /* * Set sig as src, and null as dst. * src_tab is: * src_tab[0]: signature * src_tab[1]: message (digest) * * src_len is sig size plus digest size. */ sg_init_table(src_tab, 2); sg_set_buf(&src_tab[0], km_sig, key_len); sg_set_buf(&src_tab[1], hash, hash_len); akcipher_request_set_crypt(req, src_tab, NULL, key_len, hash_len); ret = crypto_akcipher_verify(req); if (ret) { pr_err("error: crypto_akcipher_verify returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } memset(dec, 0, key_len + 1); ret = wc_RsaSSL_Verify(km_sig, key_len, dec, key_len, key); if (ret <= 0) { pr_err("error: wc_RsaSSL_Verify returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } n_diff = memcmp(km_sig, sig, sig_len); if (n_diff) { pr_err("error: km-sig doesn't match sig: %d\n", n_diff); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } /* dec and enc should match now. */ n_diff = memcmp(dec, enc, enc_len); if (n_diff) { pr_err("error: decrypt doesn't match plain: %d\n", n_diff); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ /* * pkcs1 encrypt and ecrypt test */ memset(enc, 0, key_len); memset(enc2, 0, key_len); memset(dec, 0, key_len); memset(dec2, 0, key_len); memcpy(dec, p_vector, sizeof(p_vector)); memcpy(dec2, p_vector, sizeof(p_vector)); sg_init_one(&src, dec, sizeof(p_vector)); sg_init_one(&dst, enc, key_len); akcipher_request_set_crypt(req, &src, &dst, sizeof(p_vector), key_len); /* now set pub key for verify test. */ ret = crypto_akcipher_set_pub_key(tfm, pub + 24, pub_len - 24); if (ret) { pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } ret = crypto_akcipher_encrypt(req); if (ret) { pr_err("error: crypto_akcipher_encrypt returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } ret = wc_RsaPublicEncrypt(dec2, sizeof(p_vector), enc2, key_len, key, &rng); if (unlikely(ret != (int) key_len)) { pr_err("error: wc_RsaPublicEncrypt returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } memset(dec, 0, key_len); memset(dec2, 0, key_len); sg_init_one(&src, enc, key_len); sg_init_one(&dst, dec, sizeof(p_vector)); akcipher_request_set_crypt(req, &src, &dst, key_len, sizeof(p_vector)); ret = crypto_akcipher_set_priv_key(tfm, priv, priv_len); if (ret) { pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } ret = crypto_akcipher_decrypt(req); if (ret) { pr_err("error: crypto_akcipher_decrypt returned: %d\n", ret); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } ret = wc_RsaPrivateDecrypt(enc2, key_len, dec2, sizeof(p_vector), key); if (ret != (int) sizeof(p_vector)) { pr_err("error: wc_RsaPrivateDecrypt returned: %d\n", ret); test_rc = ret; goto test_pkcs1_end; } n_diff = memcmp(dec, dec2, sizeof(p_vector)); if (n_diff) { pr_err("error: decrypt don't match: %d\n", n_diff); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } n_diff = memcmp(dec, p_vector, sizeof(p_vector)); if (n_diff) { pr_err("error: decrypt doesn't match plaintext: %d\n", n_diff); test_rc = BAD_FUNC_ARG; goto test_pkcs1_end; } test_rc = 0; test_pkcs1_end: if (req) { akcipher_request_free(req); req = NULL; } if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } if (priv) { free(priv); priv = NULL; } if (pub) { free(pub); pub = NULL; } if (enc2) { free(enc2); enc2 = NULL; } if (dec2) { free(dec2); dec2 = NULL; } if (enc) { free(enc); enc = NULL; } if (dec) { free(dec); dec = NULL; } if (km_sig) { free(km_sig); km_sig = NULL; } if (sig) { free(sig); sig = NULL; } if (init_rng) { wc_FreeRng(&rng); init_rng = 0; } if (init_key) { wc_FreeRsaKey(key); init_key = 0; } if (key) { free(key); key = NULL; } if (hash) { free(hash); } #ifdef WOLFKM_DEBUG_RSA pr_info("info: %s, %d, %d: self test returned: %d\n", driver, nbits, key_len, ret); #endif /* WOLFKM_DEBUG_RSA */ return test_rc; } #endif /* (!NO_SHA256 || WOLFSSL_SHA512) && WOLFSSL_KEY_GEN */ /* * returns the additional encoding length for given hash oid. */ #if !defined(LINUXKM_AKCIPHER_NO_SIGNVERIFY) static int get_hash_enc_len(int hash_oid) { int enc_len = -1; switch (hash_oid) { case SHA256h: case SHA512h: enc_len = 19; break; default: break; } return enc_len; } #endif /* !LINUXKM_AKCIPHER_NO_SIGNVERIFY */ #endif /* !NO_RSA && * (LINUXKM_LKCAPI_REGISTER_ALL || LINUXKM_LKCAPI_REGISTER_RSA) */