diff --git a/CHANGES b/CHANGES index 23a86ddcd1..f500f2f4cf 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,13 @@ Changes between 1.1.1 and 3.0.0 [xx XXX xxxx] + *) Added functionality to create an EVP_PKEY from user data. This + is effectively the same as creating a RSA, DH or DSA object and + then assigning them to an EVP_PKEY, but directly using algorithm + agnostic EVP functions. A benefit is that this should be future + proof for public key algorithms to come. + [Richard Levitte] + *) Change the interpretation of the '--api' configuration option to mean that this is a desired API compatibility level with no further meaning. The previous interpretation, that this would diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c index 5e9ec73f7d..583e8b362a 100644 --- a/crypto/evp/keymgmt_lib.c +++ b/crypto/evp/keymgmt_lib.c @@ -254,6 +254,24 @@ void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk) } } +void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, + const OSSL_PARAM params[], int domainparams) +{ + void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); + void *provdata = domainparams + ? keymgmt->importdomparams(provctx, params) + : keymgmt->importkey(provctx, params); + + evp_keymgmt_clear_pkey_cache(target); + if (provdata != NULL) { + EVP_KEYMGMT_up_ref(keymgmt); + target->pkeys[0].keymgmt = keymgmt; + target->pkeys[0].provdata = provdata; + target->pkeys[0].domainparams = domainparams; + } + + return provdata; +} /* internal functions */ /* TODO(3.0) decide if these should be public or internal */ diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c index 2564bbd03e..f872377671 100644 --- a/crypto/evp/pmeth_gn.c +++ b/crypto/evp/pmeth_gn.c @@ -15,6 +15,90 @@ #include "crypto/bn.h" #include "crypto/asn1.h" #include "crypto/evp.h" +#include "evp_local.h" + +static int fromdata_init(EVP_PKEY_CTX *ctx, int operation) +{ + if (ctx == NULL || ctx->algorithm == NULL) + goto not_supported; + + evp_pkey_ctx_free_old_ops(ctx); + ctx->operation = operation; + if (ctx->keymgmt == NULL) + ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->algorithm, ctx->propquery); + if (ctx->keymgmt == NULL) + goto not_supported; + + return 1; + + not_supported: + ctx->operation = EVP_PKEY_OP_UNDEFINED; + ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; +} + +int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx) +{ + return fromdata_init(ctx, EVP_PKEY_OP_PARAMFROMDATA); +} + +int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx) +{ + return fromdata_init(ctx, EVP_PKEY_OP_KEYFROMDATA); +} + +int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[]) +{ + void *provdata = NULL; + + if (ctx == NULL || (ctx->operation & EVP_PKEY_OP_TYPE_FROMDATA) == 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } + + if (ppkey == NULL) + return -1; + + if (*ppkey == NULL) + *ppkey = EVP_PKEY_new(); + + if (*ppkey == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return -1; + } + + provdata = + evp_keymgmt_fromdata(*ppkey, ctx->keymgmt, params, + ctx->operation == EVP_PKEY_OP_PARAMFROMDATA); + + if (provdata == NULL) + return 0; + /* provdata is cached in *ppkey, so we need not bother with it further */ + return 1; +} + +/* + * TODO(3.0) Re-evalutate the names, it's possible that we find these to be + * better: + * + * EVP_PKEY_param_settable() + * EVP_PKEY_param_gettable() + */ +const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx) +{ + /* We call fromdata_init to get ctx->keymgmt populated */ + if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED)) + return evp_keymgmt_importdomparam_types(ctx->keymgmt); + return NULL; +} + +const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx) +{ + /* We call fromdata_init to get ctx->keymgmt populated */ + if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED)) + return evp_keymgmt_importdomparam_types(ctx->keymgmt); + return NULL; +} int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx) { diff --git a/doc/man3/EVP_PKEY_fromdata.pod b/doc/man3/EVP_PKEY_fromdata.pod new file mode 100644 index 0000000000..0e3dc5c29f --- /dev/null +++ b/doc/man3/EVP_PKEY_fromdata.pod @@ -0,0 +1,69 @@ +=pod + +=head1 NAME + +EVP_PKEY_param_fromdata_init, EVP_PKEY_key_fromdata_init, EVP_PKEY_fromdata, +EVP_PKEY_param_fromdata_settable, EVP_PKEY_key_fromdata_settable +- functions to create domain parameters and keys from user data + +=head1 SYNOPSIS + + #include + + int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx); + int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx); + int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[]); + const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx); + const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx); + +=head1 DESCRIPTION + +EVP_PKEY_param_fromdata_init() initializes a public key algorithm context +for creating domain parameters from user data. + +EVP_PKEY_key_fromdata_init() initializes a public key algorithm context for +creating a key from user data. + +EVP_PKEY_fromdata() creates domain parameters or a key, given data from +I and a context that's been initialized with +EVP_PKEY_param_fromdata_init() or EVP_PKEY_key_fromdata_init(). The result is +written to I<*ppkey>. + +EVP_PKEY_param_fromdata_settable() and EVP_PKEY_key_fromdata_settable() +get a constant B array that describes the settable parameters +that can be used with EVP_PKEY_fromdata(). +See L for the use of B as parameter descriptor. + +=head1 NOTES + +These functions only work with key management methods coming from a +provider. + +=for comment We may choose to make this available for legacy methods too... + +=head1 RETURN VALUES + +EVP_PKEY_key_fromdata_init(), EVP_PKEY_param_fromdata_init() and +EVP_PKEY_fromdata() return 1 for success and 0 or a negative value for +failure. In particular a return value of -2 indicates the operation is +not supported by the public key algorithm. + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +These functions were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut + diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 8f8def2655..7753bc0e42 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -581,6 +581,9 @@ void evp_app_cleanup_int(void); void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, int domainparams); void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk); +void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, + const OSSL_PARAM params[], int domainparams); + /* KEYMGMT provider interface functions */ void *evp_keymgmt_importdomparams(const EVP_KEYMGMT *keymgmt, diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 06f8b1f1db..05bf87147c 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1375,14 +1375,16 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); # define EVP_PKEY_OP_UNDEFINED 0 # define EVP_PKEY_OP_PARAMGEN (1<<1) # define EVP_PKEY_OP_KEYGEN (1<<2) -# define EVP_PKEY_OP_SIGN (1<<3) -# define EVP_PKEY_OP_VERIFY (1<<4) -# define EVP_PKEY_OP_VERIFYRECOVER (1<<5) -# define EVP_PKEY_OP_SIGNCTX (1<<6) -# define EVP_PKEY_OP_VERIFYCTX (1<<7) -# define EVP_PKEY_OP_ENCRYPT (1<<8) -# define EVP_PKEY_OP_DECRYPT (1<<9) -# define EVP_PKEY_OP_DERIVE (1<<10) +# define EVP_PKEY_OP_PARAMFROMDATA (1<<3) +# define EVP_PKEY_OP_KEYFROMDATA (1<<4) +# define EVP_PKEY_OP_SIGN (1<<5) +# define EVP_PKEY_OP_VERIFY (1<<6) +# define EVP_PKEY_OP_VERIFYRECOVER (1<<7) +# define EVP_PKEY_OP_SIGNCTX (1<<8) +# define EVP_PKEY_OP_VERIFYCTX (1<<9) +# define EVP_PKEY_OP_ENCRYPT (1<<10) +# define EVP_PKEY_OP_DECRYPT (1<<11) +# define EVP_PKEY_OP_DERIVE (1<<12) # define EVP_PKEY_OP_TYPE_SIG \ (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER \ @@ -1395,7 +1397,10 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); (EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT | EVP_PKEY_OP_DERIVE) # define EVP_PKEY_OP_TYPE_GEN \ - (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) + (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) + +# define EVP_PKEY_OP_TYPE_FROMDATA \ + (EVP_PKEY_OP_PARAMFROMDATA | EVP_PKEY_OP_KEYFROMDATA) # define EVP_PKEY_CTX_set_mac_key(ctx, key, len) \ EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, \ @@ -1553,6 +1558,11 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen); typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx); +int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM param[]); +const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx); +const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx); int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); diff --git a/util/libcrypto.num b/util/libcrypto.num index ac28f86b25..69e245e122 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4857,3 +4857,8 @@ X509_LOOKUP_store ? 3_0_0 EXIST::FUNCTION: X509_STORE_load_file ? 3_0_0 EXIST::FUNCTION: X509_STORE_load_path ? 3_0_0 EXIST::FUNCTION: X509_STORE_load_store ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_param_fromdata_init ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_key_fromdata_init ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_fromdata ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_param_fromdata_settable ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_key_fromdata_settable ? 3_0_0 EXIST::FUNCTION: