Add EVP_PKEY_gettable_params support for accessing EVP_PKEY key data fields
Currently only RSA, EC and ECX are supported (DH and DSA need to be added to the keygen
PR's seperately because the fields supported have changed significantly).
The API's require the keys to be provider based.
Made the keymanagement export and get_params functions share the same code by supplying
support functions that work for both a OSSL_PARAM_BLD as well as a OSSL_PARAM[].
This approach means that complex code is not required to build an
empty OSSL_PARAM[] with the correct sized fields before then doing a second
pass to populate the array.
The RSA factor arrays have been changed to use unique key names to simplify the interface
needed by the user.
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11365)
diff --git a/crypto/build.info b/crypto/build.info
index a688248..baa31ee 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -70,7 +70,8 @@
$UTIL_COMMON=\
cryptlib.c params.c params_from_text.c bsearch.c ex_data.c o_str.c \
ctype.c threads_pthread.c threads_win.c threads_none.c initthread.c \
- context.c sparse_array.c asn1_dsa.c packet.c param_build.c $CPUIDASM
+ context.c sparse_array.c asn1_dsa.c packet.c param_build.c $CPUIDASM \
+ param_build_set.c
$UTIL_DEFINE=$CPUIDDEF
SOURCE[../libcrypto]=$UTIL_COMMON \
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 9ed238e..b176f10 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -1459,3 +1459,163 @@
return 0; /* No downgrade, but at least the key is restored */
}
#endif /* FIPS_MODE */
+
+const OSSL_PARAM *EVP_PKEY_gettable_params(EVP_PKEY *pkey)
+{
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL)
+ return 0;
+ return evp_keymgmt_gettable_params(pkey->keymgmt);
+}
+
+/*
+ * For the following methods param->return_size is set to a value
+ * larger than can be returned by the call to evp_keymgmt_get_params().
+ * If it is still this value then the parameter was ignored - and in this
+ * case it returns an error..
+ */
+
+int EVP_PKEY_get_bn_param(EVP_PKEY *pkey, const char *key_name, BIGNUM **bn)
+{
+ int ret = 0;
+ OSSL_PARAM params[2];
+ unsigned char buffer[2048];
+ /*
+ * Use -1 as the terminator here instead of sizeof(buffer) + 1 since
+ * -1 is less likely to be a valid value.
+ */
+ const size_t not_set = (size_t)-1;
+ unsigned char *buf = NULL;
+ size_t buf_sz = 0;
+
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL
+ || key_name == NULL
+ || bn == NULL)
+ return 0;
+
+ memset(buffer, 0, sizeof(buffer));
+ params[0] = OSSL_PARAM_construct_BN(key_name, buffer, sizeof(buffer));
+ /* If the return_size is still not_set then we know it was not found */
+ params[0].return_size = not_set;
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params)) {
+ if (params[0].return_size == not_set
+ || params[0].return_size == 0)
+ return 0;
+ buf_sz = params[0].return_size;
+ /*
+ * If it failed because the buffer was too small then allocate the
+ * required buffer size and retry.
+ */
+ buf = OPENSSL_zalloc(buf_sz);
+ if (buf == NULL)
+ return 0;
+ params[0].data = buf;
+ params[0].data_size = buf_sz;
+
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+ goto err;
+ }
+ /* Fail if the param was not found */
+ if (params[0].return_size == not_set)
+ goto err;
+ ret = OSSL_PARAM_get_BN(params, bn);
+err:
+ OPENSSL_free(buf);
+ return ret;
+}
+
+int EVP_PKEY_get_octet_string_param(EVP_PKEY *pkey, const char *key_name,
+ unsigned char *buf, size_t max_buf_sz,
+ size_t *out_sz)
+{
+ OSSL_PARAM params[2];
+ const size_t not_set = max_buf_sz + 1;
+
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL
+ || key_name == NULL)
+ return 0;
+
+ params[0] = OSSL_PARAM_construct_octet_string(key_name, buf, max_buf_sz);
+ params[0].return_size = not_set;
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+ return 0;
+ if (params[0].return_size == not_set)
+ return 0;
+ if (out_sz != NULL)
+ *out_sz = params[0].return_size;
+ return 1;
+}
+
+int EVP_PKEY_get_utf8_string_param(EVP_PKEY *pkey, const char *key_name,
+ char *str, size_t max_buf_sz,
+ size_t *out_sz)
+{
+ OSSL_PARAM params[2];
+ const size_t not_set = max_buf_sz + 1;
+
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL
+ || key_name == NULL)
+ return 0;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(key_name, str, max_buf_sz);
+ params[0].return_size = not_set;
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+ return 0;
+ if (params[0].return_size == not_set)
+ return 0;
+ if (out_sz != NULL)
+ *out_sz = params[0].return_size;
+ return 1;
+}
+
+int EVP_PKEY_get_int_param(EVP_PKEY *pkey, const char *key_name, int *out)
+{
+ OSSL_PARAM params[2];
+ const size_t not_set = sizeof(int) + 1;
+
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL
+ || key_name == NULL)
+ return 0;
+
+ params[0] = OSSL_PARAM_construct_int(key_name, out);
+ params[0].return_size = not_set;
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+ return 0;
+ if (params[0].return_size == not_set)
+ return 0;
+ return 1;
+}
+
+int EVP_PKEY_get_size_t_param(EVP_PKEY *pkey, const char *key_name, size_t *out)
+{
+ OSSL_PARAM params[2];
+ const size_t not_set = sizeof(size_t) + 1;
+
+ if (pkey == NULL
+ || pkey->keymgmt == NULL
+ || pkey->keydata == NULL
+ || key_name == NULL)
+ return 0;
+
+ params[0] = OSSL_PARAM_construct_size_t(key_name, out);
+ params[0].return_size = not_set;
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+ return 0;
+ if (params[0].return_size == not_set)
+ return 0;
+ return 1;
+}
diff --git a/crypto/param_build_set.c b/crypto/param_build_set.c
new file mode 100644
index 0000000..b74b0d5
--- /dev/null
+++ b/crypto/param_build_set.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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
+ */
+
+/*
+ * Key Management utility functions to share functionality between the export()
+ * and get_params() methods.
+ * export() uses OSSL_PARAM_BLD, and get_params() used the OSSL_PARAM[] to
+ * fill in parameter data for the same key and data fields.
+ */
+
+#include <openssl/core_names.h>
+#include "internal/param_build_set.h"
+
+DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM)
+
+int ossl_param_build_set_int(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+ const char *key, int num)
+{
+ if (bld != NULL)
+ return OSSL_PARAM_BLD_push_int(bld, key, num);
+ p = OSSL_PARAM_locate(p, key);
+ if (p != NULL)
+ return OSSL_PARAM_set_int(p, num);
+ return 1;
+}
+
+int ossl_param_build_set_utf8_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+ const char *key, const char *buf)
+{
+ if (bld != NULL)
+ return OSSL_PARAM_BLD_push_utf8_string(bld, key, buf, 0);
+ p = OSSL_PARAM_locate(p, key);
+ if (p != NULL)
+ return OSSL_PARAM_set_utf8_string(p, buf);
+ return 1;
+}
+
+int ossl_param_build_set_octet_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+ const char *key,
+ const unsigned char *data,
+ size_t data_len)
+{
+ if (bld != NULL)
+ return OSSL_PARAM_BLD_push_octet_string(bld, key, data, data_len);
+
+ p = OSSL_PARAM_locate(p, key);
+ if (p != NULL)
+ return OSSL_PARAM_set_octet_string(p, data, data_len);
+ return 1;
+}
+
+int ossl_param_build_set_bn_pad(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+ const char *key, const BIGNUM *bn, size_t sz)
+{
+ if (bld != NULL)
+ return OSSL_PARAM_BLD_push_BN_pad(bld, key, bn, sz);
+ p = OSSL_PARAM_locate(p, key);
+ if (p != NULL) {
+ if (sz > p->data_size)
+ return 0;
+ /* TODO(3.0) Change to use OSSL_PARAM_set_BN_pad */
+ p->data_size = sz;
+ return OSSL_PARAM_set_BN(p, bn);
+ }
+ return 1;
+}
+
+int ossl_param_build_set_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+ const char *key, const BIGNUM *bn)
+{
+ if (bld != NULL)
+ return OSSL_PARAM_BLD_push_BN(bld, key, bn);
+
+ p = OSSL_PARAM_locate(p, key);
+ if (p != NULL)
+ return OSSL_PARAM_set_BN(p, bn) > 0;
+ return 1;
+}
+
+int ossl_param_build_set_multi_key_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *params,
+ const char *names[],
+ STACK_OF(BIGNUM_const) *stk)
+{
+ int i, sz = sk_BIGNUM_const_num(stk);
+ OSSL_PARAM *p;
+
+
+ if (bld != NULL) {
+ for (i = 0; i < sz && names[i] != NULL; ++i) {
+ if (!OSSL_PARAM_BLD_push_BN(bld, names[i],
+ sk_BIGNUM_const_value(stk, i)))
+ return 0;
+ }
+ return 1;
+ }
+
+ for (i = 0; i < sz && names[i] != NULL; ++i) {
+ p = OSSL_PARAM_locate(params, names[i]);
+ if (p != NULL) {
+ if (!OSSL_PARAM_set_BN(p, sk_BIGNUM_const_value(stk, i)))
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/crypto/rsa/build.info b/crypto/rsa/build.info
index c1d1a37..7921202 100644
--- a/crypto/rsa/build.info
+++ b/crypto/rsa/build.info
@@ -2,7 +2,8 @@
$COMMON=rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_aid.c rsa_pk1.c \
rsa_none.c rsa_oaep.c rsa_chk.c rsa_pss.c rsa_x931.c rsa_crpt.c \
- rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c
+ rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c \
+ rsa_mp_names.c
SOURCE[../../libcrypto]=$COMMON\
rsa_saos.c rsa_err.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index ec8df4a..fb378ae 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -20,7 +20,7 @@
#include <openssl/bn.h>
#include <openssl/cms.h>
#include <openssl/core_names.h>
-#include "openssl/param_build.h"
+#include <openssl/param_build.h>
#include "crypto/asn1.h"
#include "crypto/evp.h"
#include "crypto/rsa.h"
@@ -1142,27 +1142,24 @@
goto err;
selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
- for (i = 0; i < numprimes; i++) {
+ for (i = 0; i < numprimes && rsa_mp_factor_names[i] != NULL; i++) {
const BIGNUM *num = sk_BIGNUM_const_value(primes, i);
- if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR,
- num))
+ if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_factor_names[i], num))
goto err;
}
- for (i = 0; i < numexps; i++) {
+ for (i = 0; i < numexps && rsa_mp_exp_names[i] != NULL; i++) {
const BIGNUM *num = sk_BIGNUM_const_value(exps, i);
- if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT,
- num))
+ if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_exp_names[i], num))
goto err;
}
- for (i = 0; i < numcoeffs; i++) {
+ for (i = 0; i < numcoeffs && rsa_mp_coeff_names[i] != NULL; i++) {
const BIGNUM *num = sk_BIGNUM_const_value(coeffs, i);
- if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT,
- num))
+ if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_coeff_names[i], num))
goto err;
}
}
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
index f68d38c..57a539c 100644
--- a/crypto/rsa/rsa_backend.c
+++ b/crypto/rsa/rsa_backend.c
@@ -20,19 +20,23 @@
DEFINE_STACK_OF(BIGNUM)
static int collect_numbers(STACK_OF(BIGNUM) *numbers,
- const OSSL_PARAM params[], const char *key)
+ const OSSL_PARAM params[], const char *names[])
{
const OSSL_PARAM *p = NULL;
+ int i;
if (numbers == NULL)
return 0;
- for (p = params; (p = OSSL_PARAM_locate_const(p, key)) != NULL; p++) {
- BIGNUM *tmp = NULL;
+ for (i = 0; names[i] != NULL; i++){
+ p = OSSL_PARAM_locate_const(params, names[i]);
+ if (p != NULL) {
+ BIGNUM *tmp = NULL;
- if (!OSSL_PARAM_get_BN(p, &tmp)
- || sk_BIGNUM_push(numbers, tmp) == 0)
- return 0;
+ if (!OSSL_PARAM_get_BN(p, &tmp)
+ || sk_BIGNUM_push(numbers, tmp) == 0)
+ return 0;
+ }
}
return 1;
@@ -65,11 +69,11 @@
if (is_private) {
if (!collect_numbers(factors = sk_BIGNUM_new_null(), params,
- OSSL_PKEY_PARAM_RSA_FACTOR)
+ rsa_mp_factor_names)
|| !collect_numbers(exps = sk_BIGNUM_new_null(), params,
- OSSL_PKEY_PARAM_RSA_EXPONENT)
+ rsa_mp_exp_names)
|| !collect_numbers(coeffs = sk_BIGNUM_new_null(), params,
- OSSL_PKEY_PARAM_RSA_COEFFICIENT))
+ rsa_mp_coeff_names))
goto err;
/* It's ok if this private key just has n, e and d */
diff --git a/crypto/rsa/rsa_mp_names.c b/crypto/rsa/rsa_mp_names.c
new file mode 100644
index 0000000..e69321a
--- /dev/null
+++ b/crypto/rsa/rsa_mp_names.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 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
+ */
+
+#include <openssl/core_names.h>
+#include "crypto/rsa.h"
+
+/*
+ * The following tables are constants used during RSA parameter building
+ * operations. It is easier to point to one of these fixed strings than have
+ * to dynamically add and generate the names on the fly.
+ */
+
+/*
+ * A fixed table of names for the RSA prime factors starting with
+ * P,Q and up to 8 additional primes.
+ */
+const char *rsa_mp_factor_names[] = {
+ OSSL_PKEY_PARAM_RSA_FACTOR1,
+ OSSL_PKEY_PARAM_RSA_FACTOR2,
+#ifndef FIPS_MODE
+ OSSL_PKEY_PARAM_RSA_FACTOR3,
+ OSSL_PKEY_PARAM_RSA_FACTOR4,
+ OSSL_PKEY_PARAM_RSA_FACTOR5,
+ OSSL_PKEY_PARAM_RSA_FACTOR6,
+ OSSL_PKEY_PARAM_RSA_FACTOR7,
+ OSSL_PKEY_PARAM_RSA_FACTOR8,
+ OSSL_PKEY_PARAM_RSA_FACTOR9,
+ OSSL_PKEY_PARAM_RSA_FACTOR10,
+#endif
+ NULL
+};
+
+/*
+ * A fixed table of names for the RSA exponents starting with
+ * DP,DQ and up to 8 additional exponents.
+ */
+const char *rsa_mp_exp_names[] = {
+ OSSL_PKEY_PARAM_RSA_EXPONENT1,
+ OSSL_PKEY_PARAM_RSA_EXPONENT2,
+#ifndef FIPS_MODE
+ OSSL_PKEY_PARAM_RSA_EXPONENT3,
+ OSSL_PKEY_PARAM_RSA_EXPONENT4,
+ OSSL_PKEY_PARAM_RSA_EXPONENT5,
+ OSSL_PKEY_PARAM_RSA_EXPONENT6,
+ OSSL_PKEY_PARAM_RSA_EXPONENT7,
+ OSSL_PKEY_PARAM_RSA_EXPONENT8,
+ OSSL_PKEY_PARAM_RSA_EXPONENT9,
+ OSSL_PKEY_PARAM_RSA_EXPONENT10,
+#endif
+ NULL
+};
+
+/*
+ * A fixed table of names for the RSA coefficients starting with
+ * QINV and up to 8 additional exponents.
+ */
+const char *rsa_mp_coeff_names[] = {
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT2,
+#ifndef FIPS_MODE
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT3,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT4,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT5,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT6,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT7,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT8,
+ OSSL_PKEY_PARAM_RSA_COEFFICIENT9,
+#endif
+ NULL
+};