X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fpmeth_lib.c;h=e5975081e1362da1fee6a23e39261ab8af5612e9;hp=f4bc49fe0fb86d53be555283742849701de59676;hb=4d4de19e9c77f36cc5ab71df77a6eb1253031d4c;hpb=4fe54d674f14e7964f982285d1aeb86698a33c3c diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index f4bc49fe0f..e5975081e1 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -1,6 +1,5 @@ - /* - * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2021 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 @@ -8,22 +7,43 @@ * https://www.openssl.org/source/license.html */ +/* + * Low level key APIs (DH etc) are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include #include -#include +#ifndef FIPS_MODULE +# include +#endif #include -#include #include #include #include +#include #include "internal/cryptlib.h" -#include "crypto/asn1.h" +#ifndef FIPS_MODULE +# include "crypto/asn1.h" +#endif #include "crypto/evp.h" +#include "crypto/dh.h" +#include "crypto/ec.h" +#include "internal/ffc.h" #include "internal/numbers.h" #include "internal/provider.h" #include "evp_local.h" -#ifndef FIPS_MODE +#ifndef FIPS_MODULE + +static int evp_pkey_ctx_store_cached_data(EVP_PKEY_CTX *ctx, + int keytype, int optype, + int cmd, const char *name, + const void *data, size_t data_len); +static void evp_pkey_ctx_free_cached_data(EVP_PKEY_CTX *ctx, + int cmd, const char *name); +static void evp_pkey_ctx_free_all_cached_data(EVP_PKEY_CTX *ctx); typedef const EVP_PKEY_METHOD *(*pmeth_fn)(void); typedef int sk_cmp_fn_type(const char *const *a, const char *const *b); @@ -32,49 +52,27 @@ static STACK_OF(EVP_PKEY_METHOD) *app_pkey_methods = NULL; /* This array needs to be in order of NIDs */ static pmeth_fn standard_methods[] = { -# ifndef OPENSSL_NO_RSA - rsa_pkey_method, -# endif + ossl_rsa_pkey_method, # ifndef OPENSSL_NO_DH - dh_pkey_method, + ossl_dh_pkey_method, # endif # ifndef OPENSSL_NO_DSA - dsa_pkey_method, + ossl_dsa_pkey_method, # endif # ifndef OPENSSL_NO_EC - ec_pkey_method, -# endif - hmac_pkey_method, -# ifndef OPENSSL_NO_CMAC - cmac_pkey_method, -# endif -# ifndef OPENSSL_NO_RSA - rsa_pss_pkey_method, + ossl_ec_pkey_method, # endif + ossl_rsa_pss_pkey_method, # ifndef OPENSSL_NO_DH - dhx_pkey_method, -# endif -# ifndef OPENSSL_NO_SCRYPT - scrypt_pkey_method, + ossl_dhx_pkey_method, # endif - tls1_prf_pkey_method, # ifndef OPENSSL_NO_EC - ecx25519_pkey_method, - ecx448_pkey_method, -# endif - hkdf_pkey_method, -# ifndef OPENSSL_NO_POLY1305 - poly1305_pkey_method, -# endif -# ifndef OPENSSL_NO_SIPHASH - siphash_pkey_method, + ossl_ecx25519_pkey_method, + ossl_ecx448_pkey_method, # endif # ifndef OPENSSL_NO_EC - ed25519_pkey_method, - ed448_pkey_method, -# endif -# ifndef OPENSSL_NO_SM2 - sm2_pkey_method, + ossl_ed25519_pkey_method, + ossl_ed448_pkey_method, # endif }; @@ -93,22 +91,33 @@ static int pmeth_cmp(const EVP_PKEY_METHOD *const *a, return ((*a)->pkey_id - (*b)->pkey_id); } -const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type) +static const EVP_PKEY_METHOD *evp_pkey_meth_find_added_by_application(int type) { - pmeth_fn *ret; - EVP_PKEY_METHOD tmp; - const EVP_PKEY_METHOD *t = &tmp; - - tmp.pkey_id = type; - if (app_pkey_methods) { + if (app_pkey_methods != NULL) { int idx; + EVP_PKEY_METHOD tmp; + + tmp.pkey_id = type; idx = sk_EVP_PKEY_METHOD_find(app_pkey_methods, &tmp); if (idx >= 0) return sk_EVP_PKEY_METHOD_value(app_pkey_methods, idx); } + return NULL; +} + +const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type) +{ + pmeth_fn *ret; + EVP_PKEY_METHOD tmp; + const EVP_PKEY_METHOD *t; + + if ((t = evp_pkey_meth_find_added_by_application(type)) != NULL) + return t; + + tmp.pkey_id = type; + t = &tmp; ret = OBJ_bsearch_pmeth_func(&t, standard_methods, - sizeof(standard_methods) / - sizeof(pmeth_fn)); + OSSL_NELEM(standard_methods)); if (ret == NULL || *ret == NULL) return NULL; return (**ret)(); @@ -120,7 +129,7 @@ EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags) pmeth = OPENSSL_zalloc(sizeof(*pmeth)); if (pmeth == NULL) { - EVPerr(EVP_F_EVP_PKEY_METH_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); return NULL; } @@ -128,72 +137,108 @@ EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags) pmeth->flags = flags | EVP_PKEY_FLAG_DYNAMIC; return pmeth; } -#endif /* FIPS_MODE */ -static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, +static void help_get_legacy_alg_type_from_keymgmt(const char *keytype, + void *arg) +{ + int *type = arg; + + if (*type == NID_undef) + *type = evp_pkey_name2type(keytype); +} + +static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt) +{ + int type = NID_undef; + + EVP_KEYMGMT_names_do_all(keymgmt, help_get_legacy_alg_type_from_keymgmt, + &type); + return type; +} +#endif /* FIPS_MODULE */ + +int evp_pkey_ctx_state(const EVP_PKEY_CTX *ctx) +{ + if (ctx->operation == EVP_PKEY_OP_UNDEFINED) + return EVP_PKEY_STATE_UNKNOWN; + + if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) + && ctx->op.kex.algctx != NULL) + || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) + && ctx->op.sig.algctx != NULL) + || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.algctx != NULL) + || (EVP_PKEY_CTX_IS_GEN_OP(ctx) + && ctx->op.keymgmt.genctx != NULL) + || (EVP_PKEY_CTX_IS_KEM_OP(ctx) + && ctx->op.encap.algctx != NULL)) + return EVP_PKEY_STATE_PROVIDER; + + return EVP_PKEY_STATE_LEGACY; +} + +static EVP_PKEY_CTX *int_ctx_new(OSSL_LIB_CTX *libctx, EVP_PKEY *pkey, ENGINE *e, - const char *name, const char *propquery, + const char *keytype, const char *propquery, int id) { - EVP_PKEY_CTX *ret; - const EVP_PKEY_METHOD *pmeth = NULL; + EVP_PKEY_CTX *ret = NULL; + const EVP_PKEY_METHOD *pmeth = NULL, *app_pmeth = NULL; + EVP_KEYMGMT *keymgmt = NULL; - /* - * When using providers, the context is bound to the algo implementation - * later. - */ - if (pkey == NULL && e == NULL && id == -1) - goto common; - - /* - * If the key doesn't contain anything legacy, then it must be provided, - * so we extract the necessary information and use that. - */ - if (pkey != NULL && pkey->ameth == NULL) { - /* If we have an engine, something went wrong somewhere... */ - if (!ossl_assert(e == NULL)) - return NULL; - name = evp_first_name(pkey->pkeys[0].keymgmt->prov, - pkey->pkeys[0].keymgmt->name_id); - /* - * TODO: I wonder if the EVP_PKEY should have the name and propquery - * that were used when building it.... /RL - */ - goto common; - } -#ifndef FIPS_MODE - /* TODO(3.0) Legacy code should be removed when all is provider based */ + /* Code below to be removed when legacy support is dropped. */ /* BEGIN legacy */ if (id == -1) { - if (pkey == NULL) + if (pkey != NULL && !evp_pkey_is_provided(pkey)) { + id = pkey->type; + } else { + if (pkey != NULL) { + /* Must be provided if we get here */ + keytype = EVP_KEYMGMT_get0_name(pkey->keymgmt); + } +#ifndef FIPS_MODULE + if (keytype != NULL) { + id = evp_pkey_name2type(keytype); + if (id == NID_undef) + id = -1; + } +#endif + } + } + /* If no ID was found here, we can only resort to find a keymgmt */ + if (id == -1) { +#ifndef FIPS_MODULE + /* Using engine with a key without id will not work */ + if (e != NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_ALGORITHM); return NULL; - id = pkey->type; + } +#endif + goto common; } +#ifndef FIPS_MODULE /* * Here, we extract what information we can for the purpose of * supporting usage with implementations from providers, to make * for a smooth transition from legacy stuff to provider based stuff. * * If an engine is given, this is entirely legacy, and we should not - * pretend anything else, so we only set the name when no engine is - * given. If both are already given, someone made a mistake, and - * since that can only happen internally, it's safe to make an - * assertion. + * pretend anything else, so we clear the name. */ - if (!ossl_assert(e == NULL || name == NULL)) - return NULL; - if (e == NULL) - name = OBJ_nid2sn(id); + if (e != NULL) + keytype = NULL; + if (e == NULL && (pkey == NULL || pkey->foreign == 0)) + keytype = OBJ_nid2sn(id); # ifndef OPENSSL_NO_ENGINE if (e == NULL && pkey != NULL) e = pkey->pmeth_engine != NULL ? pkey->pmeth_engine : pkey->engine; /* Try to find an ENGINE which implements this method */ - if (e) { + if (e != NULL) { if (!ENGINE_init(e)) { - EVPerr(EVP_F_INT_CTX_NEW, ERR_R_ENGINE_LIB); + ERR_raise(ERR_LIB_EVP, ERR_R_ENGINE_LIB); return NULL; } } else { @@ -204,33 +249,85 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, * If an ENGINE handled this method look it up. Otherwise use internal * tables. */ - if (e) + if (e != NULL) pmeth = ENGINE_get_pkey_meth(e, id); + else if (pkey != NULL && pkey->foreign) + pmeth = EVP_PKEY_meth_find(id); else # endif - pmeth = EVP_PKEY_meth_find(id); + app_pmeth = pmeth = evp_pkey_meth_find_added_by_application(id); - if (pmeth == NULL) { -# ifndef OPENSSL_NO_ENGINE - ENGINE_finish(e); -# endif - EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM); - return NULL; - } /* END legacy */ -#endif /* FIPS_MODE */ +#endif /* FIPS_MODULE */ common: - ret = OPENSSL_zalloc(sizeof(*ret)); - if (ret == NULL) { -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) + /* + * If there's no engine and no app supplied pmeth and there's a name, we try + * fetching a provider implementation. + */ + if (e == NULL && app_pmeth == NULL && keytype != NULL) { + keymgmt = EVP_KEYMGMT_fetch(libctx, keytype, propquery); + if (keymgmt == NULL) + return NULL; /* EVP_KEYMGMT_fetch() recorded an error */ + +#ifndef FIPS_MODULE + /* + * Chase down the legacy NID, as that might be needed for diverse + * purposes, such as ensure that EVP_PKEY_type() can return sensible + * values. We go through all keymgmt names, because the keytype + * that's passed to this function doesn't necessarily translate + * directly. + */ + if (keymgmt != NULL) { + int tmp_id = get_legacy_alg_type_from_keymgmt(keymgmt); + + if (tmp_id != NID_undef) { + if (id == -1) { + id = tmp_id; + } else { + /* + * It really really shouldn't differ. If it still does, + * something is very wrong. + */ + if (!ossl_assert(id == tmp_id)) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + EVP_KEYMGMT_free(keymgmt); + return NULL; + } + } + } + } +#endif + } + + if (pmeth == NULL && keymgmt == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_ALGORITHM); + } else { + ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret == NULL) + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + } + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if ((ret == NULL || pmeth == NULL) && e != NULL) ENGINE_finish(e); #endif - EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE); + + if (ret == NULL) { + EVP_KEYMGMT_free(keymgmt); return NULL; } + if (propquery != NULL) { + ret->propquery = OPENSSL_strdup(propquery); + if (ret->propquery == NULL) { + OPENSSL_free(ret); + EVP_KEYMGMT_free(keymgmt); + return NULL; + } + } ret->libctx = libctx; - ret->keytype = name; - ret->propquery = propquery; + ret->keytype = keytype; + ret->keymgmt = keymgmt; + ret->legacy_keytype = id; ret->engine = e; ret->pmeth = pmeth; ret->operation = EVP_PKEY_OP_UNDEFINED; @@ -249,16 +346,16 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, return ret; } -/*- All methods below can also be used in FIPS_MODE */ +/*- All methods below can also be used in FIPS_MODULE */ -EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_name(OPENSSL_CTX *libctx, +EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_name(OSSL_LIB_CTX *libctx, const char *name, const char *propquery) { return int_ctx_new(libctx, NULL, NULL, name, propquery, -1); } -EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_pkey(OPENSSL_CTX *libctx, EVP_PKEY *pkey, +EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_pkey(OSSL_LIB_CTX *libctx, EVP_PKEY *pkey, const char *propquery) { return int_ctx_new(libctx, pkey, NULL, NULL, propquery, -1); @@ -267,28 +364,34 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_pkey(OPENSSL_CTX *libctx, EVP_PKEY *pkey, void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx) { if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)) { - if (ctx->op.sig.sigprovctx != NULL && ctx->op.sig.signature != NULL) - ctx->op.sig.signature->freectx(ctx->op.sig.sigprovctx); + if (ctx->op.sig.algctx != NULL && ctx->op.sig.signature != NULL) + ctx->op.sig.signature->freectx(ctx->op.sig.algctx); EVP_SIGNATURE_free(ctx->op.sig.signature); - ctx->op.sig.sigprovctx = NULL; + ctx->op.sig.algctx = NULL; ctx->op.sig.signature = NULL; } else if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { - if (ctx->op.kex.exchprovctx != NULL && ctx->op.kex.exchange != NULL) - ctx->op.kex.exchange->freectx(ctx->op.kex.exchprovctx); + if (ctx->op.kex.algctx != NULL && ctx->op.kex.exchange != NULL) + ctx->op.kex.exchange->freectx(ctx->op.kex.algctx); EVP_KEYEXCH_free(ctx->op.kex.exchange); - ctx->op.kex.exchprovctx = NULL; + ctx->op.kex.algctx = NULL; ctx->op.kex.exchange = NULL; + } else if (EVP_PKEY_CTX_IS_KEM_OP(ctx)) { + if (ctx->op.encap.algctx != NULL && ctx->op.encap.kem != NULL) + ctx->op.encap.kem->freectx(ctx->op.encap.algctx); + EVP_KEM_free(ctx->op.encap.kem); + ctx->op.encap.algctx = NULL; + ctx->op.encap.kem = NULL; } -/* TODO(3.0): add dependancies and uncomment this when available for fips mode */ -#ifndef FIPS_MODE else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { - if (ctx->op.ciph.ciphprovctx != NULL && ctx->op.ciph.cipher != NULL) - ctx->op.ciph.cipher->freectx(ctx->op.ciph.ciphprovctx); + if (ctx->op.ciph.algctx != NULL && ctx->op.ciph.cipher != NULL) + ctx->op.ciph.cipher->freectx(ctx->op.ciph.algctx); EVP_ASYM_CIPHER_free(ctx->op.ciph.cipher); - ctx->op.ciph.ciphprovctx = NULL; + ctx->op.ciph.algctx = NULL; ctx->op.ciph.cipher = NULL; + } else if (EVP_PKEY_CTX_IS_GEN_OP(ctx)) { + if (ctx->op.keymgmt.genctx != NULL && ctx->keymgmt != NULL) + evp_keymgmt_gen_cleanup(ctx->keymgmt, ctx->op.keymgmt.genctx); } -#endif } void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) @@ -299,17 +402,22 @@ void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) ctx->pmeth->cleanup(ctx); evp_pkey_ctx_free_old_ops(ctx); +#ifndef FIPS_MODULE + evp_pkey_ctx_free_all_cached_data(ctx); +#endif EVP_KEYMGMT_free(ctx->keymgmt); + OPENSSL_free(ctx->propquery); EVP_PKEY_free(ctx->pkey); EVP_PKEY_free(ctx->peerkey); -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) ENGINE_finish(ctx->engine); #endif + BN_free(ctx->rsa_pubexp); OPENSSL_free(ctx); } -#ifndef FIPS_MODE +#ifndef FIPS_MODULE void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags, const EVP_PKEY_METHOD *meth) @@ -322,45 +430,14 @@ void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags, void EVP_PKEY_meth_copy(EVP_PKEY_METHOD *dst, const EVP_PKEY_METHOD *src) { + int pkey_id = dst->pkey_id; + int flags = dst->flags; - dst->init = src->init; - dst->copy = src->copy; - dst->cleanup = src->cleanup; - - dst->paramgen_init = src->paramgen_init; - dst->paramgen = src->paramgen; - - dst->keygen_init = src->keygen_init; - dst->keygen = src->keygen; + *dst = *src; - dst->sign_init = src->sign_init; - dst->sign = src->sign; - - dst->verify_init = src->verify_init; - dst->verify = src->verify; - - dst->verify_recover_init = src->verify_recover_init; - dst->verify_recover = src->verify_recover; - - dst->signctx_init = src->signctx_init; - dst->signctx = src->signctx; - - dst->verifyctx_init = src->verifyctx_init; - dst->verifyctx = src->verifyctx; - - dst->encrypt_init = src->encrypt_init; - dst->encrypt = src->encrypt; - - dst->decrypt_init = src->decrypt_init; - dst->decrypt = src->decrypt; - - dst->derive_init = src->derive_init; - dst->derive = src->derive; - - dst->ctrl = src->ctrl; - dst->ctrl_str = src->ctrl_str; - - dst->check = src->check; + /* We only copy the function pointers so restore the other values */ + dst->pkey_id = pkey_id; + dst->flags = flags; } void EVP_PKEY_meth_free(EVP_PKEY_METHOD *pmeth) @@ -383,22 +460,16 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) { EVP_PKEY_CTX *rctx; - if (((pctx->pmeth == NULL) || (pctx->pmeth->copy == NULL)) - && ((EVP_PKEY_CTX_IS_DERIVE_OP(pctx) - && pctx->op.kex.exchprovctx == NULL) - || (EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx) - && pctx->op.sig.sigprovctx == NULL))) - return NULL; # ifndef OPENSSL_NO_ENGINE /* Make sure it's safe to copy a pkey context using an ENGINE */ if (pctx->engine && !ENGINE_init(pctx->engine)) { - EVPerr(EVP_F_EVP_PKEY_CTX_DUP, ERR_R_ENGINE_LIB); + ERR_raise(ERR_LIB_EVP, ERR_R_ENGINE_LIB); return 0; } # endif rctx = OPENSSL_zalloc(sizeof(*rctx)); if (rctx == NULL) { - EVPerr(EVP_F_EVP_PKEY_CTX_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); return NULL; } @@ -408,68 +479,85 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) rctx->operation = pctx->operation; rctx->libctx = pctx->libctx; rctx->keytype = pctx->keytype; - rctx->propquery = pctx->propquery; + rctx->propquery = NULL; + if (pctx->propquery != NULL) { + rctx->propquery = OPENSSL_strdup(pctx->propquery); + if (rctx->propquery == NULL) + goto err; + } + rctx->legacy_keytype = pctx->legacy_keytype; if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) { if (pctx->op.kex.exchange != NULL) { rctx->op.kex.exchange = pctx->op.kex.exchange; - if (!EVP_KEYEXCH_up_ref(rctx->op.kex.exchange)) { - OPENSSL_free(rctx); - return NULL; - } + if (!EVP_KEYEXCH_up_ref(rctx->op.kex.exchange)) + goto err; } - if (pctx->op.kex.exchprovctx != NULL) { + if (pctx->op.kex.algctx != NULL) { if (!ossl_assert(pctx->op.kex.exchange != NULL)) - return NULL; - rctx->op.kex.exchprovctx - = pctx->op.kex.exchange->dupctx(pctx->op.kex.exchprovctx); - if (rctx->op.kex.exchprovctx == NULL) { + goto err; + rctx->op.kex.algctx + = pctx->op.kex.exchange->dupctx(pctx->op.kex.algctx); + if (rctx->op.kex.algctx == NULL) { EVP_KEYEXCH_free(rctx->op.kex.exchange); - OPENSSL_free(rctx); - return NULL; + goto err; } return rctx; } } else if (EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx)) { if (pctx->op.sig.signature != NULL) { rctx->op.sig.signature = pctx->op.sig.signature; - if (!EVP_SIGNATURE_up_ref(rctx->op.sig.signature)) { - OPENSSL_free(rctx); - return NULL; - } + if (!EVP_SIGNATURE_up_ref(rctx->op.sig.signature)) + goto err; } - if (pctx->op.sig.sigprovctx != NULL) { + if (pctx->op.sig.algctx != NULL) { if (!ossl_assert(pctx->op.sig.signature != NULL)) - return NULL; - rctx->op.sig.sigprovctx - = pctx->op.sig.signature->dupctx(pctx->op.sig.sigprovctx); - if (rctx->op.sig.sigprovctx == NULL) { + goto err; + rctx->op.sig.algctx + = pctx->op.sig.signature->dupctx(pctx->op.sig.algctx); + if (rctx->op.sig.algctx == NULL) { EVP_SIGNATURE_free(rctx->op.sig.signature); - OPENSSL_free(rctx); - return NULL; + goto err; } return rctx; } } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(pctx)) { if (pctx->op.ciph.cipher != NULL) { rctx->op.ciph.cipher = pctx->op.ciph.cipher; - if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher)) { - OPENSSL_free(rctx); - return NULL; - } + if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher)) + goto err; } - if (pctx->op.ciph.ciphprovctx != NULL) { + if (pctx->op.ciph.algctx != NULL) { if (!ossl_assert(pctx->op.ciph.cipher != NULL)) - return NULL; - rctx->op.ciph.ciphprovctx - = pctx->op.ciph.cipher->dupctx(pctx->op.ciph.ciphprovctx); - if (rctx->op.ciph.ciphprovctx == NULL) { + goto err; + rctx->op.ciph.algctx + = pctx->op.ciph.cipher->dupctx(pctx->op.ciph.algctx); + if (rctx->op.ciph.algctx == NULL) { EVP_ASYM_CIPHER_free(rctx->op.ciph.cipher); - OPENSSL_free(rctx); - return NULL; + goto err; } return rctx; } + } else if (EVP_PKEY_CTX_IS_KEM_OP(pctx)) { + if (pctx->op.encap.kem != NULL) { + rctx->op.encap.kem = pctx->op.encap.kem; + if (!EVP_KEM_up_ref(rctx->op.encap.kem)) + goto err; + } + if (pctx->op.encap.algctx != NULL) { + if (!ossl_assert(pctx->op.encap.kem != NULL)) + goto err; + rctx->op.encap.algctx + = pctx->op.encap.kem->dupctx(pctx->op.encap.algctx); + if (rctx->op.encap.algctx == NULL) { + EVP_KEM_free(rctx->op.encap.kem); + goto err; + } + return rctx; + } + } else if (EVP_PKEY_CTX_IS_GEN_OP(pctx)) { + /* Not supported - This would need a gen_dupctx() to work */ + goto err; } rctx->pmeth = pctx->pmeth; @@ -477,17 +565,32 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) rctx->engine = pctx->engine; # endif - if (pctx->peerkey) + if (pctx->peerkey != NULL) EVP_PKEY_up_ref(pctx->peerkey); rctx->peerkey = pctx->peerkey; - if (pctx->pmeth->copy(rctx, pctx) > 0) + if (pctx->pmeth == NULL) { + if (rctx->operation == EVP_PKEY_OP_UNDEFINED) { + EVP_KEYMGMT *tmp_keymgmt = pctx->keymgmt; + void *provkey; + + provkey = evp_pkey_export_to_provider(pctx->pkey, pctx->libctx, + &tmp_keymgmt, pctx->propquery); + if (provkey == NULL) + goto err; + if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) + goto err; + EVP_KEYMGMT_free(rctx->keymgmt); + rctx->keymgmt = tmp_keymgmt; + return rctx; + } + } else if (pctx->pmeth->copy(rctx, pctx) > 0) { return rctx; - + } +err: rctx->pmeth = NULL; EVP_PKEY_CTX_free(rctx); return NULL; - } int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth) @@ -495,12 +598,12 @@ int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth) if (app_pkey_methods == NULL) { app_pkey_methods = sk_EVP_PKEY_METHOD_new(pmeth_cmp); if (app_pkey_methods == NULL){ - EVPerr(EVP_F_EVP_PKEY_METH_ADD0, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); return 0; } } if (!sk_EVP_PKEY_METHOD_push(app_pkey_methods, pmeth)) { - EVPerr(EVP_F_EVP_PKEY_METH_ADD0, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); return 0; } sk_EVP_PKEY_METHOD_sort(app_pkey_methods); @@ -544,87 +647,176 @@ const EVP_PKEY_METHOD *EVP_PKEY_meth_get0(size_t idx) } #endif -int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) +int EVP_PKEY_CTX_is_a(EVP_PKEY_CTX *ctx, const char *keytype) { - if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) - && ctx->op.kex.exchprovctx != NULL +#ifndef FIPS_MODULE + if (evp_pkey_ctx_is_legacy(ctx)) + return (ctx->pmeth->pkey_id == evp_pkey_name2type(keytype)); +#endif + return EVP_KEYMGMT_is_a(ctx->keymgmt, keytype); +} + +int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, const OSSL_PARAM *params) +{ + switch (evp_pkey_ctx_state(ctx)) { + case EVP_PKEY_STATE_PROVIDER: + if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchange != NULL && ctx->op.kex.exchange->set_ctx_params != NULL) - return ctx->op.kex.exchange->set_ctx_params(ctx->op.kex.exchprovctx, - params); - if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL + return + ctx->op.kex.exchange->set_ctx_params(ctx->op.kex.algctx, + params); + if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) && ctx->op.sig.signature != NULL && ctx->op.sig.signature->set_ctx_params != NULL) - return ctx->op.sig.signature->set_ctx_params(ctx->op.sig.sigprovctx, - params); - if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) - && ctx->op.ciph.ciphprovctx != NULL + return + ctx->op.sig.signature->set_ctx_params(ctx->op.sig.algctx, + params); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) && ctx->op.ciph.cipher != NULL && ctx->op.ciph.cipher->set_ctx_params != NULL) - return ctx->op.ciph.cipher->set_ctx_params(ctx->op.ciph.ciphprovctx, - params); + return + ctx->op.ciph.cipher->set_ctx_params(ctx->op.ciph.algctx, + params); + if (EVP_PKEY_CTX_IS_GEN_OP(ctx) + && ctx->keymgmt != NULL + && ctx->keymgmt->gen_set_params != NULL) + return + evp_keymgmt_gen_set_params(ctx->keymgmt, ctx->op.keymgmt.genctx, + params); + if (EVP_PKEY_CTX_IS_KEM_OP(ctx) + && ctx->op.encap.kem != NULL + && ctx->op.encap.kem->set_ctx_params != NULL) + return + ctx->op.encap.kem->set_ctx_params(ctx->op.encap.algctx, + params); + break; +#ifndef FIPS_MODULE + case EVP_PKEY_STATE_UNKNOWN: + case EVP_PKEY_STATE_LEGACY: + return evp_pkey_ctx_set_params_to_ctrl(ctx, params); +#endif + } return 0; } -#ifndef FIPS_MODE int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) { - if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) - && ctx->op.kex.exchprovctx != NULL + switch (evp_pkey_ctx_state(ctx)) { + case EVP_PKEY_STATE_PROVIDER: + if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchange != NULL && ctx->op.kex.exchange->get_ctx_params != NULL) - return ctx->op.kex.exchange->get_ctx_params(ctx->op.kex.exchprovctx, - params); - if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL + return + ctx->op.kex.exchange->get_ctx_params(ctx->op.kex.algctx, + params); + if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) && ctx->op.sig.signature != NULL && ctx->op.sig.signature->get_ctx_params != NULL) - return ctx->op.sig.signature->get_ctx_params(ctx->op.sig.sigprovctx, - params); - if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) - && ctx->op.ciph.ciphprovctx != NULL + return + ctx->op.sig.signature->get_ctx_params(ctx->op.sig.algctx, + params); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) && ctx->op.ciph.cipher != NULL && ctx->op.ciph.cipher->get_ctx_params != NULL) - return ctx->op.ciph.cipher->get_ctx_params(ctx->op.ciph.ciphprovctx, - params); + return + ctx->op.ciph.cipher->get_ctx_params(ctx->op.ciph.algctx, + params); + if (EVP_PKEY_CTX_IS_KEM_OP(ctx) + && ctx->op.encap.kem != NULL + && ctx->op.encap.kem->get_ctx_params != NULL) + return + ctx->op.encap.kem->get_ctx_params(ctx->op.encap.algctx, + params); + break; +#ifndef FIPS_MODULE + case EVP_PKEY_STATE_UNKNOWN: + case EVP_PKEY_STATE_LEGACY: + return evp_pkey_ctx_get_params_to_ctrl(ctx, params); +#endif + } return 0; } -const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx) +#ifndef FIPS_MODULE +const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(const EVP_PKEY_CTX *ctx) { + void *provctx; + if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchange != NULL - && ctx->op.kex.exchange->gettable_ctx_params != NULL) - return ctx->op.kex.exchange->gettable_ctx_params(); + && ctx->op.kex.exchange->gettable_ctx_params != NULL) { + provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(ctx->op.kex.exchange)); + return ctx->op.kex.exchange->gettable_ctx_params(ctx->op.kex.algctx, + provctx); + } if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) && ctx->op.sig.signature != NULL - && ctx->op.sig.signature->gettable_ctx_params != NULL) - return ctx->op.sig.signature->gettable_ctx_params(); - + && ctx->op.sig.signature->gettable_ctx_params != NULL) { + provctx = ossl_provider_ctx( + EVP_SIGNATURE_get0_provider(ctx->op.sig.signature)); + return ctx->op.sig.signature->gettable_ctx_params(ctx->op.sig.algctx, + provctx); + } if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) && ctx->op.ciph.cipher != NULL - && ctx->op.ciph.cipher->gettable_ctx_params != NULL) - return ctx->op.ciph.cipher->gettable_ctx_params(); - + && ctx->op.ciph.cipher->gettable_ctx_params != NULL) { + provctx = ossl_provider_ctx( + EVP_ASYM_CIPHER_get0_provider(ctx->op.ciph.cipher)); + return ctx->op.ciph.cipher->gettable_ctx_params(ctx->op.ciph.algctx, + provctx); + } + if (EVP_PKEY_CTX_IS_KEM_OP(ctx) + && ctx->op.encap.kem != NULL + && ctx->op.encap.kem->gettable_ctx_params != NULL) { + provctx = ossl_provider_ctx(EVP_KEM_get0_provider(ctx->op.encap.kem)); + return ctx->op.encap.kem->gettable_ctx_params(ctx->op.encap.algctx, + provctx); + } return NULL; } -const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx) +const OSSL_PARAM *EVP_PKEY_CTX_settable_params(const EVP_PKEY_CTX *ctx) { + void *provctx; + if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchange != NULL - && ctx->op.kex.exchange->settable_ctx_params != NULL) - return ctx->op.kex.exchange->settable_ctx_params(); + && ctx->op.kex.exchange->settable_ctx_params != NULL) { + provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(ctx->op.kex.exchange)); + return ctx->op.kex.exchange->settable_ctx_params(ctx->op.kex.algctx, + provctx); + } if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) && ctx->op.sig.signature != NULL - && ctx->op.sig.signature->settable_ctx_params != NULL) - return ctx->op.sig.signature->settable_ctx_params(); + && ctx->op.sig.signature->settable_ctx_params != NULL) { + provctx = ossl_provider_ctx( + EVP_SIGNATURE_get0_provider(ctx->op.sig.signature)); + return ctx->op.sig.signature->settable_ctx_params(ctx->op.sig.algctx, + provctx); + } if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) && ctx->op.ciph.cipher != NULL - && ctx->op.ciph.cipher->settable_ctx_params != NULL) - return ctx->op.ciph.cipher->settable_ctx_params(); - + && ctx->op.ciph.cipher->settable_ctx_params != NULL) { + provctx = ossl_provider_ctx( + EVP_ASYM_CIPHER_get0_provider(ctx->op.ciph.cipher)); + return ctx->op.ciph.cipher->settable_ctx_params(ctx->op.ciph.algctx, + provctx); + } + if (EVP_PKEY_CTX_IS_GEN_OP(ctx) + && ctx->keymgmt != NULL + && ctx->keymgmt->gen_settable_params != NULL) { + provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(ctx->keymgmt)); + return ctx->keymgmt->gen_settable_params(ctx->op.keymgmt.genctx, + provctx); + } + if (EVP_PKEY_CTX_IS_KEM_OP(ctx) + && ctx->op.encap.kem != NULL + && ctx->op.encap.kem->settable_ctx_params != NULL) { + provctx = ossl_provider_ctx(EVP_KEM_get0_provider(ctx->op.encap.kem)); + return ctx->op.encap.kem->settable_ctx_params(ctx->op.encap.algctx, + provctx); + } return NULL; } @@ -635,23 +827,31 @@ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx) * * In particular they return -2 if any of the params is not supported. * - * They are not available in FIPS_MODE as they depend on + * They are not available in FIPS_MODULE as they depend on * - EVP_PKEY_CTX_{get,set}_params() * - EVP_PKEY_CTX_{gettable,settable}_params() * */ int evp_pkey_ctx_set_params_strict(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) { - const OSSL_PARAM *p; - if (ctx == NULL || params == NULL) return 0; - for (p = params; p->key != NULL; p++) { - /* Check the ctx actually understands this parameter */ - if (OSSL_PARAM_locate_const(EVP_PKEY_CTX_settable_params(ctx), - p->key) == NULL ) - return -2; + /* + * We only check for provider side EVP_PKEY_CTX. For #legacy, we + * depend on the translation that happens in EVP_PKEY_CTX_set_params() + * call, and that the resulting ctrl call will return -2 if it doesn't + * known the ctrl command number. + */ + if (evp_pkey_ctx_is_provided(ctx)) { + const OSSL_PARAM *settable = EVP_PKEY_CTX_settable_params(ctx); + const OSSL_PARAM *p; + + for (p = params; p->key != NULL; p++) { + /* Check the ctx actually understands this parameter */ + if (OSSL_PARAM_locate_const(settable, p->key) == NULL ) + return -2; + } } return EVP_PKEY_CTX_set_params(ctx, params); @@ -659,48 +859,32 @@ int evp_pkey_ctx_set_params_strict(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) int evp_pkey_ctx_get_params_strict(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) { - const OSSL_PARAM *p; - if (ctx == NULL || params == NULL) return 0; - for (p = params; p->key != NULL; p++ ) { - /* Check the ctx actually understands this parameter */ - if (OSSL_PARAM_locate_const(EVP_PKEY_CTX_gettable_params(ctx), - p->key) == NULL ) - return -2; - } - - return EVP_PKEY_CTX_get_params(ctx, params); -} - -# ifndef OPENSSL_NO_DH -int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) -{ - OSSL_PARAM dh_pad_params[2]; - unsigned int upad = pad; + /* + * We only check for provider side EVP_PKEY_CTX. For #legacy, we + * depend on the translation that happens in EVP_PKEY_CTX_get_params() + * call, and that the resulting ctrl call will return -2 if it doesn't + * known the ctrl command number. + */ + if (evp_pkey_ctx_is_provided(ctx)) { + const OSSL_PARAM *gettable = EVP_PKEY_CTX_gettable_params(ctx); + const OSSL_PARAM *p; - /* We use EVP_PKEY_CTX_ctrl return values */ - if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { - ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); - return -2; + for (p = params; p->key != NULL; p++ ) { + /* Check the ctx actually understands this parameter */ + if (OSSL_PARAM_locate_const(gettable, p->key) == NULL ) + return -2; + } } - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.kex.exchprovctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE, - EVP_PKEY_CTRL_DH_PAD, pad, NULL); - - dh_pad_params[0] = OSSL_PARAM_construct_uint(OSSL_EXCHANGE_PARAM_PAD, &upad); - dh_pad_params[1] = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, dh_pad_params); + return EVP_PKEY_CTX_get_params(ctx, params); } -# 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; + OSSL_PARAM sig_md_params[2], *p = sig_md_params; /* 80 should be big enough */ char name[80] = ""; const EVP_MD *tmp; @@ -711,15 +895,14 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) return -2; } - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.sig.sigprovctx == NULL) + if (ctx->op.sig.algctx == 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(); + *p = OSSL_PARAM_construct_end(); if (!EVP_PKEY_CTX_get_params(ctx, sig_md_params)) return 0; @@ -733,239 +916,624 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) return 1; } -int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +static int evp_pkey_ctx_set_md(EVP_PKEY_CTX *ctx, const EVP_MD *md, + int fallback, const char *param, int op, + int ctrl) { - OSSL_PARAM sig_md_params[2], *p = sig_md_params; + OSSL_PARAM md_params[2], *p = md_params; const char *name; - if (ctx == NULL || !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)) { + if (ctx == NULL || (ctx->operation & op) == 0) { 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->op.sig.sigprovctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, - EVP_PKEY_CTRL_MD, 0, (void *)(md)); + if (fallback) + return EVP_PKEY_CTX_ctrl(ctx, -1, op, ctrl, 0, (void *)(md)); if (md == NULL) { name = ""; } else { - name = EVP_MD_name(md); + name = EVP_MD_get0_name(md); } - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, + *p++ = OSSL_PARAM_construct_utf8_string(param, /* * Cast away the const. This is read * only so should be safe */ (char *)name, 0); - *p++ = OSSL_PARAM_construct_end(); + *p = OSSL_PARAM_construct_end(); - return EVP_PKEY_CTX_set_params(ctx, sig_md_params); + return EVP_PKEY_CTX_set_params(ctx, md_params); } -static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, - int cmd, int p1, void *p2) +int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { -# ifndef OPENSSL_NO_DH - if (keytype == EVP_PKEY_DH) { - switch (cmd) { - case EVP_PKEY_CTRL_DH_PAD: - return EVP_PKEY_CTX_set_dh_pad(ctx, p1); - } + return evp_pkey_ctx_set_md(ctx, md, ctx->op.sig.algctx == NULL, + OSSL_SIGNATURE_PARAM_DIGEST, + EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD); +} + +int EVP_PKEY_CTX_set_tls1_prf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +{ + return evp_pkey_ctx_set_md(ctx, md, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_DIGEST, + EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_TLS_MD); +} + +static int evp_pkey_ctx_set1_octet_string(EVP_PKEY_CTX *ctx, int fallback, + const char *param, int op, int ctrl, + const unsigned char *data, + int datalen) +{ + OSSL_PARAM octet_string_params[2], *p = octet_string_params; + + if (ctx == NULL || (ctx->operation & op) == 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; } -# endif -# ifndef OPENSSL_NO_EC - if (keytype == EVP_PKEY_EC) { - switch (cmd) { - case EVP_PKEY_CTRL_EC_ECDH_COFACTOR: - if (p1 == -2) { - return EVP_PKEY_CTX_get_ecdh_cofactor_mode(ctx); - } else if (p1 < -1 || p1 > 1) { - /* Uses the same return values as EVP_PKEY_CTX_ctrl */ - return -2; - } else { - return EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, p1); - } - case EVP_PKEY_CTRL_EC_KDF_TYPE: - if (p1 == -2) { - return EVP_PKEY_CTX_get_ecdh_kdf_type(ctx); - } else { - return EVP_PKEY_CTX_set_ecdh_kdf_type(ctx, p1); - } - case EVP_PKEY_CTRL_GET_EC_KDF_MD: - return EVP_PKEY_CTX_get_ecdh_kdf_md(ctx, p2); - case EVP_PKEY_CTRL_EC_KDF_MD: - return EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, p2); - case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN: - return EVP_PKEY_CTX_get_ecdh_kdf_outlen(ctx, p2); - case EVP_PKEY_CTRL_EC_KDF_OUTLEN: - return EVP_PKEY_CTX_set_ecdh_kdf_outlen(ctx, p1); - case EVP_PKEY_CTRL_GET_EC_KDF_UKM: - return EVP_PKEY_CTX_get0_ecdh_kdf_ukm(ctx, p2); - case EVP_PKEY_CTRL_EC_KDF_UKM: - return EVP_PKEY_CTX_set0_ecdh_kdf_ukm(ctx, p2, p1); - } + + /* Code below to be removed when legacy support is dropped. */ + if (fallback) + return EVP_PKEY_CTX_ctrl(ctx, -1, op, ctrl, datalen, (void *)(data)); + /* end of legacy support */ + + if (datalen < 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); + return 0; } -# endif - if (keytype == -1) { - switch (cmd) { - case EVP_PKEY_CTRL_MD: - return EVP_PKEY_CTX_set_signature_md(ctx, p2); - case EVP_PKEY_CTRL_GET_MD: - return EVP_PKEY_CTX_get_signature_md(ctx, p2); - case EVP_PKEY_CTRL_RSA_PADDING: - return EVP_PKEY_CTX_set_rsa_padding(ctx, p1); - case EVP_PKEY_CTRL_GET_RSA_PADDING: - return EVP_PKEY_CTX_get_rsa_padding(ctx, p2); - case EVP_PKEY_CTRL_RSA_OAEP_MD: - return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2); - case EVP_PKEY_CTRL_GET_RSA_OAEP_MD: - return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2); - case EVP_PKEY_CTRL_RSA_MGF1_MD: - return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2); - case EVP_PKEY_CTRL_GET_RSA_MGF1_MD: - return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2); - case EVP_PKEY_CTRL_RSA_OAEP_LABEL: - return EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, p2, p1); - case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL: - return EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, (unsigned char **)p2); - case EVP_PKEY_CTRL_PKCS7_ENCRYPT: - case EVP_PKEY_CTRL_PKCS7_DECRYPT: -# ifndef OPENSSL_NO_CMS - case EVP_PKEY_CTRL_CMS_DECRYPT: - case EVP_PKEY_CTRL_CMS_ENCRYPT: -# endif - if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) - return 1; - ERR_raise(ERR_LIB_EVP, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; - } + + *p++ = OSSL_PARAM_construct_octet_string(param, + /* + * Cast away the const. This is read + * only so should be safe + */ + (unsigned char *)data, + (size_t)datalen); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, octet_string_params); +} + +int EVP_PKEY_CTX_set1_tls1_prf_secret(EVP_PKEY_CTX *ctx, + const unsigned char *sec, int seclen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_SECRET, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_TLS_SECRET, + sec, seclen); +} + +int EVP_PKEY_CTX_add1_tls1_prf_seed(EVP_PKEY_CTX *ctx, + const unsigned char *seed, int seedlen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_SEED, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_TLS_SEED, + seed, seedlen); +} + +int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +{ + return evp_pkey_ctx_set_md(ctx, md, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_DIGEST, + EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_HKDF_MD); +} + +int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *ctx, + const unsigned char *salt, int saltlen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_SALT, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_SALT, + salt, saltlen); +} + +int EVP_PKEY_CTX_set1_hkdf_key(EVP_PKEY_CTX *ctx, + const unsigned char *key, int keylen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_KEY, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_KEY, + key, keylen); +} + +int EVP_PKEY_CTX_add1_hkdf_info(EVP_PKEY_CTX *ctx, + const unsigned char *info, int infolen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_INFO, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_INFO, + info, infolen); +} + +int EVP_PKEY_CTX_set_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) +{ + OSSL_PARAM int_params[2], *p = int_params; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; } - return 0; + + /* Code below to be removed when legacy support is dropped. */ + if (ctx->op.kex.algctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_MODE, mode, NULL); + /* end of legacy support */ + + if (mode < 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE); + return 0; + } + + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, int_params); } -int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, - int cmd, int p1, void *p2) +int EVP_PKEY_CTX_set1_pbe_pass(EVP_PKEY_CTX *ctx, const char *pass, + int passlen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_PASSWORD, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_PASS, + (const unsigned char *)pass, passlen); +} + +int EVP_PKEY_CTX_set1_scrypt_salt(EVP_PKEY_CTX *ctx, + const unsigned char *salt, int saltlen) +{ + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.kex.algctx == NULL, + OSSL_KDF_PARAM_SALT, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_SCRYPT_SALT, + salt, saltlen); +} + +static int evp_pkey_ctx_set_uint64(EVP_PKEY_CTX *ctx, const char *param, + int op, int ctrl, uint64_t val) +{ + OSSL_PARAM uint64_params[2], *p = uint64_params; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* Code below to be removed when legacy support is dropped. */ + if (ctx->op.kex.algctx == NULL) + return EVP_PKEY_CTX_ctrl_uint64(ctx, -1, op, ctrl, val); + /* end of legacy support */ + + *p++ = OSSL_PARAM_construct_uint64(param, &val); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, uint64_params); +} + +int EVP_PKEY_CTX_set_scrypt_N(EVP_PKEY_CTX *ctx, uint64_t n) +{ + return evp_pkey_ctx_set_uint64(ctx, OSSL_KDF_PARAM_SCRYPT_N, + EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_SCRYPT_N, + n); +} + +int EVP_PKEY_CTX_set_scrypt_r(EVP_PKEY_CTX *ctx, uint64_t r) +{ + return evp_pkey_ctx_set_uint64(ctx, OSSL_KDF_PARAM_SCRYPT_R, + EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_SCRYPT_R, + r); +} + +int EVP_PKEY_CTX_set_scrypt_p(EVP_PKEY_CTX *ctx, uint64_t p) +{ + return evp_pkey_ctx_set_uint64(ctx, OSSL_KDF_PARAM_SCRYPT_P, + EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_SCRYPT_P, + p); +} + +int EVP_PKEY_CTX_set_scrypt_maxmem_bytes(EVP_PKEY_CTX *ctx, + uint64_t maxmem_bytes) +{ + return evp_pkey_ctx_set_uint64(ctx, OSSL_KDF_PARAM_SCRYPT_MAXMEM, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES, + maxmem_bytes); +} + +int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key, + int keylen) { + return evp_pkey_ctx_set1_octet_string(ctx, ctx->op.keymgmt.genctx == NULL, + OSSL_PKEY_PARAM_PRIV_KEY, + EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_SET_MAC_KEY, + key, keylen); +} + +int EVP_PKEY_CTX_set_kem_op(EVP_PKEY_CTX *ctx, const char *op) +{ + OSSL_PARAM params[2], *p = params; + + if (ctx == NULL || op == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE); + return 0; + } + if (!EVP_PKEY_CTX_IS_KEM_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, + (char *)op, 0); + *p = OSSL_PARAM_construct_end(); + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int evp_pkey_ctx_set1_id_prov(EVP_PKEY_CTX *ctx, const void *id, int len) +{ + OSSL_PARAM params[2], *p = params; int ret; - if (ctx == NULL) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + if (!EVP_PKEY_CTX_IS_SIGNATURE_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 ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL) - || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL) - || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) - && ctx->op.ciph.ciphprovctx != NULL)) - return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DIST_ID, + /* + * Cast away the const. This is + * read only so should be safe + */ + (void *)id, (size_t)len); + *p++ = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return ret; +} + +int EVP_PKEY_CTX_set1_id(EVP_PKEY_CTX *ctx, const void *id, int len) +{ + return EVP_PKEY_CTX_ctrl(ctx, -1, -1, + EVP_PKEY_CTRL_SET1_ID, (int)len, (void*)(id)); +} - if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); +static int get1_id_data(EVP_PKEY_CTX *ctx, void *id, size_t *id_len) +{ + int ret; + void *tmp_id = NULL; + OSSL_PARAM params[2], *p = params; + + if (!EVP_PKEY_CTX_IS_SIGNATURE_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 ((keytype != -1) && (ctx->pmeth->pkey_id != keytype)) - return -1; - /* Skip the operation checks since this is called in a very early stage */ - if (ctx->pmeth->digest_custom != NULL) - goto doit; + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_PKEY_PARAM_DIST_ID, + &tmp_id, 0); + *p++ = OSSL_PARAM_construct_end(); - if (ctx->operation == EVP_PKEY_OP_UNDEFINED) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_NO_OPERATION_SET); - return -1; + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + } else if (ret > 0) { + size_t tmp_id_len = params[0].return_size; + + if (id != NULL) + memcpy(id, tmp_id, tmp_id_len); + if (id_len != NULL) + *id_len = tmp_id_len; } + return ret; +} - if ((optype != -1) && !(ctx->operation & optype)) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_INVALID_OPERATION); - return -1; +int evp_pkey_ctx_get1_id_prov(EVP_PKEY_CTX *ctx, void *id) +{ + return get1_id_data(ctx, id, NULL); +} + +int evp_pkey_ctx_get1_id_len_prov(EVP_PKEY_CTX *ctx, size_t *id_len) +{ + return get1_id_data(ctx, NULL, id_len); +} + +int EVP_PKEY_CTX_get1_id(EVP_PKEY_CTX *ctx, void *id) +{ + return EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_GET1_ID, 0, (void*)id); +} + +int EVP_PKEY_CTX_get1_id_len(EVP_PKEY_CTX *ctx, size_t *id_len) +{ + return EVP_PKEY_CTX_ctrl(ctx, -1, -1, + EVP_PKEY_CTRL_GET1_ID_LEN, 0, (void*)id_len); +} + +static int evp_pkey_ctx_ctrl_int(EVP_PKEY_CTX *ctx, int keytype, int optype, + int cmd, int p1, void *p2) +{ + int ret = 0; + + /* + * If the method has a |digest_custom| function, we can relax the + * operation type check, since this can be called before the operation + * is initialized. + */ + if (ctx->pmeth == NULL || ctx->pmeth->digest_custom == NULL) { + if (ctx->operation == EVP_PKEY_OP_UNDEFINED) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_OPERATION_SET); + return -1; + } + + if ((optype != -1) && !(ctx->operation & optype)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return -1; + } } - doit: - ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2); + switch (evp_pkey_ctx_state(ctx)) { + case EVP_PKEY_STATE_PROVIDER: + return evp_pkey_ctx_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2); + case EVP_PKEY_STATE_UNKNOWN: + case EVP_PKEY_STATE_LEGACY: + if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype)) + return -1; - if (ret == -2) - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2); + if (ret == -2) + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + break; + } return ret; } +int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, + int cmd, int p1, void *p2) +{ + int ret = 0; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + /* If unsupported, we don't want that reported here */ + ERR_set_mark(); + ret = evp_pkey_ctx_store_cached_data(ctx, keytype, optype, + cmd, NULL, p2, p1); + if (ret == -2) { + ERR_pop_to_mark(); + } else { + ERR_clear_last_mark(); + /* + * If there was an error, there was an error. + * If the operation isn't initialized yet, we also return, as + * the saved values will be used then anyway. + */ + if (ret < 1 || ctx->operation == EVP_PKEY_OP_UNDEFINED) + return ret; + } + return evp_pkey_ctx_ctrl_int(ctx, keytype, optype, cmd, p1, p2); +} + int EVP_PKEY_CTX_ctrl_uint64(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, uint64_t value) { return EVP_PKEY_CTX_ctrl(ctx, keytype, optype, cmd, 0, &value); } -static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name, - const char *value) + +static int evp_pkey_ctx_ctrl_str_int(EVP_PKEY_CTX *ctx, + const char *name, const char *value) { - if (strcmp(name, "rsa_padding_mode") == 0) - name = OSSL_ASYM_CIPHER_PARAM_PAD_MODE; - else if (strcmp(name, "rsa_mgf1_md") == 0) - name = OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST; - else if (strcmp(name, "rsa_oaep_md") == 0) - name = OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST; - else if (strcmp(name, "rsa_oaep_label") == 0) - name = OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL; -# ifndef OPENSSL_NO_DH - else if (strcmp(name, "dh_pad") == 0) - name = OSSL_EXCHANGE_PARAM_PAD; -# endif -# ifndef OPENSSL_NO_EC - else if (strcmp(name, "ecdh_cofactor_mode") == 0) - name = OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE; - else if (strcmp(name, "ecdh_kdf_md") == 0) - name = OSSL_EXCHANGE_PARAM_KDF_TYPE; -# endif + int ret = 0; - { - /* - * TODO(3.0) reduce the code above to only translate known legacy - * string to the corresponding core name (see core_names.h), but - * otherwise leave it to this code block to do the actual work. - */ - const OSSL_PARAM *settable = EVP_PKEY_CTX_settable_params(ctx); - OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - int rv = 0; + if (ctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } - if (!OSSL_PARAM_allocate_from_text(¶ms[0], settable, name, value, - strlen(value))) - return 0; - if (EVP_PKEY_CTX_set_params(ctx, params)) - rv = 1; - OPENSSL_free(params[0].data); - return rv; + switch (evp_pkey_ctx_state(ctx)) { + case EVP_PKEY_STATE_PROVIDER: + return evp_pkey_ctx_ctrl_str_to_param(ctx, name, value); + case EVP_PKEY_STATE_UNKNOWN: + case EVP_PKEY_STATE_LEGACY: + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->ctrl_str == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (strcmp(name, "digest") == 0) + ret = EVP_PKEY_CTX_md(ctx, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_MD, value); + else + ret = ctx->pmeth->ctrl_str(ctx, name, value); + break; } + + return ret; } int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *name, const char *value) { - if (ctx == NULL) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED); - return -2; + int ret = 0; + + /* If unsupported, we don't want that reported here */ + ERR_set_mark(); + ret = evp_pkey_ctx_store_cached_data(ctx, -1, -1, -1, + name, value, strlen(value) + 1); + if (ret == -2) { + ERR_pop_to_mark(); + } else { + ERR_clear_last_mark(); + /* + * If there was an error, there was an error. + * If the operation isn't initialized yet, we also return, as + * the saved values will be used then anyway. + */ + if (ret < 1 || ctx->operation == EVP_PKEY_OP_UNDEFINED) + return ret; + } + + return evp_pkey_ctx_ctrl_str_int(ctx, name, value); +} + +static int decode_cmd(int cmd, const char *name) +{ + if (cmd == -1) { + /* + * The consequence of the assertion not being true is that this + * function will return -1, which will cause the calling functions + * to signal that the command is unsupported... in non-debug mode. + */ + if (ossl_assert(name != NULL)) + if (strcmp(name, "distid") == 0 || strcmp(name, "hexdistid") == 0) + cmd = EVP_PKEY_CTRL_SET1_ID; } - if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL) - || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL) - || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) - && ctx->op.ciph.ciphprovctx != NULL)) - return legacy_ctrl_str_to_param(ctx, name, value); + return cmd; +} - if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) { - EVPerr(EVP_F_EVP_PKEY_CTX_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED); +static int evp_pkey_ctx_store_cached_data(EVP_PKEY_CTX *ctx, + int keytype, int optype, + int cmd, const char *name, + const void *data, size_t data_len) +{ + /* + * Check that it's one of the supported commands. The ctrl commands + * number cases here must correspond to the cases in the bottom switch + * in this function. + */ + switch (cmd = decode_cmd(cmd, name)) { + case EVP_PKEY_CTRL_SET1_ID: + break; + default: + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); return -2; } - if (strcmp(name, "digest") == 0) - return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, - value); - return ctx->pmeth->ctrl_str(ctx, name, value); + + if (keytype != -1) { + switch (evp_pkey_ctx_state(ctx)) { + case EVP_PKEY_STATE_PROVIDER: + if (ctx->keymgmt == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (!EVP_KEYMGMT_is_a(ctx->keymgmt, + evp_pkey_type2name(keytype))) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return -1; + } + break; + case EVP_PKEY_STATE_UNKNOWN: + case EVP_PKEY_STATE_LEGACY: + if (ctx->pmeth == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (EVP_PKEY_type(ctx->pmeth->pkey_id) != EVP_PKEY_type(keytype)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return -1; + } + break; + } + } + if (optype != -1 && (ctx->operation & optype) == 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return -1; + } + + switch (cmd) { + case EVP_PKEY_CTRL_SET1_ID: + evp_pkey_ctx_free_cached_data(ctx, cmd, name); + if (name != NULL) { + ctx->cached_parameters.dist_id_name = OPENSSL_strdup(name); + if (ctx->cached_parameters.dist_id_name == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } + if (data_len > 0) { + ctx->cached_parameters.dist_id = OPENSSL_memdup(data, data_len); + if (ctx->cached_parameters.dist_id == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } + ctx->cached_parameters.dist_id_set = 1; + ctx->cached_parameters.dist_id_len = data_len; + break; + } + return 1; +} + +static void evp_pkey_ctx_free_cached_data(EVP_PKEY_CTX *ctx, + int cmd, const char *name) +{ + cmd = decode_cmd(cmd, name); + switch (cmd) { + case EVP_PKEY_CTRL_SET1_ID: + OPENSSL_free(ctx->cached_parameters.dist_id); + OPENSSL_free(ctx->cached_parameters.dist_id_name); + ctx->cached_parameters.dist_id = NULL; + ctx->cached_parameters.dist_id_name = NULL; + break; + } +} + +static void evp_pkey_ctx_free_all_cached_data(EVP_PKEY_CTX *ctx) +{ + evp_pkey_ctx_free_cached_data(ctx, EVP_PKEY_CTRL_SET1_ID, NULL); +} + +int evp_pkey_ctx_use_cached_data(EVP_PKEY_CTX *ctx) +{ + int ret = 1; + + if (ret && ctx->cached_parameters.dist_id_set) { + const char *name = ctx->cached_parameters.dist_id_name; + const void *val = ctx->cached_parameters.dist_id; + size_t len = ctx->cached_parameters.dist_id_len; + + if (name != NULL) + ret = evp_pkey_ctx_ctrl_str_int(ctx, name, val); + else + ret = evp_pkey_ctx_ctrl_int(ctx, -1, ctx->operation, + EVP_PKEY_CTRL_SET1_ID, + (int)len, (void *)val); + } + + return ret; +} + +OSSL_LIB_CTX *EVP_PKEY_CTX_get0_libctx(EVP_PKEY_CTX *ctx) +{ + return ctx->libctx; +} + +const char *EVP_PKEY_CTX_get0_propq(EVP_PKEY_CTX *ctx) +{ + return ctx->propquery; } /* Utility functions to send a string of hex string to a ctrl */ @@ -1001,7 +1569,7 @@ int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md) const EVP_MD *m; if (md == NULL || (m = EVP_get_digestbyname(md)) == NULL) { - EVPerr(EVP_F_EVP_PKEY_CTX_MD, EVP_R_INVALID_DIGEST); + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_DIGEST); return 0; } return EVP_PKEY_CTX_ctrl(ctx, -1, optype, cmd, 0, (void *)m); @@ -1446,4 +2014,4 @@ void EVP_PKEY_meth_get_digest_custom(EVP_PKEY_METHOD *pmeth, *pdigest_custom = pmeth->digest_custom; } -#endif /* FIPS_MODE */ +#endif /* FIPS_MODULE */