From 2972af109e10c5ce30e548190e3eee28327d6043 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sun, 27 Oct 2019 15:28:29 +0100 Subject: [PATCH] PROV: Add RSA functionality for key generation This includes added support in legacy controls Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/10289) --- crypto/evp/pmeth_lib.c | 6 + crypto/rsa/rsa_lib.c | 91 +++++++++++++ include/openssl/core_names.h | 2 +- include/openssl/rsa.h | 16 +-- providers/implementations/keymgmt/rsa_kmgmt.c | 124 ++++++++++++++++++ util/libcrypto.num | 3 + 6 files changed, 229 insertions(+), 13 deletions(-) diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index f7bdbebbc1..a81908a962 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -951,6 +951,12 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name, name = OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL; else if (strcmp(name, "rsa_pss_saltlen") == 0) name = OSSL_SIGNATURE_PARAM_PSS_SALTLEN; + else if (strcmp(name, "rsa_keygen_bits") == 0) + name = OSSL_PKEY_PARAM_RSA_BITS; + else if (strcmp(name, "rsa_keygen_pubexp") == 0) + name = OSSL_PKEY_PARAM_RSA_E; + else if (strcmp(name, "rsa_keygen_primes") == 0) + name = OSSL_PKEY_PARAM_RSA_PRIMES; # ifndef OPENSSL_NO_DH else if (strcmp(name, "dh_pad") == 0) name = OSSL_EXCHANGE_PARAM_PAD; diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index ada5388bb2..0a0d3e84db 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -20,6 +20,7 @@ #include #include "internal/cryptlib.h" #include "internal/refcount.h" +#include "internal/param_build.h" #include "crypto/bn.h" #include "crypto/evp.h" #include "crypto/rsa.h" @@ -1266,4 +1267,94 @@ int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *saltlen) return 1; } + +int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) +{ + OSSL_PARAM params[2], *p = params; + size_t bits2 = bits; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL); + + *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bits2); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_set_params(ctx, params)) + return 0; + + return 1; +} + +int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *pubexp) +{ + OSSL_PARAM_BLD tmpl; + OSSL_PARAM *params; + int ret; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp); + + ossl_param_bld_init(&tmpl); + if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_RSA_E, pubexp) + || (params = ossl_param_bld_to_param(&tmpl)) == NULL) + return 0; + + ret = EVP_PKEY_CTX_set_params(ctx, params); + ossl_param_bld_free(params); + return ret; +} + +int EVP_PKEY_CTX_set_rsa_keygen_primes(EVP_PKEY_CTX *ctx, int primes) +{ + OSSL_PARAM params[2], *p = params; + size_t primes2 = primes; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES, primes, + NULL); + + *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_PRIMES, &primes2); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_set_params(ctx, params)) + return 0; + + return 1; +} #endif diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index e2639ec1fc..1f67475a9a 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -221,7 +221,7 @@ extern "C" { #define OSSL_PKEY_PARAM_RSA_EXPONENT "rsa-exponent" #define OSSL_PKEY_PARAM_RSA_COEFFICIENT "rsa-coefficient" /* Key generation parameters */ -#define OSSL_PKEY_PARAM_RSA_BITS "bits" +#define OSSL_PKEY_PARAM_RSA_BITS OSSL_PKEY_PARAM_BITS #define OSSL_PKEY_PARAM_RSA_PRIMES "primes" /* Key Exchange parameters */ diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index 1f0687df24..49040bf7e6 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -111,6 +111,10 @@ int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *pad_mode); int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int saltlen); int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *saltlen); +int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits); +int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *pubexp); +int EVP_PKEY_CTX_set_rsa_keygen_primes(EVP_PKEY_CTX *ctx, int primes); + /* Salt length matches digest */ # define RSA_PSS_SALTLEN_DIGEST -1 /* Verify only: auto detect salt length */ @@ -124,18 +128,6 @@ int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *saltlen); EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, EVP_PKEY_OP_KEYGEN, \ EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) -# define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ - RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ - EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) - -# define EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp) \ - RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ - EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp) - -# define EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, primes) \ - RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ - EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES, primes, NULL) - int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname, const char *mdprops); diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c index 8c7673ad49..4e77f5c4a7 100644 --- a/providers/implementations/keymgmt/rsa_kmgmt.c +++ b/providers/implementations/keymgmt/rsa_kmgmt.c @@ -28,6 +28,11 @@ #include "crypto/rsa.h" static OSSL_OP_keymgmt_new_fn rsa_newdata; +static OSSL_OP_keymgmt_gen_init_fn rsa_gen_init; +static OSSL_OP_keymgmt_gen_set_params_fn rsa_gen_set_params; +static OSSL_OP_keymgmt_gen_settable_params_fn rsa_gen_settable_params; +static OSSL_OP_keymgmt_gen_fn rsa_gen; +static OSSL_OP_keymgmt_gen_cleanup_fn rsa_gen_cleanup; static OSSL_OP_keymgmt_free_fn rsa_freedata; static OSSL_OP_keymgmt_get_params_fn rsa_get_params; static OSSL_OP_keymgmt_gettable_params_fn rsa_gettable_params; @@ -409,8 +414,127 @@ static int rsa_validate(void *keydata, int selection) return ok; } +struct rsa_gen_ctx { + OPENSSL_CTX *libctx; + + size_t nbits; + BIGNUM *pub_exp; + size_t primes; + + /* For generation callback */ + OSSL_CALLBACK *cb; + void *cbarg; +}; + +static int rsa_gencb(int p, int n, BN_GENCB *cb) +{ + struct rsa_gen_ctx *gctx = BN_GENCB_get_arg(cb); + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + + return gctx->cb(params, gctx->cbarg); +} + +static void *rsa_gen_init(void *provctx, int selection) +{ + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx); + struct rsa_gen_ctx *gctx = NULL; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + if ((gctx->pub_exp = BN_new()) == NULL + || !BN_set_word(gctx->pub_exp, RSA_F4)) { + BN_free(gctx->pub_exp); + gctx = NULL; + } else { + gctx->nbits = 2048; + gctx->primes = RSA_DEFAULT_PRIME_NUM; + } + } + return gctx; +} + +static int rsa_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct rsa_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_BITS)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->nbits)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_PRIMES)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->primes)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E)) != NULL + && !OSSL_PARAM_get_BN(p, &gctx->pub_exp)) + return 0; + return 1; +} + +static const OSSL_PARAM *rsa_gen_settable_params(void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, NULL), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_PRIMES, NULL), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), + OSSL_PARAM_END + }; + + return settable; +} + +static void *rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct rsa_gen_ctx *gctx = genctx; + RSA *rsa = NULL; + BN_GENCB *gencb = NULL; + + if (gctx == NULL + || (rsa = rsa_new_with_ctx(gctx->libctx)) == NULL) + return NULL; + + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, rsa_gencb, genctx); + + if (!RSA_generate_multi_prime_key(rsa, (int)gctx->nbits, (int)gctx->primes, + gctx->pub_exp, gencb)) { + RSA_free(rsa); + rsa = NULL; + } + + BN_GENCB_free(gencb); + + return rsa; +} + +static void rsa_gen_cleanup(void *genctx) +{ + struct rsa_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; + + BN_clear_free(gctx->pub_exp); + OPENSSL_free(gctx); +} + const OSSL_DISPATCH rsa_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))rsa_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))rsa_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, + (void (*)(void))rsa_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))rsa_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))rsa_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))rsa_gen_cleanup }, { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))rsa_freedata }, { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params }, { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params }, diff --git a/util/libcrypto.num b/util/libcrypto.num index 9c9213aff4..30978d2fb0 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4981,3 +4981,6 @@ OSSL_CMP_SRV_CTX_set_accept_unprotected ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_SRV_CTX_set_accept_raverified ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_SRV_CTX_set_grant_implicit_confirm ? 3_0_0 EXIST::FUNCTION:CMP EVP_PKEY_gen ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_set_rsa_keygen_bits ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_keygen_pubexp ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_keygen_primes ? 3_0_0 EXIST::FUNCTION:RSA