From 9c45222ddc36124b8826d98dc0794f3eef1e5f0b Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 4 Sep 2019 12:46:02 +0100 Subject: [PATCH] Revise EVP_PKEY param handling We add new functions for getting parameters and discovering the gettable and settable parameters. We also make EVP_PKEY_CTX_get_signature_md() a function and implement it in terms of the new functions. This enables applications to discover the set of parameters that are supported for a given algorithm implementation. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9753) --- crypto/evp/evp_locl.h | 8 +- crypto/evp/exchange.c | 23 ++++-- crypto/evp/pmeth_fn.c | 41 ++++++++-- crypto/evp/pmeth_lib.c | 120 +++++++++++++++++++++++----- doc/man3/EVP_PKEY_CTX_ctrl.pod | 63 ++++++++++----- doc/man7/provider-keyexch.pod | 28 ++++--- doc/man7/provider-signature.pod | 40 ++++++---- include/openssl/core_numbers.h | 24 ++++-- include/openssl/evp.h | 8 +- providers/common/exchange/dh_exch.c | 18 ++++- providers/common/signature/dsa.c | 72 +++++++++++++++-- test/evp_extra_test.c | 114 ++++++++++++++++++++++++++ util/libcrypto.num | 4 + 13 files changed, 464 insertions(+), 99 deletions(-) diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 722eecfe43..b338823f84 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -110,7 +110,8 @@ struct evp_keyexch_st { OSSL_OP_keyexch_derive_fn *derive; OSSL_OP_keyexch_freectx_fn *freectx; OSSL_OP_keyexch_dupctx_fn *dupctx; - OSSL_OP_keyexch_set_params_fn *set_params; + OSSL_OP_keyexch_set_ctx_params_fn *set_ctx_params; + OSSL_OP_keyexch_settable_ctx_params_fn *settable_ctx_params; } /* EVP_KEYEXCH */; struct evp_signature_st { @@ -130,7 +131,10 @@ struct evp_signature_st { OSSL_OP_signature_verify_recover_fn *verify_recover; OSSL_OP_signature_freectx_fn *freectx; OSSL_OP_signature_dupctx_fn *dupctx; - OSSL_OP_signature_set_params_fn *set_params; + OSSL_OP_signature_get_ctx_params_fn *get_ctx_params; + OSSL_OP_signature_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_OP_signature_set_ctx_params_fn *set_ctx_params; + OSSL_OP_signature_settable_ctx_params_fn *settable_ctx_params; } /* EVP_SIGNATURE */; int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index e9b7259cd1..1f14a368a2 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -50,7 +50,7 @@ static void *evp_keyexch_from_dispatch(const char *name, EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name, keymgmt_data->properties); EVP_KEYEXCH *exchange = NULL; - int fncnt = 0; + int fncnt = 0, paramfncnt = 0; if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE); @@ -102,19 +102,28 @@ static void *evp_keyexch_from_dispatch(const char *name, break; exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns); break; - case OSSL_FUNC_KEYEXCH_SET_PARAMS: - if (exchange->set_params != NULL) + case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS: + if (exchange->set_ctx_params != NULL) break; - exchange->set_params = OSSL_get_OP_keyexch_set_params(fns); + exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns); + paramfncnt++; + break; + case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS: + if (exchange->settable_ctx_params != NULL) + break; + exchange->settable_ctx_params + = OSSL_get_OP_keyexch_settable_ctx_params(fns); + paramfncnt++; break; } } - if (fncnt != 4) { + if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) { /* * In order to be a consistent set of functions we must have at least * a complete set of "exchange" functions: init, derive, newctx, - * and freectx. The dupctx, set_peer and set_params functions are - * optional. + * and freectx. The set_ctx_params and settable_ctx_params functions are + * optional, but if one of them is present then the other one must also + * be present. The dupctx and set_peer functions are optional. */ EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH, EVP_R_INVALID_PROVIDER_FUNCTIONS); diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index 8fdb31c218..dfdc85f1d5 100644 --- a/crypto/evp/pmeth_fn.c +++ b/crypto/evp/pmeth_fn.c @@ -51,6 +51,7 @@ static void *evp_signature_from_dispatch(const char *name, keymgmt_data->properties); EVP_SIGNATURE *signature = NULL; int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0; + int gparamfncnt = 0, sparamfncnt = 0; if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE); @@ -123,21 +124,49 @@ static void *evp_signature_from_dispatch(const char *name, break; signature->dupctx = OSSL_get_OP_signature_dupctx(fns); break; - case OSSL_FUNC_SIGNATURE_SET_PARAMS: - if (signature->set_params != NULL) + case OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS: + if (signature->get_ctx_params != NULL) break; - signature->set_params = OSSL_get_OP_signature_set_params(fns); + signature->get_ctx_params + = OSSL_get_OP_signature_get_ctx_params(fns); + gparamfncnt++; + break; + case OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS: + if (signature->gettable_ctx_params != NULL) + break; + signature->gettable_ctx_params + = OSSL_get_OP_signature_gettable_ctx_params(fns); + gparamfncnt++; + break; + case OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS: + if (signature->set_ctx_params != NULL) + break; + signature->set_ctx_params + = OSSL_get_OP_signature_set_ctx_params(fns); + sparamfncnt++; + break; + case OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS: + if (signature->settable_ctx_params != NULL) + break; + signature->settable_ctx_params + = OSSL_get_OP_signature_settable_ctx_params(fns); + sparamfncnt++; break; } } if (ctxfncnt != 2 - || (signfncnt != 2 && verifyfncnt != 2 && verifyrecfncnt != 2)) { + || (signfncnt != 2 && verifyfncnt != 2 && verifyrecfncnt != 2) + || (gparamfncnt != 0 && gparamfncnt != 2) + || (sparamfncnt != 0 && sparamfncnt != 2)) { /* * In order to be a consistent set of functions we must have at least * a set of context functions (newctx and freectx) as well as a pair of * "signature" functions: (sign_init, sign) or (verify_init verify) or - * (verify_recover_init, verify_recover). The dupctx and set_params - * functions are optional. + * (verify_recover_init, verify_recover). set_ctx_params and + * settable_ctx_params are optional, but if one of them is present then + * the other one must also be present. The same applies to + * get_ctx_params and gettable_ctx_params. The dupctx function is + * optional. */ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); goto err; diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 534f857df1..4c98212c6a 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -404,15 +404,49 @@ void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) OPENSSL_free(ctx); } +int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) +{ + if (ctx->sigprovctx != NULL + && ctx->signature != NULL + && ctx->signature->get_ctx_params != NULL) + return ctx->signature->get_ctx_params(ctx->sigprovctx, params); + return 0; +} + +const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx) +{ + if (ctx->signature != NULL + && ctx->signature->gettable_ctx_params != NULL) + return ctx->signature->gettable_ctx_params(); + + return NULL; +} + int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) { - if (ctx->exchprovctx != NULL && ctx->exchange != NULL) - return ctx->exchange->set_params(ctx->exchprovctx, params); - if (ctx->sigprovctx != NULL && ctx->signature != NULL) - return ctx->signature->set_params(ctx->sigprovctx, params); + if (ctx->exchprovctx != NULL + && ctx->exchange != NULL + && ctx->exchange->set_ctx_params != NULL) + return ctx->exchange->set_ctx_params(ctx->exchprovctx, params); + if (ctx->sigprovctx != NULL + && ctx->signature != NULL + && ctx->signature->set_ctx_params != NULL) + return ctx->signature->set_ctx_params(ctx->sigprovctx, params); return 0; } +const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx) +{ + if (ctx->exchange != NULL + && ctx->exchange->settable_ctx_params != NULL) + return ctx->exchange->settable_ctx_params(); + if (ctx->signature != NULL + && ctx->signature->settable_ctx_params != NULL) + return ctx->signature->settable_ctx_params(); + + return NULL; +} + #ifndef OPENSSL_NO_DH int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) { @@ -431,36 +465,78 @@ int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) } #endif +int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) +{ + OSSL_PARAM sig_md_params[3], *p = sig_md_params; + /* 80 should be big enough */ + char name[80] = ""; + const EVP_MD *tmp; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->sigprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_GET_MD, 0, (void *)(md)); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, + name, + sizeof(name)); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_get_params(ctx, sig_md_params)) + return 0; + + tmp = EVP_get_digestbyname(name); + if (tmp == NULL) + return 0; + + *md = tmp; + + return 1; +} + int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { - OSSL_PARAM sig_md_params[3]; + OSSL_PARAM sig_md_params[3], *p = sig_md_params; size_t mdsize; const char *name; + if (ctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + /* TODO(3.0): Remove this eventually when no more legacy */ if (ctx->sigprovctx == NULL) return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void *)(md)); - if (md == NULL) - return 1; - - mdsize = EVP_MD_size(md); - name = EVP_MD_name(md); - sig_md_params[0] = OSSL_PARAM_construct_utf8_string( - OSSL_SIGNATURE_PARAM_DIGEST, - /* - * Cast away the const. This is read only so should - * be safe - */ - (char *)name, - strlen(name) + 1); - sig_md_params[1] = OSSL_PARAM_construct_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, - &mdsize); - sig_md_params[2] = OSSL_PARAM_construct_end(); + if (md == NULL) { + name = ""; + mdsize = 0; + } else { + mdsize = EVP_MD_size(md); + name = EVP_MD_name(md); + } - return EVP_PKEY_CTX_set_params(ctx, sig_md_params); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)name, + strlen(name) + 1); + *p++ = OSSL_PARAM_construct_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, + &mdsize); + *p++ = OSSL_PARAM_construct_end(); + return EVP_PKEY_CTX_set_params(ctx, sig_md_params); } static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod index 9d1812f6bd..18b984162e 100644 --- a/doc/man3/EVP_PKEY_CTX_ctrl.pod +++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod @@ -2,7 +2,10 @@ =head1 NAME +EVP_PKEY_CTX_get_params, +EVP_PKEY_CTX_gettable_params, EVP_PKEY_CTX_set_params, +EVP_PKEY_CTX_settable_params, EVP_PKEY_CTX_ctrl, EVP_PKEY_CTX_ctrl_str, EVP_PKEY_CTX_ctrl_uint64, @@ -63,7 +66,10 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len #include + int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params); + const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx); int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params); + const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx); int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2); @@ -144,16 +150,20 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len =head1 DESCRIPTION -The EVP_PKEY_CTX_set_params() function sends arbitrary parameters to the -algorithm implementation. +The EVP_PKEY_CTX_get_params() and EVP_PKEY_CTX_set_params() functions get and +send arbitrary parameters from and to the algorithm implementation respectively. Not all parameters may be supported by all providers. See L for more information on providers. See L for more information on parameters. +These functions must only be called after the EVP_PKEY_CTX has been initialised +for use in an operation (for example by L, +L or other similar functions). + The parameters currently supported by the default provider are: =over 4 -=item OSSL_EXCHANGE_PARAM_PAD (uint type) +=item "exchange-pad" (B) Sets the DH padding mode. If B is 1 then the shared secret is padded with zeroes @@ -161,19 +171,29 @@ up to the size of the DH prime B

. If B is zero (the default) then no padding is performed. -=item OSSL_SIGNATURE_PARAM_DIGEST (UTF8 string type) +=item "digest" (B) -Sets the name of the digest algorithm used for the input to the signature -functions. +Gets and sets the name of the digest algorithm used for the input to the +signature functions. -=item OSSL_SIGNATURE_PARAM_DIGEST_SIZE (size_t type) +=item "digest-size" (B) -Sets the output size of the digest algorithm used for the input to the signature -functions. +Gets and sets the output size of the digest algorithm used for the input to the +signature functions. The internal algorithm that supports this parameter is DSA. =back +EVP_PKEY_CTX_gettable_params() and EVP_PKEY_CTX_settable_params() gets a +constant B array that decribes the gettable and +settable parameters for the current algorithm implementation, i.e. parameters +that can be used with EVP_PKEY_CTX_get_params() and EVP_PKEY_CTX_set_params() +respectively. +See L for the use of B as parameter descriptor. +These functions must only be called after the EVP_PKEY_CTX has been initialised +for use in an operation (for example by L, +L or other similar functions). + The function EVP_PKEY_CTX_ctrl() sends a control operation to the context B. The key type used must match B if it is not -1. The parameter B is a mask indicating which operations the control can be applied to. @@ -199,13 +219,13 @@ B, B and B commands. The function EVP_PKEY_CTX_md() sends a message digest control operation to the context B. The message digest is specified by its name B. -All the remaining "functions" are implemented as macros. +The EVP_PKEY_CTX_set_signature_md() function sets the message digest type used +in a signature. It can be used in the RSA, DSA and ECDSA algorithms. -The EVP_PKEY_CTX_set_signature_md() macro sets the message digest type used +The EVP_PKEY_CTX_get_signature_md() function gets the message digest type used in a signature. It can be used in the RSA, DSA and ECDSA algorithms. -The EVP_PKEY_CTX_get_signature_md() macro gets the message digest type used in a -signature. It can be used in the RSA, DSA and ECDSA algorithms. +All the remaining "functions" are implemented as macros. Key generation typically involves setting up parameters to be used and generating the private and public key data. Some algorithm implementations @@ -471,9 +491,15 @@ allocate adequate memory space for the B before calling EVP_PKEY_CTX_get1_id =head1 RETURN VALUES -EVP_PKEY_CTX_ctrl() and its macros return a positive value 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. +EVP_PKEY_CTX_set_params() returns 1 for success or 0 otherwise. +EVP_PKEY_CTX_settable_params() returns an OSSL_PARAM array on success or NULL on +error. +It may also return NULL if there are no settable parameters available. + +EVP_PKEY_CTX_set_signature_md(), EVP_PKEY_CTX_set_dh_pad(), EVP_PKEY_CTX_ctrl() +and its macros return a positive value 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 @@ -492,8 +518,9 @@ The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len() macros were added in 1.1.1, other functions were added in OpenSSL 1.0.0. -EVP_PKEY_CTX_set_dh_pad() was a macro in OpenSSL 1.1.1 and below. -From OpenSSL 3.0 it is a function. +EVP_PKEY_CTX_get_signature_md(), EVP_PKEY_CTX_set_signature_md() and +EVP_PKEY_CTX_set_dh_pad() were macros in OpenSSL 1.1.1 and below. From OpenSSL +3.0 they are functions. =head1 COPYRIGHT diff --git a/doc/man7/provider-keyexch.pod b/doc/man7/provider-keyexch.pod index 71830c12c6..9ef294395c 100644 --- a/doc/man7/provider-keyexch.pod +++ b/doc/man7/provider-keyexch.pod @@ -29,8 +29,8 @@ provider-keyexch - The keyexch library E-E provider functions size_t outlen); /* Key Exchange parameters */ - int OP_keyexch_set_params(void *ctx, const OSSL_PARAM params[]); - + int OP_keyexch_set_ctx_params(void *ctx, const OSSL_PARAM params[]); + const OSSL_PARAM *OP_keyexch_settable_ctx_params(void); =head1 DESCRIPTION @@ -61,15 +61,16 @@ For example, the "function" OP_keyexch_newctx() has these: B arrays are indexed by numbers that are provided as macros in L, as follows: - OP_keyexch_newctx OSSL_FUNC_KEYEXCH_NEWCTX - OP_keyexch_freectx OSSL_FUNC_KEYEXCH_FREECTX - OP_keyexch_dupctx OSSL_FUNC_KEYEXCH_DUPCTX + OP_keyexch_newctx OSSL_FUNC_KEYEXCH_NEWCTX + OP_keyexch_freectx OSSL_FUNC_KEYEXCH_FREECTX + OP_keyexch_dupctx OSSL_FUNC_KEYEXCH_DUPCTX - OP_keyexch_init OSSL_FUNC_KEYEXCH_INIT - OP_keyexch_set_peer OSSL_FUNC_KEYEXCH_SET_PEER - OP_keyexch_derive OSSL_FUNC_KEYEXCH_DERIVE + OP_keyexch_init OSSL_FUNC_KEYEXCH_INIT + OP_keyexch_set_peer OSSL_FUNC_KEYEXCH_SET_PEER + OP_keyexch_derive OSSL_FUNC_KEYEXCH_DERIVE - OP_keyexch_set_params OSSL_FUNC_KEYEXCH_SET_PARAMS + OP_keyexch_set_ctx_params OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS + OP_keyexch_settable_ctx_params OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS A key exchange algorithm implementation may not implement all of these functions. In order to be a consistent set of functions a provider must implement @@ -127,8 +128,8 @@ written to B<*secretlen>. See L for further details on the parameters structure used by the OP_keyexch_set_params() function. -OP_keyexch_set_params() sets key exchange parameters associated with the given -provider side key exchange context B to B. +OP_keyexch_set_ctx_params() sets key exchange parameters associated with the +given provider side key exchange context B to B. Any parameter settings are additional to any that were previously set. Parameters currently recognised by built-in key exchange algorithms are as @@ -151,6 +152,11 @@ possible secret size. =back +OP_keyexch_settable_ctx_params() gets a constant B array that +decribes the settable parameters, i.e. parameters that can be used with +OP_signature_set_ctx_params(). +See L for the use of B as parameter descriptor. + =head1 RETURN VALUES OP_keyexch_newctx() and OP_keyexch_dupctx() should return the newly created diff --git a/doc/man7/provider-signature.pod b/doc/man7/provider-signature.pod index 3894afd03c..1ab4831035 100644 --- a/doc/man7/provider-signature.pod +++ b/doc/man7/provider-signature.pod @@ -39,8 +39,10 @@ provider-signature - The signature library E-E provider functions const unsigned char *sig, size_t siglen); /* Signature parameters */ - int OP_signature_set_params(void *ctx, const OSSL_PARAM params[]); - + int OP_signature_get_ctx_params(void *ctx, OSSL_PARAM params[]); + const OSSL_PARAM *OP_signature_gettable_ctx_params(void); + int OP_signature_set_ctx_params(void *ctx, const OSSL_PARAM params[]); + const OSSL_PARAM *OP_signature_settable_ctx_params(void); =head1 DESCRIPTION @@ -86,7 +88,10 @@ macros in L, as follows: OP_signature_verify_recover_init OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT OP_signature_verify_recover OSSL_FUNC_SIGNATURE_VERIFY_RECOVER - OP_signature_set_params OSSL_FUNC_SIGNATURE_SET_PARAMS + OP_signature_get_ctx_params OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS + OP_signature_gettable_ctx_params OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS + OP_signature_set_ctx_params OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS + OP_signature_settable_ctx_params OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS A signature algorithm implementation may not implement all of these functions. In order to be a consistent set of functions a provider must implement @@ -174,10 +179,12 @@ the B parameter. =head2 Signature Parameters See L for further details on the parameters structure used by -the OP_signature_set_params() function. +the OP_signature_get_ctx_params() and OP_signature_set_ctx_params() functions. -OP_signature_set_params() sets signature parameters associated with the given -provider side key exchange context B to B. +OP_signature_get_ctx_params() gets signature parameters associated with the +given provider side signature context B and stored them in B. +OP_signature_set_ctx_params() sets the signature parameters associated with the +given provider side signature context B to B. Any parameter settings are additional to any that were previously set. Parameters currently recognised by built-in signature algorithms are as @@ -187,27 +194,30 @@ algorithms: =over 4 -=item B (UTF8 string) +=item "digest" (B) -Sets the name of the digest algorithm used for the input to the signature +Get or sets the name of the digest algorithm used for the input to the signature functions. -=item B (size_t) +=item "digest-size" (B) -Sets the output size of the digest algorithm used for the input to the signature -functions. +Gets or sets the output size of the digest algorithm used for the input to the +signature functions. =back +OP_signature_gettable_ctx_params() and OP_signature_settable_ctx_params() get a +constant B array that decribes the gettable and settable parameters, +i.e. parameters that can be used with OP_signature_get_ctx_params() and +OP_signature_set_ctx_params() respectively. +See L for the use of B as parameter descriptor. + =head1 RETURN VALUES OP_signature_newctx() and OP_signature_dupctx() should return the newly created provider side signature, or NULL on failure. -OP_signature_sign_init(), OP_signature_sign(), OP_signature_verify_init(), -OP_signature_verify(), OP_signature_verify_recover_init(), -OP_signature_verify_recover() and OP_signature_set_params() should return 1 for -success or 0 on error. +All other functions should return 1 for success or 0 on error. =head1 SEE ALSO diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 35e6056ba1..002582012e 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -389,7 +389,8 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_exportkey_types, (void)) # define OSSL_FUNC_KEYEXCH_SET_PEER 4 # define OSSL_FUNC_KEYEXCH_FREECTX 5 # define OSSL_FUNC_KEYEXCH_DUPCTX 6 -# define OSSL_FUNC_KEYEXCH_SET_PARAMS 7 +# define OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS 7 +# define OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS 8 OSSL_CORE_MAKE_FUNC(void *, OP_keyexch_newctx, (void *provctx)) OSSL_CORE_MAKE_FUNC(int, OP_keyexch_init, (void *ctx, void *provkey)) @@ -398,8 +399,10 @@ OSSL_CORE_MAKE_FUNC(int, OP_keyexch_derive, (void *ctx, unsigned char *secret, OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_peer, (void *ctx, void *provkey)) OSSL_CORE_MAKE_FUNC(void, OP_keyexch_freectx, (void *ctx)) OSSL_CORE_MAKE_FUNC(void *, OP_keyexch_dupctx, (void *ctx)) -OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_params, (void *ctx, - const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_ctx_params, (void *ctx, + const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keyexch_settable_ctx_params, + (void)) /* Signature */ @@ -412,7 +415,10 @@ OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_params, (void *ctx, # define OSSL_FUNC_SIGNATURE_VERIFY_RECOVER 7 # define OSSL_FUNC_SIGNATURE_FREECTX 8 # define OSSL_FUNC_SIGNATURE_DUPCTX 9 -# define OSSL_FUNC_SIGNATURE_SET_PARAMS 10 +# define OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS 10 +# define OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS 11 +# define OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS 12 +# define OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS 13 OSSL_CORE_MAKE_FUNC(void *, OP_signature_newctx, (void *provctx)) OSSL_CORE_MAKE_FUNC(int, OP_signature_sign_init, (void *ctx, void *provkey)) @@ -436,8 +442,14 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover, (void *ctx, size_t siglen)) OSSL_CORE_MAKE_FUNC(void, OP_signature_freectx, (void *ctx)) OSSL_CORE_MAKE_FUNC(void *, OP_signature_dupctx, (void *ctx)) -OSSL_CORE_MAKE_FUNC(int, OP_signature_set_params, (void *ctx, - const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(int, OP_signature_get_ctx_params, + (void *ctx, OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_gettable_ctx_params, + (void)) +OSSL_CORE_MAKE_FUNC(int, OP_signature_set_ctx_params, + (void *ctx, const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_settable_ctx_params, + (void)) # ifdef __cplusplus } diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2ea8d2799f..69d70e5e9c 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1337,6 +1337,7 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth, int (*pkey_security_bits) (const EVP_PKEY *pk)); +int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md); int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); # define EVP_PKEY_OP_UNDEFINED 0 @@ -1364,10 +1365,6 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); # define EVP_PKEY_OP_TYPE_GEN \ (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) -# define EVP_PKEY_CTX_get_signature_md(ctx, pmd) \ - EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, \ - EVP_PKEY_CTRL_GET_MD, 0, (void *)(pmd)) - # define EVP_PKEY_CTX_set_mac_key(ctx, key, len) \ EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, \ EVP_PKEY_CTRL_SET_MAC_KEY, len, (void *)(key)) @@ -1427,7 +1424,10 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e); EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *ctx); void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx); +int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params); +const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx); int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params); +const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx); int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2); int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, diff --git a/providers/common/exchange/dh_exch.c b/providers/common/exchange/dh_exch.c index 5ff8318725..cfbda43fb8 100644 --- a/providers/common/exchange/dh_exch.c +++ b/providers/common/exchange/dh_exch.c @@ -20,6 +20,8 @@ static OSSL_OP_keyexch_set_peer_fn dh_set_peer; static OSSL_OP_keyexch_derive_fn dh_derive; static OSSL_OP_keyexch_freectx_fn dh_freectx; static OSSL_OP_keyexch_dupctx_fn dh_dupctx; +static OSSL_OP_keyexch_set_ctx_params_fn dh_set_ctx_params; +static OSSL_OP_keyexch_settable_ctx_params_fn dh_settable_ctx_params; /* * What's passed as an actual key is defined by the KEYMGMT interface. @@ -124,7 +126,7 @@ static void *dh_dupctx(void *vpdhctx) return dstctx; } -static int dh_set_params(void *vpdhctx, const OSSL_PARAM params[]) +static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[]) { PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; const OSSL_PARAM *p; @@ -140,6 +142,16 @@ static int dh_set_params(void *vpdhctx, const OSSL_PARAM params[]) return 1; } +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_settable_ctx_params(void) +{ + return known_settable_ctx_params; +} + const OSSL_DISPATCH dh_keyexch_functions[] = { { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx }, { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init }, @@ -147,6 +159,8 @@ const OSSL_DISPATCH dh_keyexch_functions[] = { { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer }, { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx }, { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx }, - { OSSL_FUNC_KEYEXCH_SET_PARAMS, (void (*)(void))dh_set_params }, + { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params }, + { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, + (void (*)(void))dh_settable_ctx_params }, { 0, NULL } }; diff --git a/providers/common/signature/dsa.c b/providers/common/signature/dsa.c index c0cd29381c..dc4eb6c6d4 100644 --- a/providers/common/signature/dsa.c +++ b/providers/common/signature/dsa.c @@ -20,7 +20,10 @@ static OSSL_OP_signature_verify_init_fn dsa_signature_init; static OSSL_OP_signature_sign_fn dsa_sign; static OSSL_OP_signature_freectx_fn dsa_freectx; static OSSL_OP_signature_dupctx_fn dsa_dupctx; -static OSSL_OP_signature_set_params_fn dsa_set_params; +static OSSL_OP_signature_get_ctx_params_fn dsa_get_ctx_params; +static OSSL_OP_signature_gettable_ctx_params_fn dsa_gettable_ctx_params; +static OSSL_OP_signature_set_ctx_params_fn dsa_set_ctx_params; +static OSSL_OP_signature_settable_ctx_params_fn dsa_settable_ctx_params; /* * What's passed as an actual key is defined by the KEYMGMT interface. @@ -31,6 +34,8 @@ static OSSL_OP_signature_set_params_fn dsa_set_params; typedef struct { DSA *dsa; size_t mdsize; + /* Should be big enough */ + char mdname[80]; } PROV_DSA_CTX; static void *dsa_newctx(void *provctx) @@ -116,24 +121,74 @@ static void *dsa_dupctx(void *vpdsactx) return dstctx; } -static int dsa_set_params(void *vpdsactx, const OSSL_PARAM params[]) +static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + OSSL_PARAM *p; + + if (pdsactx == NULL || params == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, pdsactx->mdsize)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->mdname)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dsa_gettable_ctx_params(void) +{ + return known_gettable_ctx_params; +} + +static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[]) { PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; const OSSL_PARAM *p; - size_t mdsize; + char *mdname; if (pdsactx == NULL || params == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); - if (p == NULL || !OSSL_PARAM_get_size_t(p, &mdsize)) + if (p != NULL && !OSSL_PARAM_get_size_t(p, &pdsactx->mdsize)) return 0; - pdsactx->mdsize = mdsize; + /* + * We never actually use the mdname, but we do support getting it later. + * This can be useful for applications that want to know the MD that they + * previously set. + */ + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + mdname = pdsactx->mdname; + if (p != NULL + && !OSSL_PARAM_get_utf8_string(p, &mdname, sizeof(pdsactx->mdname))) + return 0; return 1; } +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dsa_settable_ctx_params(void) +{ + return known_settable_ctx_params; +} + const OSSL_DISPATCH dsa_signature_functions[] = { { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx }, { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_signature_init }, @@ -142,6 +197,11 @@ const OSSL_DISPATCH dsa_signature_functions[] = { { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))dsa_verify }, { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx }, { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx }, - { OSSL_FUNC_SIGNATURE_SET_PARAMS, (void (*)(void))dsa_set_params }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))dsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))dsa_gettable_ctx_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))dsa_set_ctx_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, + (void (*)(void))dsa_settable_ctx_params }, { 0, NULL } }; diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 1ad62d2f79..7b7c632dd1 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "testutil.h" #include "internal/nelem.h" #include "internal/evp_int.h" @@ -1393,6 +1395,117 @@ static int test_EVP_CIPHER_fetch(int tst) return ret; } +/* Test getting and setting parameters on an EVP_PKEY_CTX */ +static int test_EVP_PKEY_CTX_get_set_params(void) +{ + EVP_PKEY_CTX *ctx = NULL; + EVP_SIGNATURE *dsaimpl = NULL; + const OSSL_PARAM *params; + OSSL_PARAM ourparams[2], *param = ourparams; + DSA *dsa = NULL; + BIGNUM *p = NULL, *q = NULL, *g = NULL; + EVP_PKEY *pkey = NULL; + int ret = 0; + const EVP_MD *md; + size_t mdsize = SHA512_DIGEST_LENGTH; + + /* + * Setup the parameters for our DSA object. For our purposes they don't have + * to actually be *valid* parameters. We just need to set something. We + * don't even need a pub_key/priv_key. + */ + dsa = DSA_new(); + p = BN_new(); + q = BN_new(); + g = BN_new(); + if (!TEST_ptr(dsa) + || !TEST_ptr(p) + || !TEST_ptr(q) + || !TEST_ptr(g) + || !DSA_set0_pqg(dsa, p, q, g)) + goto err; + p = q = g = NULL; + + pkey = EVP_PKEY_new(); + if (!TEST_ptr(pkey) + || !TEST_true(EVP_PKEY_assign_DSA(pkey, dsa))) + goto err; + + dsa = NULL; + + /* Initialise a sign operation */ + ctx = EVP_PKEY_CTX_new(pkey, NULL); + dsaimpl = EVP_SIGNATURE_fetch(NULL, "DSA", NULL); + if (!TEST_ptr(ctx) + || !TEST_ptr(dsaimpl) + || !TEST_int_gt(EVP_PKEY_sign_init_ex(ctx, dsaimpl), 0)) + goto err; + + /* + * We should be able to query the parameters now. The default DSA + * implementation supports exactly one parameter - so we expect to see that + * returned and no more. + */ + params = EVP_PKEY_CTX_settable_params(ctx); + if (!TEST_ptr(params) + || !TEST_int_eq(strcmp(params[0].key, + OSSL_SIGNATURE_PARAM_DIGEST_SIZE), 0) + || !TEST_int_eq(strcmp(params[1].key, OSSL_SIGNATURE_PARAM_DIGEST), + 0) + /* The final key should be NULL */ + || !TEST_ptr_null(params[2].key)) + goto err; + + /* Gettable params are the same as the settable ones */ + params = EVP_PKEY_CTX_gettable_params(ctx); + if (!TEST_ptr(params) + || !TEST_int_eq(strcmp(params[0].key, + OSSL_SIGNATURE_PARAM_DIGEST_SIZE), 0) + || !TEST_int_eq(strcmp(params[1].key, OSSL_SIGNATURE_PARAM_DIGEST), + 0) + /* The final key should be NULL */ + || !TEST_ptr_null(params[2].key)) + goto err; + + /* + * Test getting and setting params via EVP_PKEY_CTX_set_params() and + * EVP_PKEY_CTX_get_params() + */ + *param++ = OSSL_PARAM_construct_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, + &mdsize); + *param++ = OSSL_PARAM_construct_end(); + + if (!TEST_true(EVP_PKEY_CTX_set_params(ctx, ourparams))) + goto err; + + mdsize = 0; + if (!TEST_true(EVP_PKEY_CTX_get_params(ctx, ourparams)) + || !TEST_size_t_eq(mdsize, SHA512_DIGEST_LENGTH)) + goto err; + + /* + * Test the TEST_PKEY_CTX_set_signature_md() and + * TEST_PKEY_CTX_get_signature_md() functions + */ + if (!TEST_int_gt(EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()), 0) + || !TEST_int_gt(EVP_PKEY_CTX_get_signature_md(ctx, &md), 0) + || !TEST_ptr_eq(md, EVP_sha256())) + goto err; + + ret = 1; + + err: + EVP_PKEY_CTX_free(ctx); + EVP_SIGNATURE_free(dsaimpl); + EVP_PKEY_free(pkey); + DSA_free(dsa); + BN_free(p); + BN_free(q); + BN_free(g); + + return ret; +} + int setup_tests(void) { ADD_TEST(test_EVP_DigestSignInit); @@ -1429,5 +1542,6 @@ int setup_tests(void) ADD_ALL_TESTS(test_EVP_MD_fetch, 5); ADD_ALL_TESTS(test_EVP_CIPHER_fetch, 5); #endif + ADD_TEST(test_EVP_PKEY_CTX_get_set_params); return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index a1a36f1f77..e5c869af44 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4748,3 +4748,7 @@ EVP_PKEY_sign_init_ex 4864 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_set_signature_md 4865 3_0_0 EXIST::FUNCTION: EVP_PKEY_verify_init_ex 4866 3_0_0 EXIST::FUNCTION: EVP_PKEY_verify_recover_init_ex 4867 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_get_signature_md 4868 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_get_params 4869 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_gettable_params 4870 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_settable_params 4871 3_0_0 EXIST::FUNCTION: -- 2.39.5