From: Richard Levitte Date: Thu, 19 Mar 2020 13:02:28 +0000 (+0100) Subject: PROV: Implement EC param / key generation X-Git-Tag: openssl-3.0.0-alpha1~107 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=1f185f51a7899e1eddc9161d7781e3d5ae86ab78;p=oweals%2Fopenssl.git PROV: Implement EC param / key generation Reviewed-by: Matt Caswell Reviewed-by: Nicola Tuveri (Merged from https://github.com/openssl/openssl/pull/11328) --- diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index cf6b9cd893..12826beb0b 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2819,6 +2819,7 @@ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE:165:\ PROV_R_INAVLID_UKM_LENGTH:146:inavlid ukm length PROV_R_INVALID_AAD:108:invalid aad PROV_R_INVALID_CONSTANT_LENGTH:157:invalid constant length +PROV_R_INVALID_CURVE:176:invalid curve PROV_R_INVALID_CUSTOM_LENGTH:111:invalid custom length PROV_R_INVALID_DATA:115:invalid data PROV_R_INVALID_DIGEST:122:invalid digest @@ -2858,6 +2859,7 @@ PROV_R_MISSING_XCGHASH:135:missing xcghash PROV_R_NOT_SUPPORTED:136:not supported PROV_R_NOT_XOF_OR_INVALID_LENGTH:113:not xof or invalid length PROV_R_NO_KEY_SET:114:no key set +PROV_R_NO_PARAMETERS_SET:177:no parameters set PROV_R_OUTPUT_BUFFER_TOO_SMALL:106:output buffer too small PROV_R_PSS_SALTLEN_TOO_SMALL:172:pss saltlen too small PROV_R_READ_KEY:159:read key diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h index f834a71347..5b3bcbb6a0 100644 --- a/providers/common/include/prov/providercommonerr.h +++ b/providers/common/include/prov/providercommonerr.h @@ -69,6 +69,7 @@ int ERR_load_PROV_strings(void); # define PROV_R_INAVLID_UKM_LENGTH 146 # define PROV_R_INVALID_AAD 108 # define PROV_R_INVALID_CONSTANT_LENGTH 157 +# define PROV_R_INVALID_CURVE 176 # define PROV_R_INVALID_CUSTOM_LENGTH 111 # define PROV_R_INVALID_DATA 115 # define PROV_R_INVALID_DIGEST 122 @@ -108,6 +109,7 @@ int ERR_load_PROV_strings(void); # define PROV_R_NOT_SUPPORTED 136 # define PROV_R_NOT_XOF_OR_INVALID_LENGTH 113 # define PROV_R_NO_KEY_SET 114 +# define PROV_R_NO_PARAMETERS_SET 177 # define PROV_R_OUTPUT_BUFFER_TOO_SMALL 106 # define PROV_R_PSS_SALTLEN_TOO_SMALL 172 # define PROV_R_READ_KEY 159 diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c index 1a65e2cc87..1018fa31ea 100644 --- a/providers/common/provider_err.c +++ b/providers/common/provider_err.c @@ -47,6 +47,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_AAD), "invalid aad"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CONSTANT_LENGTH), "invalid constant length"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CURVE), "invalid curve"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CUSTOM_LENGTH), "invalid custom length"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DATA), "invalid data"}, @@ -99,6 +100,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NOT_XOF_OR_INVALID_LENGTH), "not xof or invalid length"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_KEY_SET), "no key set"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_PARAMETERS_SET), "no parameters set"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_OUTPUT_BUFFER_TOO_SMALL), "output buffer too small"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_PSS_SALTLEN_TOO_SMALL), diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c index 661aa2de9f..0e310ecbae 100644 --- a/providers/implementations/keymgmt/ec_kmgmt.c +++ b/providers/implementations/keymgmt/ec_kmgmt.c @@ -16,15 +16,25 @@ #include #include #include +#include #include #include "crypto/bn.h" #include "crypto/ec.h" #include "prov/implementations.h" #include "prov/providercommon.h" +#include "prov/providercommonerr.h" #include "prov/provider_ctx.h" #include "internal/param_build_set.h" static OSSL_OP_keymgmt_new_fn ec_newdata; +static OSSL_OP_keymgmt_gen_init_fn ec_gen_init; +static OSSL_OP_keymgmt_gen_set_template_fn ec_gen_set_template; +static OSSL_OP_keymgmt_gen_set_params_fn ec_gen_set_params; +static OSSL_OP_keymgmt_gen_settable_params_fn ec_gen_settable_params; +static OSSL_OP_keymgmt_gen_get_params_fn ec_gen_get_params; +static OSSL_OP_keymgmt_gen_gettable_params_fn ec_gen_gettable_params; +static OSSL_OP_keymgmt_gen_fn ec_gen; +static OSSL_OP_keymgmt_gen_cleanup_fn ec_gen_cleanup; static OSSL_OP_keymgmt_free_fn ec_freedata; static OSSL_OP_keymgmt_get_params_fn ec_get_params; static OSSL_OP_keymgmt_gettable_params_fn ec_gettable_params; @@ -558,8 +568,195 @@ int ec_validate(void *keydata, int selection) return ok; } +struct ec_gen_ctx { + OPENSSL_CTX *libctx; + + EC_GROUP *gen_group; + int selection; +}; + +static void *ec_gen_init(void *provctx, int selection) +{ + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx); + struct ec_gen_ctx *gctx = NULL; + + if ((selection & (EC_POSSIBLE_SELECTIONS)) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + gctx->gen_group = NULL; + gctx->selection = selection; + } + return gctx; +} + +static int ec_gen_set_group(void *genctx, int nid) +{ + struct ec_gen_ctx *gctx = genctx; + EC_GROUP *group; + + group = EC_GROUP_new_by_curve_name_ex(gctx->libctx, nid); + if (group == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); + return 0; + } + EC_GROUP_free(gctx->gen_group); + gctx->gen_group = group; + return 1; +} +static int ec_gen_set_template(void *genctx, void *templ) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = templ; + const EC_GROUP *ec_group; + + if (gctx == NULL || ec == NULL) + return 0; + if ((ec_group = EC_KEY_get0_group(ec)) == NULL) + return 0; + return ec_gen_set_group(gctx, EC_GROUP_get_curve_name(ec_group)); +} + +static int ec_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct ec_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME)) + != NULL) { + const char *curve_name = NULL; + int ret = 0; + + switch (p->data_type) { + case OSSL_PARAM_UTF8_STRING: + /* The OSSL_PARAM functions have no support for this */ + curve_name = p->data; + ret = (curve_name != NULL); + break; + case OSSL_PARAM_UTF8_PTR: + ret = OSSL_PARAM_get_utf8_ptr(p, &curve_name); + break; + } + + if (ret) { + int nid = ec_curve_name2nid(curve_name); + + if (nid == NID_undef) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); + ret = 0; + } else { + ret = ec_gen_set_group(gctx, nid); + } + } + return ret; + } + return 1; +} + +static const OSSL_PARAM *ec_gen_settable_params(void *provctx) +{ + static OSSL_PARAM settable[] = { + { OSSL_PKEY_PARAM_EC_NAME, OSSL_PARAM_UTF8_STRING, NULL, 0, 0 }, + OSSL_PARAM_END + }; + + return settable; +} + +static int ec_gen_get_params(void *genctx, OSSL_PARAM params[]) +{ + struct ec_gen_ctx *gctx = genctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_NAME)) != NULL) { + int nid = EC_GROUP_get_curve_name(gctx->gen_group); + int ret = 0; + const char *curve_name = ec_curve_nid2name(nid); + + switch (p->data_type) { + case OSSL_PARAM_UTF8_STRING: + ret = OSSL_PARAM_set_utf8_string(p, curve_name); + break; + case OSSL_PARAM_UTF8_PTR: + ret = OSSL_PARAM_set_utf8_ptr(p, curve_name); + break; + } + return ret; + } + return 1; +} + +static const OSSL_PARAM *ec_gen_gettable_params(void *provctx) +{ + static OSSL_PARAM gettable[] = { + { OSSL_PKEY_PARAM_EC_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 }, + OSSL_PARAM_END + }; + + return gettable; +} + +static int ec_gen_assign_group(EC_KEY *ec, EC_GROUP *group) +{ + if (group == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET); + return 0; + } + return EC_KEY_set_group(ec, group) > 0; +} + +/* + * The callback arguments (osslcb & cbarg) are not used by EC_KEY generation + */ +static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = NULL; + int ret = 1; /* Start optimistically */ + + if (gctx == NULL + || (ec = EC_KEY_new_ex(gctx->libctx)) == NULL) + return NULL; + + /* We must always assign a group, no matter what */ + ret = ec_gen_assign_group(ec, gctx->gen_group); + /* Whether you want it or not, you get a keypair, not just one half */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + ret = ret && EC_KEY_generate_key(ec); + + if (ret) + return ec; + + /* Something went wrong, throw the key away */ + EC_KEY_free(ec); + return NULL; +} + +static void ec_gen_cleanup(void *genctx) +{ + struct ec_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; + + EC_GROUP_free(gctx->gen_group); + OPENSSL_free(gctx); +} + const OSSL_DISPATCH ec_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, + (void (*)(void))ec_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ec_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))ec_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN_GET_PARAMS, (void (*)(void))ec_gen_get_params }, + { OSSL_FUNC_KEYMGMT_GEN_GETTABLE_PARAMS, + (void (*)(void))ec_gen_gettable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))ec_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ec_gen_cleanup }, { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata }, { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))ec_get_params }, { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ec_gettable_params }, @@ -573,6 +770,6 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export }, { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types }, { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, - (void (*)(void))ec_query_operation_name }, + (void (*)(void))ec_query_operation_name }, { 0, NULL } };