Add OSSL_PARAM_construct_from_text() and OSSL_PARAM_allocate_from_text()
These are utility functions that can be used to replace calls to ctrl_str type functions with get_params / set_params types of calls. They work by translating text values to something more suitable for OSSL_PARAM, and by interpretting parameter keys in a compatible fashion. Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/9303)
This commit is contained in:
parent
82bd7c2cbd
commit
246a1f3dfa
5 changed files with 399 additions and 1 deletions
|
@ -67,7 +67,7 @@ SOURCE[../providers/fips]=$CORE_COMMON
|
|||
|
||||
# Central utilities
|
||||
$UTIL_COMMON=\
|
||||
cryptlib.c params.c bsearch.c ex_data.c o_str.c \
|
||||
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
|
||||
$UTIL_DEFINE=$CPUIDDEF
|
||||
|
|
219
crypto/params_from_text.c
Normal file
219
crypto/params_from_text.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <string.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/params.h>
|
||||
|
||||
/*
|
||||
* When processing text to params, we're trying to be smart with numbers.
|
||||
* Instead of handling each specific separate integer type, we use a bignum
|
||||
* and ensure that it isn't larger than the expected size, and we then make
|
||||
* sure it is the expected size... if there is one given.
|
||||
* (if the size can be arbitrary, then we give whatever we have)
|
||||
*/
|
||||
|
||||
static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
|
||||
const char *value, size_t value_n,
|
||||
/* Output parameters */
|
||||
const OSSL_PARAM **paramdef, int *ishex,
|
||||
size_t *buf_n, BIGNUM **tmpbn)
|
||||
{
|
||||
const OSSL_PARAM *p;
|
||||
|
||||
/*
|
||||
* ishex is used to translate legacy style string controls in hex format
|
||||
* to octet string parameters.
|
||||
*/
|
||||
*ishex = strncmp(key, "hex", 3) == 0;
|
||||
|
||||
if (*ishex)
|
||||
key += 3;
|
||||
|
||||
p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key);
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
|
||||
switch (p->data_type) {
|
||||
case OSSL_PARAM_INTEGER:
|
||||
case OSSL_PARAM_UNSIGNED_INTEGER:
|
||||
if (*ishex)
|
||||
BN_hex2bn(tmpbn, value);
|
||||
else
|
||||
BN_dec2bn(tmpbn, value);
|
||||
|
||||
if (*tmpbn == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 2s complement negate, part 1
|
||||
*
|
||||
* BN_bn2nativepad puts the absolute value of the number in the
|
||||
* buffer, i.e. if it's negative, we need to deal with it. We do
|
||||
* it by subtracting 1 here and inverting the bytes in
|
||||
* construct_from_text() below.
|
||||
*/
|
||||
if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn)
|
||||
&& !BN_sub_word(*tmpbn, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*buf_n = BN_num_bytes(*tmpbn);
|
||||
|
||||
/*
|
||||
* TODO(v3.0) is this the right way to do this? This code expects
|
||||
* a zero data size to simply mean "arbitrary size".
|
||||
*/
|
||||
if (p->data_size > 0) {
|
||||
if (*buf_n >= p->data_size) {
|
||||
CRYPTOerr(0, CRYPTO_R_TOO_SMALL_BUFFER);
|
||||
/* Since this is a different error, we don't break */
|
||||
return 0;
|
||||
}
|
||||
/* Change actual size to become the desired size. */
|
||||
*buf_n = p->data_size;
|
||||
}
|
||||
break;
|
||||
case OSSL_PARAM_UTF8_STRING:
|
||||
if (*ishex) {
|
||||
CRYPTOerr(0, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
*buf_n = strlen(value) + 1;
|
||||
break;
|
||||
case OSSL_PARAM_OCTET_STRING:
|
||||
if (*ishex) {
|
||||
*buf_n = strlen(value) >> 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
|
||||
const char *value, size_t value_n, int ishex,
|
||||
void *buf, size_t buf_n, BIGNUM *tmpbn)
|
||||
{
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
||||
switch (paramdef->data_type) {
|
||||
case OSSL_PARAM_INTEGER:
|
||||
case OSSL_PARAM_UNSIGNED_INTEGER:
|
||||
/*
|
||||
{
|
||||
if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) {
|
||||
BN_free(a);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
BN_bn2nativepad(tmpbn, buf, buf_n);
|
||||
|
||||
/*
|
||||
* 2s complement negate, part two.
|
||||
*
|
||||
* Because we did the first part on the BIGNUM itself, we can just
|
||||
* invert all the bytes here and be done with it.
|
||||
*/
|
||||
if (paramdef->data_type == OSSL_PARAM_INTEGER
|
||||
&& BN_is_negative(tmpbn)) {
|
||||
unsigned char *cp;
|
||||
size_t i = buf_n;
|
||||
|
||||
for (cp = buf; i-- > 0; cp++)
|
||||
*cp ^= 0xFF;
|
||||
}
|
||||
break;
|
||||
case OSSL_PARAM_UTF8_STRING:
|
||||
strncpy(buf, value, buf_n);
|
||||
break;
|
||||
case OSSL_PARAM_OCTET_STRING:
|
||||
if (ishex) {
|
||||
size_t l = 0;
|
||||
|
||||
if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value))
|
||||
return 0;
|
||||
} else {
|
||||
memcpy(buf, value, buf_n);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*to = *paramdef;
|
||||
to->data = buf;
|
||||
to->data_size = buf_n;
|
||||
to->return_size = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_PARAM_construct_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n,
|
||||
void *buf, size_t *buf_n)
|
||||
{
|
||||
const OSSL_PARAM *paramdef = NULL;
|
||||
int ishex = 0;
|
||||
BIGNUM *tmpbn = NULL;
|
||||
int ok = 0;
|
||||
|
||||
if (to == NULL || paramdefs == NULL)
|
||||
return 0;
|
||||
|
||||
if (!prepare_from_text(paramdefs, key, value, value_n,
|
||||
¶mdef, &ishex, buf_n, &tmpbn))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The user gets the expected buffer size back even if the buffer isn't
|
||||
* allocated.
|
||||
*/
|
||||
if (buf == NULL)
|
||||
return 1;
|
||||
|
||||
ok = construct_from_text(to, paramdef, value, value_n, ishex,
|
||||
buf, *buf_n, tmpbn);
|
||||
BN_free(tmpbn);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n)
|
||||
{
|
||||
const OSSL_PARAM *paramdef = NULL;
|
||||
int ishex = 0;
|
||||
void *buf = NULL;
|
||||
size_t buf_n = 0;
|
||||
BIGNUM *tmpbn = NULL;
|
||||
int ok = 0;
|
||||
|
||||
if (to == NULL || paramdefs == NULL)
|
||||
return 0;
|
||||
|
||||
if (!prepare_from_text(paramdefs, key, value, value_n,
|
||||
¶mdef, &ishex, &buf_n, &tmpbn))
|
||||
return 0;
|
||||
|
||||
if ((buf = OPENSSL_malloc(buf_n)) == NULL) {
|
||||
CRYPTOerr(0, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = construct_from_text(to, paramdef, value, value_n, ishex,
|
||||
buf, buf_n, tmpbn);
|
||||
BN_free(tmpbn);
|
||||
return ok;
|
||||
}
|
167
doc/man3/OSSL_PARAM_construct_from_text.pod
Normal file
167
doc/man3/OSSL_PARAM_construct_from_text.pod
Normal file
|
@ -0,0 +1,167 @@
|
|||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
OSSL_PARAM_construct_from_text, OSSL_PARAM_allocate_from_text
|
||||
- OSSL_PARAM construction utilities
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/params.h>
|
||||
|
||||
int OSSL_PARAM_construct_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n,
|
||||
void *buf, size_t *buf_n)
|
||||
int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
With OpenSSL before version 3.0, parameters were passed down to or
|
||||
retrieved from algorithm implementations via control functions.
|
||||
Some of these control functions existed in variants that took string
|
||||
parameters, for example L<EVP_PKEY_CTX_ctrl_str(3)>.
|
||||
|
||||
OpenSSL 3.0 introduces a new mechanism to do the same thing with an
|
||||
array of parameters that contain name, value, value type and value
|
||||
size (see L<OSSL_PARAM(3)> for more information).
|
||||
|
||||
OSSL_PARAM_construct_from_text() takes a control I<key>, I<value> and
|
||||
value size I<value_n>, and given a parameter descriptor array
|
||||
I<paramdefs>, it converts the value to something suitable for
|
||||
L<OSSL_PARAM(3)> and stores that in the buffer I<buf>, and modifies
|
||||
the parameter I<to> to match.
|
||||
I<buf_n>, if not NULL, will be assigned the number of bytes used in
|
||||
I<buf>.
|
||||
If I<buf> is NULL, only I<buf_n> will be modified, everything else is
|
||||
left untouched, allowing a caller to find out how large the buffer
|
||||
should be.
|
||||
I<buf> needs to be correctly aligned for the type of the B<OSSL_PARAM>
|
||||
I<key>.
|
||||
|
||||
OSSL_PARAM_allocate_from_text() works like OSSL_PARAM_construct_from_text(),
|
||||
except it allocates the buffer internally.
|
||||
The caller must remember to free the data of I<to> when it's not
|
||||
useful any more.
|
||||
|
||||
For parameters having the type B<OSSL_PARAM_INTEGER>,
|
||||
B<OSSL_PARAM_UNSIGNED_INTEGER>, or B<OSSL_PARAM_OCTET_STRING>, both
|
||||
functions will interpret the I<value> differently if the key starts
|
||||
with "hex".
|
||||
In that case, the value is decoded first, and the result will be used
|
||||
as parameter value.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
OSSL_PARAM_construct_from_text() and OSSL_PARAM_allocate_from_text()
|
||||
returns 1 on success, and 0 on error.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
The parameter descriptor array comes from functions dedicated to
|
||||
return them.
|
||||
The following B<OSSL_PARAM> attributes are used:
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<key>
|
||||
|
||||
=item I<data>
|
||||
|
||||
=item I<data_size>
|
||||
|
||||
=back
|
||||
|
||||
All other attributes are ignored.
|
||||
|
||||
The I<data_size> attribute can be zero, meaning that the parameter it
|
||||
describes expects arbitrary length data.
|
||||
|
||||
=head1 EXAMPLE
|
||||
|
||||
Code that looked like this:
|
||||
|
||||
int mac_ctrl_string(EVP_PKEY_CTX *ctx, const char *value)
|
||||
{
|
||||
int rv;
|
||||
char *stmp, *vtmp = NULL;
|
||||
stmp = OPENSSL_strdup(value);
|
||||
if (!stmp)
|
||||
return -1;
|
||||
vtmp = strchr(stmp, ':');
|
||||
if (vtmp) {
|
||||
*vtmp = 0;
|
||||
vtmp++;
|
||||
}
|
||||
rv = EVP_MAC_ctrl_str(ctx, stmp, vtmp);
|
||||
OPENSSL_free(stmp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
|
||||
char *macopt;
|
||||
for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) {
|
||||
macopt = sk_OPENSSL_STRING_value(macopts, i);
|
||||
if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
|
||||
BIO_printf(bio_err,
|
||||
"MAC parameter error \"%s\"\n", macopt);
|
||||
ERR_print_errors(bio_err);
|
||||
goto mac_end;
|
||||
}
|
||||
}
|
||||
|
||||
Can be written like this instead:
|
||||
|
||||
OSSL_PARAM *params =
|
||||
OPENSSL_zalloc(sizeof(OSSL_PARAM)
|
||||
* (sk_OPENSSL_STRING_num(opts) + 1));
|
||||
const OSSL_PARAM *paramdefs = EVP_MAC_CTX_set_param_types(mac);
|
||||
size_t params_n;
|
||||
|
||||
for (params_n = 0; params_n < (size_t)sk_OPENSSL_STRING_num(opts);
|
||||
params_n++) {
|
||||
char *opt = sk_OPENSSL_STRING_value(opts, (int)params_n);
|
||||
char *stmp, *vtmp = NULL;
|
||||
|
||||
if ((stmp = OPENSSL_strdup(opt)) == NULL
|
||||
|| (vtmp = strchr(stmp, ':')) == NULL
|
||||
|| (*vtmp++ = '\0') /* Always zero */
|
||||
|| !OSSL_PARAM_allocate_from_text(¶ms[params_n],
|
||||
paramdefs,
|
||||
stmp, vtmp, strlen(vtmp))) {
|
||||
BIO_printf(bio_err, "MAC parameter error '%s'\n", opt);
|
||||
ERR_print_errors(bio_err);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
params[params_n] = OSSL_PARAM_construct_end();
|
||||
if (!EVP_MAC_CTX_set_params(ctx, params)) {
|
||||
BIO_printf(bio_err, "MAC parameter error\n");
|
||||
ERR_print_errors(bio_err);
|
||||
goto err;
|
||||
}
|
||||
for (; params_n-- > 0;) {
|
||||
OPENSSL_free(params[params_n].data);
|
||||
}
|
||||
OPENSSL_free(params);
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<OSSL_PARAM(3)>, L<OSSL_PARAM_TYPE(3)>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2019 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
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
|
@ -89,6 +89,16 @@ OSSL_PARAM OSSL_PARAM_construct_octet_ptr(const char *key, void **buf,
|
|||
size_t bsize);
|
||||
OSSL_PARAM OSSL_PARAM_construct_end(void);
|
||||
|
||||
int OSSL_PARAM_construct_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n,
|
||||
void *buf, size_t *buf_n);
|
||||
int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
|
||||
const OSSL_PARAM *paramdefs,
|
||||
const char *key, const char *value,
|
||||
size_t value_n);
|
||||
|
||||
int OSSL_PARAM_get_int(const OSSL_PARAM *p, int *val);
|
||||
int OSSL_PARAM_get_uint(const OSSL_PARAM *p, unsigned int *val);
|
||||
int OSSL_PARAM_get_long(const OSSL_PARAM *p, long int *val);
|
||||
|
|
|
@ -4708,3 +4708,5 @@ EC_KEY_new_ex 4817 3_0_0 EXIST::FUNCTION:EC
|
|||
EC_KEY_new_by_curve_name_ex 4818 3_0_0 EXIST::FUNCTION:EC
|
||||
OPENSSL_hexstr2buf_ex 4819 3_0_0 EXIST::FUNCTION:
|
||||
OPENSSL_buf2hexstr_ex 4820 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_PARAM_construct_from_text 4821 3_0_0 EXIST::FUNCTION:
|
||||
OSSL_PARAM_allocate_from_text 4822 3_0_0 EXIST::FUNCTION:
|
||||
|
|
Loading…
Reference in a new issue