diff options
-rw-r--r-- | crypto/evp/build.info | 2 | ||||
-rw-r--r-- | crypto/evp/ctrl_params_translate.c | 2685 | ||||
-rw-r--r-- | include/crypto/evp.h | 17 |
3 files changed, 2703 insertions, 1 deletions
diff --git a/crypto/evp/build.info b/crypto/evp/build.info index 4b3057873f..34551df4a3 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -15,7 +15,7 @@ SOURCE[../../libcrypto]=$COMMON\ evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c pbe_scrypt.c \ e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \ e_chacha20_poly1305.c \ - legacy_sha.c + legacy_sha.c ctrl_params_translate.c # Diverse type specific ctrl functions. They are kinda sorta legacy, kinda # sorta not. diff --git a/crypto/evp/ctrl_params_translate.c b/crypto/evp/ctrl_params_translate.c new file mode 100644 index 0000000000..84a55e4d07 --- /dev/null +++ b/crypto/evp/ctrl_params_translate.c @@ -0,0 +1,2685 @@ +/* + * Copyright 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Some ctrls depend on deprecated functionality. We trust that this is + * functionality that remains internally even when 'no-deprecated' is + * configured. When we drop #legacy EVP_PKEYs, this source should be + * possible to drop as well. + */ +#include "internal/deprecated.h" + +#include <string.h> + +/* The following includes get us all the EVP_PKEY_CTRL macros */ +#include <openssl/dh.h> +#include <openssl/dsa.h> +#include <openssl/ec.h> +#include <openssl/rsa.h> +#include <openssl/kdf.h> + +/* This include gets us all the OSSL_PARAM key string macros */ +#include <openssl/core_names.h> + +#include <openssl/err.h> +#include <openssl/evperr.h> +#include <openssl/params.h> +#include "internal/nelem.h" +#include "internal/cryptlib.h" +#include "internal/ffc.h" +#include "crypto/evp.h" +#include "crypto/dh.h" +#include "crypto/ec.h" + +#include "e_os.h" /* strcasecmp() for Windows */ + +struct translation_ctx_st; /* Forwarding */ +struct translation_st; /* Forwarding */ + +/* + * The fixup_args functions are called with the following parameters: + * + * |state| The state we're called in, explained further at the + * end of this comment. + * |translation| The translation item, to be pilfered for data as + * necessary. + * |ctx| The translation context, which contains copies of + * the following arguments, applicable according to + * the caller. All of the attributes in this context + * may be freely modified by the fixup_args function. + * For cleanup, call cleanup_translation_ctx(). + * + * The |state| tells the fixup_args function something about the caller and + * what they may expect: + * + * PKEY The fixup_args function has been called + * from an EVP_PKEY payload getter / setter, + * and is fully responsible for getting or + * setting the requested data. With this + * state, the fixup_args function is expected + * to use or modify |*params|, depending on + * |action_type|. + * + * PRE_CTRL_TO_PARAMS The fixup_args function has been called + * POST_CTRL_TO_PARAMS from EVP_PKEY_CTX_ctrl(), to help with + * translating the ctrl data to an OSSL_PARAM + * element or back. The calling sequence is + * as follows: + * + * 1. fixup_args(PRE_CTRL_TO_PARAMS, ...) + * 2. EVP_PKEY_CTX_set_params() or + * EVP_PKEY_CTX_get_params() + * 3. fixup_args(POST_CTRL_TO_PARAMS, ...) + * + * With the PRE_CTRL_TO_PARAMS state, the + * fixup_args function is expected to modify + * the passed |*params| in whatever way + * necessary, when |action_type == SET|. + * With the POST_CTRL_TO_PARAMS state, the + * fixup_args function is expected to modify + * the passed |p2| in whatever way necessary, + * when |action_type == GET|. + * + * The return value from the fixup_args call + * with the POST_CTRL_TO_PARAMS state becomes + * the return value back to EVP_PKEY_CTX_ctrl(). + * CLEANUP_CTRL_TO_PARAMS The cleanup_args functions has been called + * from EVP_PKEY_CTX_ctrl(), to clean up what + * the fixup_args function has done, if needed. + * + * PRE_CTRL_STR_TO_PARAMS The fixup_args function has been called + * POST_CTRL_STR_TO_PARAMS from EVP_PKEY_CTX_ctrl_str(), to help with + * translating the ctrl_str data to an + * OSSL_PARAM element or back. The calling + * sequence is as follows: + * + * 1. fixup_args(PRE_CTRL_STR_TO_PARAMS, ...) + * 2. EVP_PKEY_CTX_set_params() or + * EVP_PKEY_CTX_get_params() + * 3. fixup_args(POST_CTRL_STR_TO_PARAMS, ...) + * + * With the PRE_CTRL_STR_TO_PARAMS state, + * the fixup_args function is expected to + * modify the passed |*params| in whatever + * way necessary, when |action_type == SET|. + * With the POST_CTRL_STR_TO_PARAMS state, + * the fixup_args function is only expected + * to return a value. + * CLEANUP_CTRL_STR_TO_PARAMS The cleanup_args functions has been called + * from EVP_PKEY_CTX_ctrl_str(), to clean up + * what the fixup_args function has done, if + * needed. + * + * PRE_PARAMS_TO_CTRL The fixup_args function has been called + * POST_PARAMS_TO_CTRL from EVP_PKEY_CTX_get_params() or + * EVP_PKEY_CTX_set_params(), to help with + * translating the OSSL_PARAM data to the + * corresponding EVP_PKEY_CTX_ctrl() arguments + * or the other way around. The calling + * sequence is as follows: + * + * 1. fixup_args(PRE_PARAMS_TO_CTRL, ...) + * 2. EVP_PKEY_CTX_ctrl() + * 3. fixup_args(POST_PARAMS_TO_CTRL, ...) + * + * With the PRE_PARAMS_TO_CTRL state, the + * fixup_args function is expected to modify + * the passed |p1| and |p2| in whatever way + * necessary, when |action_type == SET|. + * With the POST_PARAMS_TO_CTRL state, the + * fixup_args function is expected to + * modify the passed |*params| in whatever + * way necessary, when |action_type == GET|. + * CLEANUP_PARAMS_TO_CTRL The cleanup_args functions has been called + * from EVP_PKEY_CTX_get_params() or + * EVP_PKEY_CTX_set_params(), to clean up what + * the fixup_args function has done, if needed. + */ +enum state { + PKEY, + PRE_CTRL_TO_PARAMS, POST_CTRL_TO_PARAMS, CLEANUP_CTRL_TO_PARAMS, + PRE_CTRL_STR_TO_PARAMS, POST_CTRL_STR_TO_PARAMS, CLEANUP_CTRL_STR_TO_PARAMS, + PRE_PARAMS_TO_CTRL, POST_PARAMS_TO_CTRL, CLEANUP_PARAMS_TO_CTRL, +}; +enum action { + NONE = 0, GET = 1, SET = 2 +}; +typedef int fixup_args_fn(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx); +typedef int cleanup_args_fn(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx); + +struct translation_ctx_st { + /* + * The EVP_PKEY_CTX, for calls on that structure, to be pilfered for data + * as necessary. + */ + EVP_PKEY_CTX *pctx; + /* + * The action type (GET or SET). This may be 0 in some cases, and should + * be modified by the fixup_args function in the PRE states. It should + * otherwise remain untouched once set. + */ + enum action action_type; + /* + * For ctrl to params translation, the actual ctrl command number used. + * For params to ctrl translation, 0. + */ + int ctrl_cmd; + /* + * For ctrl_str to params translation, the actual ctrl command string + * used. In this case, the (string) value is always passed as |p2|. + * For params to ctrl translation, this is NULL. Along with it is also + * and indicator whether it matched |ctrl_str| or |ctrl_hexstr| in the + * translation item. + */ + const char *ctrl_str; + int ishex; + /* the ctrl-style int argument. */ + int p1; + /* the ctrl-style void* argument. */ + void *p2; + /* a size, for passing back the |p2| size where applicable */ + size_t sz; + /* pointer to the OSSL_PARAM-style params array. */ + OSSL_PARAM *params; + + /*- + * The following are used entirely internally by the fixup_args functions + * and should not be touched by the callers, at all. + */ + + /* + * copy of the ctrl-style void* argument, if the the fixup_args function + * needs to manipulate |p2| but wants to remember original. + */ + void *orig_p2; + /* Diverse types of storage for the needy. */ + char name_buf[OSSL_MAX_NAME_SIZE]; + void *allocated_buf; + void *bufp; + size_t buflen; +}; + +struct translation_st { + /*- + * What this table item does. + * + * If the item has this set to 0, it means that both GET and SET are + * supported, and |fixup_args| will determine which it is. This is to + * support translations of ctrls where the action type depends on the + * value of |p1| or |p2| (ctrls are really bi-directional, but are + * seldom used that way). + * + * This can be also used in the lookup template when it looks up by + * OSSL_PARAM key, to indicate if a setter or a getter called. + */ + enum action action_type; + + /*- + * Conditions, for params->ctrl translations. + * + * In table item, |keytype1| and |keytype2| can be set to -1 to indicate + * that this item supports all key types (or rather, that |fixup_args| + * will check and return an error if it's not supported). + * Any of these may be set to 0 to indicate that they are unset. + */ + int keytype1; /* The EVP_PKEY_XXX type, i.e. NIDs. #legacy */ + int keytype2; /* Another EVP_PKEY_XXX type, used for aliases */ + int optype; /* The operation type */ + + /* + * Lookup and translation attributes + * + * |ctrl_num|, |ctrl_str|, |ctrl_hexstr| and |param_key| are lookup + * attributes. + * + * |ctrl_num| may be 0 or that |param_key| may be NULL in the table item, + * but not at the same time. If they are, they are simply not used for + * lookup. + * When |ctrl_num| == 0, no ctrl will be called. Likewise, when + * |param_key| == NULL, no OSSL_PARAM setter/getter will be called. + * In that case the treatment of the translation item relies entirely on + * |fixup_args|, which is then assumed to have side effects. + * + * As a special case, it's possible to set |ctrl_hexstr| and assign NULL + * to |ctrl_str|. That will signal to default_fixup_args() that the + * value must always be interpreted as hex. + */ + int ctrl_num; /* EVP_PKEY_CTRL_xxx */ + const char *ctrl_str; /* The corresponding ctrl string */ + const char *ctrl_hexstr; /* The alternative "hex{str}" ctrl string */ + const char *param_key; /* The corresponding OSSL_PARAM key */ + /* + * The appropriate OSSL_PARAM data type. This may be 0 to indicate that + * this OSSL_PARAM may have more than one data type, depending on input + * material. In this case, |fixup_args| is expected to check and handle + * it. + */ + unsigned int param_data_type; + + /* + * Fixer functions + * + * |fixup_args| is always called before (for SET) or after (for GET) + * the actual ctrl / OSSL_PARAM function. + */ + fixup_args_fn *fixup_args; +}; + +/*- + * Fixer function implementations + * ============================== + */ + +/* + * default_check isn't a fixer per se, but rather a helper function to + * perform certain standard checks. + */ +static int default_check(enum state state, + const struct translation_st *translation, + const struct translation_ctx_st *ctx) +{ + switch (state) { + default: + break; + case PRE_CTRL_TO_PARAMS: + if (!ossl_assert(translation != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (!ossl_assert(translation->param_key != 0) + || !ossl_assert(translation->param_data_type != 0)) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return -1; + } + break; + case PRE_CTRL_STR_TO_PARAMS: + /* + * For ctrl_str to params translation, we allow direct use of + * OSSL_PARAM keys as ctrl_str keys. Therefore, it's possible that + * we end up with |translation == NULL|, which is fine. The fixup + * function will have to deal with it carefully. + */ + if (translation != NULL) { + if (!ossl_assert(translation->action_type != GET)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (!ossl_assert(translation->param_key != NULL) + || !ossl_assert(translation->param_data_type != 0)) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return 0; + } + } + break; + case PRE_PARAMS_TO_CTRL: + case POST_PARAMS_TO_CTRL: + if (!ossl_assert(translation != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (!ossl_assert(translation->ctrl_num != 0) + || !ossl_assert(translation->param_data_type != 0)) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return -1; + } + } + + /* Nothing else to check */ + return 1; +} + +/*- + * default_fixup_args fixes up all sorts of arguments, governed by the + * diverse attributes in the translation item. It covers all "standard" + * base ctrl functionality, meaning it can handle basic conversion of + * data between p1+p2 (SET) or return value+p2 (GET) as long as the values + * don't have extra semantics (such as NIDs, OIDs, that sort of stuff). + * Extra semantics must be handled via specific fixup_args functions. + * + * The following states and action type combinations have standard handling + * done in this function: + * + * PRE_CTRL_TO_PARAMS, 0 - ERROR. action type must be + * determined by a fixup function. + * PRE_CTRL_TO_PARAMS, SET | GET - |p1| and |p2| are converted to an + * OSSL_PARAM according to the data + * type given in |translattion|. + * For OSSL_PARAM_UNSIGNED_INTEGER, + * a BIGNUM passed as |p2| is accepted. + * POST_CTRL_TO_PARAMS, GET - If the OSSL_PARAM data type is a + * STRING or PTR type, |p1| is set + * to the OSSL_PARAM return size, and + * |p2| is set to the string. + * PRE_CTRL_STR_TO_PARAMS, !SET - ERROR. That combination is not + * supported. + * PRE_CTRL_STR_TO_PARAMS, SET - |p2| is taken as a string, and is + * converted to an OSSL_PARAM in a + * standard manner, guided by the + * param key and data type from + * |translation|. + * PRE_PARAMS_TO_CTRL, SET - the OSSL_PARAM is converted to + * |p1| and |p2| according to the + * data type given in |translation| + * For OSSL_PARAM_UNSIGNED_INTEGER, + * if |p2| is non-NULL, then |*p2| + * is assigned a BIGNUM, otherwise + * |p1| is assigned an unsigned int. + * POST_PARAMS_TO_CTRL, GET - |p1| and |p2| are converted to + * an OSSL_PARAM, in the same manner + * as for the combination of + * PRE_CTRL_TO_PARAMS, SET. + */ +static int default_fixup_args(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx) +{ + int ret; + + if ((ret = default_check(state, translation, ctx)) < 0) + return ret; + + switch (state) { + default: + /* For states this function should never have been called with */ + ERR_raise_data(ERR_LIB_EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED, + "[action:%d, state:%d]", ctx->action_type, state); + return 0; + + /* + * PRE_CTRL_TO_PARAMS and POST_CTRL_TO_PARAMS handle ctrl to params + * translations. PRE_CTRL_TO_PARAMS is responsible for preparing + * |*params|, and POST_CTRL_TO_PARAMS is responsible for bringing the + * result back to |*p2| and the return value. + */ + case PRE_CTRL_TO_PARAMS: + /* This is ctrl to params translation, so we need an OSSL_PARAM key */ + if (ctx->action_type == NONE) { + /* + * No action type is an error here. That's a case for a + * special fixup function. + */ + ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED, + "[action:%d, state:%d]", ctx->action_type, state); + return 0; + } + + if (translation->optype != 0) { + if ((EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + && ctx->pctx->op.sig.sigprovctx == NULL) + || (EVP_PKEY_CTX_IS_DERIVE_OP(ctx->pctx) + && ctx->pctx->op.kex.exchprovctx == NULL) + || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx->pctx) + && ctx->pctx->op.ciph.ciphprovctx == NULL) + || (EVP_PKEY_CTX_IS_KEM_OP(ctx->pctx) + && ctx->pctx->op.encap.kemprovctx == NULL) + /* + * The following may be unnecessary, but we have them + * for good measure... + */ + || (EVP_PKEY_CTX_IS_GEN_OP(ctx->pctx) + && ctx->pctx->op.keymgmt.genctx == NULL) + || (EVP_PKEY_CTX_IS_FROMDATA_OP(ctx->pctx) + && ctx->pctx->op.keymgmt.genctx == NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + } + + /* + * OSSL_PARAM_construct_TYPE() works equally well for both SET and GET. + */ + switch (translation->param_data_type) { + case OSSL_PARAM_INTEGER: + *ctx->params = OSSL_PARAM_construct_int(translation->param_key, + &ctx->p1); + break; + case OSSL_PARAM_UNSIGNED_INTEGER: + /* + * BIGNUMs are passed via |p2|. For all ctrl's that just want + * to pass a simple integer via |p1|, |p2| is expected to be + * NULL. + * + * Note that this allocates a buffer, which the cleanup function + * must deallocate. + */ + if (ctx->p2 != NULL) { + if (ctx->action_type == SET) { + ctx->buflen = BN_num_bytes(ctx->p2); + if ((ctx->allocated_buf = + OPENSSL_malloc(ctx->buflen)) == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!BN_bn2nativepad(ctx->p2, + ctx->allocated_buf, ctx->buflen)) { + OPENSSL_free(ctx->allocated_buf); + ctx->allocated_buf = NULL; + return 0; + } + *ctx->params = + OSSL_PARAM_construct_BN(translation->param_key, + ctx->allocated_buf, + ctx->buflen); + } else { + /* + * No support for getting a BIGNUM by ctrl, this needs + * fixup_args function support. + */ + ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED, + "[action:%d, state:%d] trying to get a " + "BIGNUM via ctrl call", + ctx->action_type, state); + return 0; + } + } else { + *ctx->params = + OSSL_PARAM_construct_uint(translation->param_key, + (unsigned int *)&ctx->p1); + } + break; + case OSSL_PARAM_UTF8_STRING: + *ctx->params = + OSSL_PARAM_construct_utf8_string(translation->param_key, + ctx->p2, (size_t)ctx->p1); + break; + case OSSL_PARAM_UTF8_PTR: + *ctx->params = + OSSL_PARAM_construct_utf8_ptr(translation->param_key, + ctx->p2, (size_t)ctx->p1); + break; + case OSSL_PARAM_OCTET_STRING: + *ctx->params = + OSSL_PARAM_construct_octet_string(translation->param_key, + ctx->p2, (size_t)ctx->p1); + break; + case OSSL_PARAM_OCTET_PTR: + *ctx->params = + OSSL_PARAM_construct_octet_ptr(translation->param_key, + ctx->p2, (size_t)ctx->p1); + break; + } + break; + case POST_CTRL_TO_PARAMS: + /* + * Because EVP_PKEY_CTX_ctrl() returns the length of certain objects + * as its return value, we need to ensure that we do it here as well, + * for the OSSL_PARAM data types where this makes sense. + */ + if (ctx->action_type == GET) { + switch (translation->param_data_type) { + case OSSL_PARAM_UTF8_STRING: + case OSSL_PARAM_UTF8_PTR: + case OSSL_PARAM_OCTET_STRING: + case OSSL_PARAM_OCTET_PTR: + ctx->p1 = (int)ctx->params[0].return_size; + break; + } + } + break; + + /* + * PRE_CTRL_STR_TO_PARAMS and POST_CTRL_STR_TO_PARAMS handle ctrl_str to + * params translations. PRE_CTRL_TO_PARAMS is responsible for preparing + * |*params|, and POST_CTRL_TO_PARAMS currently has nothing to do, since + * there's no support for getting data via ctrl_str calls. + */ + case PRE_CTRL_STR_TO_PARAMS: + { + /* This is ctrl_str to params translation */ + const char *tmp_ctrl_str = ctx->ctrl_str; + const char *orig_ctrl_str = ctx->ctrl_str; + const char *orig_value = ctx->p2; + const OSSL_PARAM *settable = NULL; + int exists = 0; + + /* Only setting is supported here */ + if (ctx->action_type != SET) { + ERR_raise_data(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED, + "[action:%d, state:%d] only setting allowed", + ctx->action_type, state); + return 0; + } + + /* + * If no translation exists, we simply pass the control string + * unmodified. + */ + if (translation != NULL) { + tmp_ctrl_str = ctx->ctrl_str = translation->param_key; + + if (ctx->ishex) { + strcpy(ctx->name_buf, "hex"); + if (OPENSSL_strlcat(ctx->name_buf, tmp_ctrl_str, + sizeof(ctx->name_buf)) <= 3) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return -1; + } + tmp_ctrl_str = ctx->name_buf; + } + } + + settable = EVP_PKEY_CTX_settable_params(ctx->pctx); + if (!OSSL_PARAM_allocate_from_text(ctx->params, settable, + tmp_ctrl_str, + ctx->p2, strlen(ctx->p2), + &exists)) { + if (!exists) { + ERR_raise_data(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED, + "[action:%d, state:%d] name=%s, value=%s", + ctx->action_type, state, + orig_ctrl_str, orig_value); + return -2; + } + return 0; + } + ctx->allocated_buf = ctx->params->data; + ctx->buflen = ctx->params->data_size; + } + break; + case POST_CTRL_STR_TO_PARAMS: + /* Nothing to be done */ + break; + + /* + * PRE_PARAMS_TO_CTRL and POST_PARAMS_TO_CTRL handle params to ctrl + * translations. PRE_PARAMS_TO_CTRL is responsible for preparing + * |p1| and |p2|, and POST_PARAMS_TO_CTRL is responsible for bringing + * the EVP_PKEY_CTX_ctrl() return value (passed as |p1|) and |p2| back + * to |*params|. + * + * PKEY is treated just like POST_PARAMS_TO_CTRL, making it easy + * for the related fixup_args functions to just set |p1| and |p2| + * appropriately and leave it to this section of code to fix up + * |ctx->params| accordingly. + */ + case PKEY: + case POST_PARAMS_TO_CTRL: + ret = ctx->p1; + /* FALLTHRU */ + case PRE_PARAMS_TO_CTRL: + { + /* This is params to ctrl translation */ + if (state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET) { + /* For the PRE state, only setting needs some work to be done */ + + /* When setting, we populate |p1| and |p2| from |*params| */ + switch (translation->param_data_type) { + case OSSL_PARAM_INTEGER: + return OSSL_PARAM_get_int(ctx->params, &ctx->p1); + case OSSL_PARAM_UNSIGNED_INTEGER: + if (ctx->p2 != NULL) { + /* BIGNUM passed down with p2 */ + if (!OSSL_PARAM_get_BN(ctx->params, ctx->p2)) + return 0; + } else { + /* Normal C unsigned int passed down */ + if (!OSSL_PARAM_get_uint(ctx->params, + (unsigned int *)&ctx->p1)) + return 0; + } + return 1; + case OSSL_PARAM_UTF8_STRING: + return OSSL_PARAM_get_utf8_string(ctx->params, + ctx->p2, ctx->sz); + case OSSL_PARAM_OCTET_STRING: + return OSSL_PARAM_get_octet_string(ctx->params, + ctx->p2, ctx->sz, + &ctx->sz); + case OSSL_PARAM_OCTET_PTR: + return OSSL_PARAM_get_octet_ptr(ctx->params, + ctx->p2, &ctx->sz); + default: + ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED, + "[action:%d, state:%d] " + "unknown OSSL_PARAM data type %d", + ctx->action_type, state, + translation->param_data_type); + return 0; + } + } else if ((state == POST_PARAMS_TO_CTRL || state == PKEY) + && ctx->action_type == GET) { + /* For the POST state, only getting needs some work to be done */ + + /* When getting, we populate |*params| from |p1| and |p2| */ + switch (translation->param_data_type) { + case OSSL_PARAM_INTEGER: + return OSSL_PARAM_set_int(ctx->params, ctx->p1); + case OSSL_PARAM_UNSIGNED_INTEGER: + if (ctx->p2 != NULL) { + /* BIGNUM passed back */ + return OSSL_PARAM_set_BN(ctx->params, ctx->p2); + } else { + /* Normal C unsigned int passed back */ + return OSSL_PARAM_set_uint(ctx->params, + (unsigned int)ctx->p1); + } + return 0; + case OSSL_PARAM_UTF8_STRING: + return OSSL_PARAM_set_utf8_string(ctx->params, ctx->p2); + case OSSL_PARAM_OCTET_STRING: + return OSSL_PARAM_set_octet_string(ctx->params, ctx->p2, + (size_t)ctx->p1); + case OSSL_PARAM_OCTET_PTR: + return OSSL_PARAM_set_octet_ptr(ctx->params, ctx->p2, + (size_t)ctx->p1); + default: + ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED, + "[action:%d, state:%d] " + "unsupported OSSL_PARAM data type %d", + ctx->action_type, state, + translation->param_data_type); + return 0; + } + } + } + /* Any other combination is simply pass-through */ + break; + } + return ret; +} + +static int +cleanup_translation_ctx(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx) +{ + if (ctx->allocated_buf != NULL) + OPENSSL_free(ctx->allocated_buf); + ctx->allocated_buf = NULL; + return 1; +} + +/* + * fix_cipher_md fixes up an EVP_CIPHER / EVP_MD to its name on SET, + * and cipher / md name to EVP_MD on GET. + */ +static const char *get_cipher_name(void *cipher) +{ + return EVP_CIPHER_name(cipher); +} + +static const char *get_md_name(void *md) +{ + return EVP_MD_name(md); +} + +static const void *get_cipher_by_name(OSSL_LIB_CTX *libctx, const char *name) +{ + return evp_get_cipherbyname_ex(libctx, name); +} + +static const void *get_md_by_name(OSSL_LIB_CTX *libctx, const char *name) +{ + return evp_get_digestbyname_ex(libctx, name); +} + +static int fix_cipher_md(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx, + const char *(*get_name)(void *algo), + const void *(*get_algo_by_name)(OSSL_LIB_CTX *libctx, + const char *name)) +{ + int ret = 1; + + if ((ret = default_check(state, translation, ctx)) <= 0) + return ret; + + if (state == PRE_CTRL_TO_PARAMS && ctx->action_type == GET) { + /* + * |ctx->p2| contains the address to an EVP_CIPHER or EVP_MD pointer + * to be filled in. We need to remember it, then make |ctx->p2| + * point at a buffer to be filled in with the name, and |ctx->p1| + * with its size. default_fixup_args() will take care of the rest + * for us. + */ + ctx->orig_p2 = ctx->p2; + ctx->p2 = ctx->name_buf; + ctx->p1 = sizeof(ctx->name_buf); + } else if (state == PRE_CTRL_TO_PARAMS && ctx->action_type == SET) { + /* + * In different parts of OpenSSL, this ctrl command is used + * differently. Some calls pass a NID as p1, others pass an + * EVP_CIPHER pointer as p2... + */ + ctx->p2 = (char *)(ctx->p2 == NULL + ? OBJ_nid2sn(ctx->p1) + : get_name(ctx->p2)); + ctx->p1 = strlen(ctx->p2); + } else if (state == POST_PARAMS_TO_CTRL && ctx->action_type == GET) { + ctx->p2 = (ctx->p2 == NULL ? "" : (char *)get_name(ctx->p2)); + ctx->p1 = strlen(ctx->p2); + } + + if ((ret = default_fixup_args(state, translation, ctx)) <= 0) + return ret; + + if (state == POST_CTRL_TO_PARAMS && ctx->action_type == GET) { + /* + * Here's how we re-use |ctx->orig_p2| that was set in the + * PRE_CTRL_TO_PARAMS state above. + */ + *(void **)ctx->orig_p2 = + (void *)get_algo_by_name(ctx->pctx->libctx, ctx->p2); + ctx->p1 = 1; + } else if (state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET) { + ctx->p2 = (void *)get_algo_by_name(ctx->pctx->libctx, ctx->p2); + ctx->p1 = 0; + } + + return ret; +} + +static int fix_cipher(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx) +{ + return fix_cipher_md(state, translation, ctx, + get_cipher_name, get_cipher_by_name); +} + +static int fix_md(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx) +{ + return fix_cipher_md(state, translation, ctx, + get_md_name, get_md_by_name); +} + +static int fix_distid_len(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx) +{ + int ret = default_fixup_args(state, translation, ctx); + + if (ret > 0) { + ret = 0; + if ((state == POST_CTRL_TO_PARAMS + || state == POST_CTRL_STR_TO_PARAMS) && ctx->action_type == GET) { + *(size_t *)ctx->p2 = ctx->sz; + ret = 1; + } + } + return ret; +} + +struct kdf_type_map_st { + int kdf_type_num; + const char *kdf_type_str; +}; + +static int fix_kdf_type(enum state state, + const struct translation_st *translation, + struct translation_ctx_st *ctx, + const struct kdf_type_map_st *kdf_type_map) +{ + /* + * The EVP_PKEY_CTRL_DH_KDF_TYPE ctrl command is a bit special, in + * that it's used both for setting a value, and for getting it, all + * depending on the value if |p1|; if |p1| is -2, the backend is + * supposed to place the current kdf type in |p2|, and if not, |p1| + * is interpreted as the new kdf type. + */ + int ret = 0; + + if ((ret = default_check(state, translation, ctx)) <= 0) + return ret; + + if (state == PRE_CTRL_TO_PARAMS) { + /* + * In |translations|, the initial value for |ctx->action_type| must + * be NONE. + */ + if (!ossl_assert(ctx->action_type == NONE)) + return 0; + + /* The action type depends on the value of *p1 */ + if (ctx->p1 == -2) { + /* + * The OSSL_PARAMS getter needs space to store a copy of the kdf + * type string. We use |ctx->name_buf|, which has enough space + * allocated. + * + * (this wouldn't be needed if the OSSL_xxx_PARAM_KDF_TYPE + * had the data type OSSL_PARAM_UTF8_PTR) + */ |