The branch master has been updated via 246a1f3dfafc4a377bc7d7da65d9f8981a696abd (commit) via 82bd7c2cbd3a4b38321fb9053b8aa0f5d100cf54 (commit) from a42cb4ba8aa74757b526af2cad2ac09b493df3fb (commit)
- Log ----------------------------------------------------------------- commit 246a1f3dfafc4a377bc7d7da65d9f8981a696abd Author: Richard Levitte <levi...@openssl.org> Date: Wed Jul 3 18:42:21 2019 +0200 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.d...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/9303) commit 82bd7c2cbd3a4b38321fb9053b8aa0f5d100cf54 Author: Richard Levitte <levi...@openssl.org> Date: Wed Jul 3 18:40:17 2019 +0200 Add OPENSSL_hexstr2buf_ex() and OPENSSL_buf2hexstr_ex() They do the same thing as OPENSSL_hexstr2buf() and OPENSSL_buf2hexstr(), except they take a result buffer from the caller. We take the opportunity to break out the documentation of the hex to / from buffer conversion routines from the OPENSSL_malloc() file to its own file. These routines aren't memory allocation routines per se. Reviewed-by: Paul Dale <paul.d...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/9303) ----------------------------------------------------------------------- Summary of changes: crypto/build.info | 2 +- crypto/cpt_err.c | 2 + crypto/err/openssl.txt | 3 + crypto/o_str.c | 121 ++++++++++----- crypto/params_from_text.c | 219 ++++++++++++++++++++++++++++ doc/man3/OPENSSL_hexchar2int.pod | 74 ++++++++++ doc/man3/OPENSSL_malloc.pod | 20 --- doc/man3/OSSL_PARAM_construct_from_text.pod | 167 +++++++++++++++++++++ include/openssl/crypto.h | 8 +- include/openssl/cryptoerr.h | 3 + include/openssl/params.h | 10 ++ util/libcrypto.num | 4 + 12 files changed, 574 insertions(+), 59 deletions(-) create mode 100644 crypto/params_from_text.c create mode 100644 doc/man3/OPENSSL_hexchar2int.pod create mode 100644 doc/man3/OSSL_PARAM_construct_from_text.pod diff --git a/crypto/build.info b/crypto/build.info index 0b203a7f93..2130382034 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -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 diff --git a/crypto/cpt_err.c b/crypto/cpt_err.c index fdf0e6ebce..012f181d2a 100644 --- a/crypto/cpt_err.c +++ b/crypto/cpt_err.c @@ -40,6 +40,8 @@ static const ERR_STRING_DATA CRYPTO_str_reasons[] = { {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_TOO_MANY_BYTES), "too many bytes"}, {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_TOO_MANY_RECORDS), "too many records"}, + {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_TOO_SMALL_BUFFER), + "too small buffer"}, {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_ZERO_LENGTH_NUMBER), "zero length number"}, {0, NULL} diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index f6e5a7593e..61ad994a8d 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -391,8 +391,10 @@ CRYPTO_F_GET_AND_LOCK:113:get_and_lock CRYPTO_F_GET_PROVIDER_STORE:133:get_provider_store CRYPTO_F_OPENSSL_ATEXIT:114:OPENSSL_atexit CRYPTO_F_OPENSSL_BUF2HEXSTR:117:OPENSSL_buf2hexstr +CRYPTO_F_OPENSSL_BUF2HEXSTR_EX:153: CRYPTO_F_OPENSSL_FOPEN:119:openssl_fopen CRYPTO_F_OPENSSL_HEXSTR2BUF:118:OPENSSL_hexstr2buf +CRYPTO_F_OPENSSL_HEXSTR2BUF_EX:154: CRYPTO_F_OPENSSL_INIT_CRYPTO:116:OPENSSL_init_crypto CRYPTO_F_OPENSSL_LH_NEW:126:OPENSSL_LH_new CRYPTO_F_OPENSSL_SK_DEEP_COPY:127:OPENSSL_sk_deep_copy @@ -2243,6 +2245,7 @@ CRYPTO_R_SECURE_MALLOC_FAILURE:111:secure malloc failure CRYPTO_R_STRING_TOO_LONG:112:string too long CRYPTO_R_TOO_MANY_BYTES:113:too many bytes CRYPTO_R_TOO_MANY_RECORDS:114:too many records +CRYPTO_R_TOO_SMALL_BUFFER:116:too small buffer CRYPTO_R_ZERO_LENGTH_NUMBER:115:zero length number CT_R_BASE64_DECODE_ERROR:108:base64 decode error CT_R_INVALID_LOG_ID_LENGTH:100:invalid log id length diff --git a/crypto/o_str.c b/crypto/o_str.c index c24524f892..6780188cda 100644 --- a/crypto/o_str.c +++ b/crypto/o_str.c @@ -132,76 +132,125 @@ int OPENSSL_hexchar2int(unsigned char c) /* * Give a string of hex digits convert to a buffer */ -unsigned char *OPENSSL_hexstr2buf(const char *str, long *len) +int OPENSSL_hexstr2buf_ex(unsigned char *buf, size_t buf_n, size_t *buflen, + const char *str) { - unsigned char *hexbuf, *q; + unsigned char *q; unsigned char ch, cl; int chi, cli; const unsigned char *p; - size_t s; + size_t cnt; - s = strlen(str); - if ((hexbuf = OPENSSL_malloc(s >> 1)) == NULL) { - CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE); - return NULL; - } - for (p = (const unsigned char *)str, q = hexbuf; *p; ) { + for (p = (const unsigned char *)str, q = buf, cnt = 0; *p; ) { ch = *p++; if (ch == ':') continue; cl = *p++; if (!cl) { - CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, + CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF_EX, CRYPTO_R_ODD_NUMBER_OF_DIGITS); - OPENSSL_free(hexbuf); - return NULL; + return 0; } cli = OPENSSL_hexchar2int(cl); chi = OPENSSL_hexchar2int(ch); if (cli < 0 || chi < 0) { - OPENSSL_free(hexbuf); - CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT); - return NULL; + CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF_EX, + CRYPTO_R_ILLEGAL_HEX_DIGIT); + return 0; + } + cnt++; + if (q != NULL) { + if (cnt > buf_n) { + CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF_EX, + CRYPTO_R_TOO_SMALL_BUFFER); + return 0; + } + *q++ = (unsigned char)((chi << 4) | cli); } - *q++ = (unsigned char)((chi << 4) | cli); } - if (len) - *len = q - hexbuf; - return hexbuf; + if (buflen != NULL) + *buflen = cnt; + return 1; } -/* - * Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its - * hex representation @@@ (Contents of buffer are always kept in ASCII, also - * on EBCDIC machines) - */ -char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len) +unsigned char *OPENSSL_hexstr2buf(const char *str, long *buflen) +{ + unsigned char *buf; + size_t buf_n, tmp_buflen; + + buf_n = strlen(str) >> 1; + if ((buf = OPENSSL_malloc(buf_n)) == NULL) { + CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (buflen != NULL) + *buflen = 0; + tmp_buflen = 0; + if (OPENSSL_hexstr2buf_ex(buf, buf_n, &tmp_buflen, str)) { + if (buflen != NULL) + *buflen = (long)tmp_buflen; + return buf; + } + OPENSSL_free(buf); + return NULL; +} + +int OPENSSL_buf2hexstr_ex(char *str, size_t str_n, size_t *strlen, + const unsigned char *buf, size_t buflen) { static const char hexdig[] = "0123456789ABCDEF"; - char *tmp, *q; const unsigned char *p; - int i; + char *q; + size_t i; - if (len == 0) - return OPENSSL_zalloc(1); + if (strlen != NULL) + *strlen = buflen * 3; + if (str == NULL) + return 1; - if ((tmp = OPENSSL_malloc(len * 3)) == NULL) { - CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR, ERR_R_MALLOC_FAILURE); - return NULL; + if (str_n < (unsigned long)buflen * 3) { + CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR_EX, CRYPTO_R_TOO_SMALL_BUFFER); + return 0; } - q = tmp; - for (i = 0, p = buffer; i < len; i++, p++) { + + q = str; + for (i = 0, p = buf; i < buflen; i++, p++) { *q++ = hexdig[(*p >> 4) & 0xf]; *q++ = hexdig[*p & 0xf]; *q++ = ':'; } q[-1] = 0; #ifdef CHARSET_EBCDIC - ebcdic2ascii(tmp, tmp, q - tmp - 1); + ebcdic2ascii(str, str, q - str - 1); #endif + return 1; +} + +/* + * Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its + * hex representation @@@ (Contents of buffer are always kept in ASCII, also + * on EBCDIC machines) + */ +char *OPENSSL_buf2hexstr(const unsigned char *buf, long buflen) +{ + char *tmp; + size_t tmp_n; + + if (buflen == 0) + return OPENSSL_zalloc(1); + + tmp_n = buflen * 3; + if ((tmp = OPENSSL_malloc(tmp_n)) == NULL) { + CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR, ERR_R_MALLOC_FAILURE); + return NULL; + } - return tmp; + if (OPENSSL_buf2hexstr_ex(tmp, tmp_n, NULL, buf, buflen)) + return tmp; + OPENSSL_free(tmp); + return NULL; } int openssl_strerror_r(int errnum, char *buf, size_t buflen) diff --git a/crypto/params_from_text.c b/crypto/params_from_text.c new file mode 100644 index 0000000000..2a861c94fe --- /dev/null +++ b/crypto/params_from_text.c @@ -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; +} diff --git a/doc/man3/OPENSSL_hexchar2int.pod b/doc/man3/OPENSSL_hexchar2int.pod new file mode 100644 index 0000000000..930b32b61f --- /dev/null +++ b/doc/man3/OPENSSL_hexchar2int.pod @@ -0,0 +1,74 @@ +=pod + +=head1 NAME + +OPENSSL_hexchar2int, +OPENSSL_hexstr2buf_ex, OPENSSL_hexstr2buf, +OPENSSL_buf2hexstr_ex, OPENSSL_buf2hexstr +- Hex encoding and decoding functions + +=head1 SYNOPSIS + + #include <openssl/crypto.h> + + int OPENSSL_hexchar2int(unsigned char c); + int OPENSSL_hexstr2buf_ex(unsigned char *buf, size_t buf_n, long *buflen, + const char *str); + unsigned char *OPENSSL_hexstr2buf(const char *str, long *len); + int OPENSSL_buf2hexstr_ex(char *str, size_t str_n, size_t *strlen, + const unsigned char *buf, long buflen); + char *OPENSSL_buf2hexstr(const unsigned char *buf, long buflen); + +=head1 DESCRIPTION + +OPENSSL_hexchar2int() converts a hexadecimal character to its numeric +equivalent. + +OPENSSL_hexstr2buf_ex() decodes the hex string B<str> and places the +resulting string of bytes in the given I<buf>. +I<buf_n> gives the size of the buffer. +If I<buflen> is not NULL, it is filled in with the result length. +To find out how large the result will be, call this function with NULL +for I<buf>. +Colons between two-character hex "bytes" are accepted and ignored. +An odd number of hex digits is an error. + +OPENSSL_hexstr2buf() does the same thing as OPENSSL_hexstr2buf_ex(), +but allocates the space for the result, and returns the result. +The memory is allocated by calling OPENSSL_malloc() and should be +released by calling OPENSSL_free(). + +OPENSSL_buf2hexstr_ex() encodes the contents of the given I<buf> with +length I<buflen> and places the resulting hexadecimal character string +in the given I<str>. +I<str_n> gives the size of the of the string buffer. +If I<strlen> is not NULL, it is filled in with the result length. +To find out how large the result will be, call this function with NULL +for I<str>. + +OPENSSL_buf2hexstr() does the same thing as OPENSSL_buf2hexstr_ex(), +but allocates the space for the result, and returns the result. +The memory is allocated by calling OPENSSL_malloc() and should be +released by calling OPENSSL_free(). + +=head1 RETURN VALUES + +OPENSSL_hexchar2int returns the value of a decoded hex character, +or -1 on error. + +OPENSSL_buf2hexstr() and OPENSSL_hexstr2buf() +return a pointer to allocated memory, or NULL on error. + +OPENSSL_buf2hexstr_ex() and OPENSSL_hexstr2buf_ex() return 1 on +success, or 0 on error. + +=head1 COPYRIGHT + +Copyright 2016-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 diff --git a/doc/man3/OPENSSL_malloc.pod b/doc/man3/OPENSSL_malloc.pod index 38edf49d4d..198251fcd7 100644 --- a/doc/man3/OPENSSL_malloc.pod +++ b/doc/man3/OPENSSL_malloc.pod @@ -8,7 +8,6 @@ OPENSSL_clear_realloc, OPENSSL_clear_free, OPENSSL_cleanse, CRYPTO_malloc, CRYPTO_zalloc, CRYPTO_realloc, CRYPTO_free, OPENSSL_strdup, OPENSSL_strndup, OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat, -OPENSSL_hexstr2buf, OPENSSL_buf2hexstr, OPENSSL_hexchar2int, CRYPTO_strdup, CRYPTO_strndup, OPENSSL_mem_debug_push, OPENSSL_mem_debug_pop, CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop, @@ -40,10 +39,6 @@ OPENSSL_MALLOC_FD void OPENSSL_clear_free(void *str, size_t num) void OPENSSL_cleanse(void *ptr, size_t len); - unsigned char *OPENSSL_hexstr2buf(const char *str, long *len); - char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len); - int OPENSSL_hexchar2int(unsigned char c); - void *CRYPTO_malloc(size_t num, const char *file, int line) void *CRYPTO_zalloc(size_t num, const char *file, int line) void *CRYPTO_realloc(void *p, size_t num, const char *file, int line) @@ -119,20 +114,6 @@ OPENSSL_strlcpy(), OPENSSL_strlcat() and OPENSSL_strnlen() are equivalents of the common C library functions and are provided for portability. -OPENSSL_hexstr2buf() parses B<str> as a hex string and returns a -pointer to the parsed value. The memory is allocated by calling -OPENSSL_malloc() and should be released by calling OPENSSL_free(). -If B<len> is not NULL, it is filled in with the output length. -Colons between two-character hex "bytes" are ignored. -An odd number of hex digits is an error. - -OPENSSL_buf2hexstr() takes the specified buffer and length, and returns -a hex string for value, or NULL on error. -B<Buffer> cannot be NULL; if B<len> is 0 an empty string is returned. - -OPENSSL_hexchar2int() converts a character to the hexadecimal equivalent, -or returns -1 on error. - If no allocations have been done, it is possible to "swap out" the default implementations for OPENSSL_malloc(), OPENSSL_realloc and OPENSSL_free() and replace them with alternate versions (hooks). @@ -216,7 +197,6 @@ OPENSSL_malloc(), OPENSSL_zalloc(), OPENSSL_realloc(), OPENSSL_clear_realloc(), CRYPTO_malloc(), CRYPTO_zalloc(), CRYPTO_realloc(), CRYPTO_clear_realloc(), -OPENSSL_buf2hexstr(), OPENSSL_hexstr2buf(), OPENSSL_strdup(), and OPENSSL_strndup() return a pointer to allocated memory or NULL on error. diff --git a/doc/man3/OSSL_PARAM_construct_from_text.pod b/doc/man3/OSSL_PARAM_construct_from_text.pod new file mode 100644 index 0000000000..28d5e6fc13 --- /dev/null +++ b/doc/man3/OSSL_PARAM_construct_from_text.pod @@ -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 diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index 875ee556c1..accb22f3b1 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -148,8 +148,12 @@ int CRYPTO_mem_ctrl(int mode); size_t OPENSSL_strlcpy(char *dst, const char *src, size_t siz); size_t OPENSSL_strlcat(char *dst, const char *src, size_t siz); size_t OPENSSL_strnlen(const char *str, size_t maxlen); -char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len); -unsigned char *OPENSSL_hexstr2buf(const char *str, long *len); +int OPENSSL_buf2hexstr_ex(char *str, size_t str_n, size_t *strlen, + const unsigned char *buf, size_t buflen); +char *OPENSSL_buf2hexstr(const unsigned char *buf, long buflen); +int OPENSSL_hexstr2buf_ex(unsigned char *buf, size_t buf_n, size_t *buflen, + const char *str); +unsigned char *OPENSSL_hexstr2buf(const char *str, long *buflen); int OPENSSL_hexchar2int(unsigned char c); # define OPENSSL_MALLOC_MAX_NELEMS(type) (((1U<<(sizeof(int)*8-1))-1)/sizeof(type)) diff --git a/include/openssl/cryptoerr.h b/include/openssl/cryptoerr.h index 9fdf52c0c1..15071e2741 100644 --- a/include/openssl/cryptoerr.h +++ b/include/openssl/cryptoerr.h @@ -40,8 +40,10 @@ int ERR_load_CRYPTO_strings(void); # define CRYPTO_F_GET_PROVIDER_STORE 0 # define CRYPTO_F_OPENSSL_ATEXIT 0 # define CRYPTO_F_OPENSSL_BUF2HEXSTR 0 +# define CRYPTO_F_OPENSSL_BUF2HEXSTR_EX 0 # define CRYPTO_F_OPENSSL_FOPEN 0 # define CRYPTO_F_OPENSSL_HEXSTR2BUF 0 +# define CRYPTO_F_OPENSSL_HEXSTR2BUF_EX 0 # define CRYPTO_F_OPENSSL_INIT_CRYPTO 0 # define CRYPTO_F_OPENSSL_LH_NEW 0 # define CRYPTO_F_OPENSSL_SK_DEEP_COPY 0 @@ -89,6 +91,7 @@ int ERR_load_CRYPTO_strings(void); # define CRYPTO_R_STRING_TOO_LONG 112 # define CRYPTO_R_TOO_MANY_BYTES 113 # define CRYPTO_R_TOO_MANY_RECORDS 114 +# define CRYPTO_R_TOO_SMALL_BUFFER 116 # define CRYPTO_R_ZERO_LENGTH_NUMBER 115 #endif diff --git a/include/openssl/params.h b/include/openssl/params.h index 0e830dee0d..8293ee2cf0 100644 --- a/include/openssl/params.h +++ b/include/openssl/params.h @@ -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); diff --git a/util/libcrypto.num b/util/libcrypto.num index c99a69ab22..ac861fec6b 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4706,3 +4706,7 @@ EC_GROUP_new_ex 4815 3_0_0 EXIST::FUNCTION:EC EC_GROUP_new_by_curve_name_ex 4816 3_0_0 EXIST::FUNCTION:EC 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: