summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2021-01-20 23:04:53 +0100
committerRichard Levitte <levitte@openssl.org>2021-02-23 13:41:48 +0100
commit9a1c4e41e8d3fd8fe9d1bd8eeb8b1e1df21da37f (patch)
treee7e936eba2359e076f5c73c6b8b24ab22b934386 /crypto
parent4d4928edd0758753e43294816ae6095975a6e5fa (diff)
EVP: Implement data-driven translation between known ctrl and OSSL_PARAMs
The idea is to make it as transparent as possible to call things like EVP_PKEY_CTX_ctrl() with a provider backed EVP_PKEY_CTX, or things like EVP_PKEY_get_bn_param() with a legacy EVP_PKEY. All these sorts of calls demand that we translate between ctrl commands and OSSL_PARAM keys, and treat the arguments appropriately. This implementation has it being as data driven as possible, thereby centralizing everything into one table of translation data, which supports both directions. Fixes #13528 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13913)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/evp/build.info2
-rw-r--r--crypto/evp/ctrl_params_translate.c2685
2 files changed, 2686 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)
+{