1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci */ 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <openssl/ebcdic.h> 13e1051a39Sopenharmony_ci#include <openssl/err.h> 14e1051a39Sopenharmony_ci#include <openssl/params.h> 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci/* 17e1051a39Sopenharmony_ci * When processing text to params, we're trying to be smart with numbers. 18e1051a39Sopenharmony_ci * Instead of handling each specific separate integer type, we use a bignum 19e1051a39Sopenharmony_ci * and ensure that it isn't larger than the expected size, and we then make 20e1051a39Sopenharmony_ci * sure it is the expected size... if there is one given. 21e1051a39Sopenharmony_ci * (if the size can be arbitrary, then we give whatever we have) 22e1051a39Sopenharmony_ci */ 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_cistatic int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key, 25e1051a39Sopenharmony_ci const char *value, size_t value_n, 26e1051a39Sopenharmony_ci /* Output parameters */ 27e1051a39Sopenharmony_ci const OSSL_PARAM **paramdef, int *ishex, 28e1051a39Sopenharmony_ci size_t *buf_n, BIGNUM **tmpbn, int *found) 29e1051a39Sopenharmony_ci{ 30e1051a39Sopenharmony_ci const OSSL_PARAM *p; 31e1051a39Sopenharmony_ci size_t buf_bits; 32e1051a39Sopenharmony_ci int r; 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_ci /* 35e1051a39Sopenharmony_ci * ishex is used to translate legacy style string controls in hex format 36e1051a39Sopenharmony_ci * to octet string parameters. 37e1051a39Sopenharmony_ci */ 38e1051a39Sopenharmony_ci *ishex = strncmp(key, "hex", 3) == 0; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ci if (*ishex) 41e1051a39Sopenharmony_ci key += 3; 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ci p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key); 44e1051a39Sopenharmony_ci if (found != NULL) 45e1051a39Sopenharmony_ci *found = p != NULL; 46e1051a39Sopenharmony_ci if (p == NULL) 47e1051a39Sopenharmony_ci return 0; 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci switch (p->data_type) { 50e1051a39Sopenharmony_ci case OSSL_PARAM_INTEGER: 51e1051a39Sopenharmony_ci case OSSL_PARAM_UNSIGNED_INTEGER: 52e1051a39Sopenharmony_ci if (*ishex) 53e1051a39Sopenharmony_ci r = BN_hex2bn(tmpbn, value); 54e1051a39Sopenharmony_ci else 55e1051a39Sopenharmony_ci r = BN_asc2bn(tmpbn, value); 56e1051a39Sopenharmony_ci 57e1051a39Sopenharmony_ci if (r == 0 || *tmpbn == NULL) 58e1051a39Sopenharmony_ci return 0; 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ci if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER 61e1051a39Sopenharmony_ci && BN_is_negative(*tmpbn)) { 62e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE); 63e1051a39Sopenharmony_ci return 0; 64e1051a39Sopenharmony_ci } 65e1051a39Sopenharmony_ci 66e1051a39Sopenharmony_ci /* 67e1051a39Sopenharmony_ci * 2's complement negate, part 1 68e1051a39Sopenharmony_ci * 69e1051a39Sopenharmony_ci * BN_bn2nativepad puts the absolute value of the number in the 70e1051a39Sopenharmony_ci * buffer, i.e. if it's negative, we need to deal with it. We do 71e1051a39Sopenharmony_ci * it by subtracting 1 here and inverting the bytes in 72e1051a39Sopenharmony_ci * construct_from_text() below. 73e1051a39Sopenharmony_ci * To subtract 1 from an absolute value of a negative number we 74e1051a39Sopenharmony_ci * actually have to add 1: -3 - 1 = -4, |-3| = 3 + 1 = 4. 75e1051a39Sopenharmony_ci */ 76e1051a39Sopenharmony_ci if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn) 77e1051a39Sopenharmony_ci && !BN_add_word(*tmpbn, 1)) { 78e1051a39Sopenharmony_ci return 0; 79e1051a39Sopenharmony_ci } 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_ci buf_bits = (size_t)BN_num_bits(*tmpbn); 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci /* 84e1051a39Sopenharmony_ci * Compensate for cases where the most significant bit in 85e1051a39Sopenharmony_ci * the resulting OSSL_PARAM buffer will be set after the 86e1051a39Sopenharmony_ci * BN_bn2nativepad() call, as the implied sign may not be 87e1051a39Sopenharmony_ci * correct after the second part of the 2's complement 88e1051a39Sopenharmony_ci * negation has been performed. 89e1051a39Sopenharmony_ci * We fix these cases by extending the buffer by one byte 90e1051a39Sopenharmony_ci * (8 bits), which will give some padding. The second part 91e1051a39Sopenharmony_ci * of the 2's complement negation will do the rest. 92e1051a39Sopenharmony_ci */ 93e1051a39Sopenharmony_ci if (p->data_type == OSSL_PARAM_INTEGER && buf_bits % 8 == 0) 94e1051a39Sopenharmony_ci buf_bits += 8; 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci *buf_n = (buf_bits + 7) / 8; 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci /* 99e1051a39Sopenharmony_ci * A zero data size means "arbitrary size", so only do the 100e1051a39Sopenharmony_ci * range checking if a size is specified. 101e1051a39Sopenharmony_ci */ 102e1051a39Sopenharmony_ci if (p->data_size > 0) { 103e1051a39Sopenharmony_ci if (buf_bits > p->data_size * 8) { 104e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER); 105e1051a39Sopenharmony_ci /* Since this is a different error, we don't break */ 106e1051a39Sopenharmony_ci return 0; 107e1051a39Sopenharmony_ci } 108e1051a39Sopenharmony_ci /* Change actual size to become the desired size. */ 109e1051a39Sopenharmony_ci *buf_n = p->data_size; 110e1051a39Sopenharmony_ci } 111e1051a39Sopenharmony_ci break; 112e1051a39Sopenharmony_ci case OSSL_PARAM_UTF8_STRING: 113e1051a39Sopenharmony_ci if (*ishex) { 114e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 115e1051a39Sopenharmony_ci return 0; 116e1051a39Sopenharmony_ci } 117e1051a39Sopenharmony_ci *buf_n = strlen(value) + 1; 118e1051a39Sopenharmony_ci break; 119e1051a39Sopenharmony_ci case OSSL_PARAM_OCTET_STRING: 120e1051a39Sopenharmony_ci if (*ishex) { 121e1051a39Sopenharmony_ci *buf_n = strlen(value) >> 1; 122e1051a39Sopenharmony_ci } else { 123e1051a39Sopenharmony_ci *buf_n = value_n; 124e1051a39Sopenharmony_ci } 125e1051a39Sopenharmony_ci break; 126e1051a39Sopenharmony_ci } 127e1051a39Sopenharmony_ci 128e1051a39Sopenharmony_ci return 1; 129e1051a39Sopenharmony_ci} 130e1051a39Sopenharmony_ci 131e1051a39Sopenharmony_cistatic int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef, 132e1051a39Sopenharmony_ci const char *value, size_t value_n, int ishex, 133e1051a39Sopenharmony_ci void *buf, size_t buf_n, BIGNUM *tmpbn) 134e1051a39Sopenharmony_ci{ 135e1051a39Sopenharmony_ci if (buf == NULL) 136e1051a39Sopenharmony_ci return 0; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci if (buf_n > 0) { 139e1051a39Sopenharmony_ci switch (paramdef->data_type) { 140e1051a39Sopenharmony_ci case OSSL_PARAM_INTEGER: 141e1051a39Sopenharmony_ci case OSSL_PARAM_UNSIGNED_INTEGER: 142e1051a39Sopenharmony_ci /* 143e1051a39Sopenharmony_ci { 144e1051a39Sopenharmony_ci if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) { 145e1051a39Sopenharmony_ci BN_free(a); 146e1051a39Sopenharmony_ci break; 147e1051a39Sopenharmony_ci } 148e1051a39Sopenharmony_ci */ 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_ci BN_bn2nativepad(tmpbn, buf, buf_n); 151e1051a39Sopenharmony_ci 152e1051a39Sopenharmony_ci /* 153e1051a39Sopenharmony_ci * 2's complement negation, part two. 154e1051a39Sopenharmony_ci * 155e1051a39Sopenharmony_ci * Because we did the first part on the BIGNUM itself, we can just 156e1051a39Sopenharmony_ci * invert all the bytes here and be done with it. 157e1051a39Sopenharmony_ci */ 158e1051a39Sopenharmony_ci if (paramdef->data_type == OSSL_PARAM_INTEGER 159e1051a39Sopenharmony_ci && BN_is_negative(tmpbn)) { 160e1051a39Sopenharmony_ci unsigned char *cp; 161e1051a39Sopenharmony_ci size_t i = buf_n; 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci for (cp = buf; i-- > 0; cp++) 164e1051a39Sopenharmony_ci *cp ^= 0xFF; 165e1051a39Sopenharmony_ci } 166e1051a39Sopenharmony_ci break; 167e1051a39Sopenharmony_ci case OSSL_PARAM_UTF8_STRING: 168e1051a39Sopenharmony_ci#ifdef CHARSET_EBCDIC 169e1051a39Sopenharmony_ci ebcdic2ascii(buf, value, buf_n); 170e1051a39Sopenharmony_ci#else 171e1051a39Sopenharmony_ci strncpy(buf, value, buf_n); 172e1051a39Sopenharmony_ci#endif 173e1051a39Sopenharmony_ci /* Don't count the terminating NUL byte as data */ 174e1051a39Sopenharmony_ci buf_n--; 175e1051a39Sopenharmony_ci break; 176e1051a39Sopenharmony_ci case OSSL_PARAM_OCTET_STRING: 177e1051a39Sopenharmony_ci if (ishex) { 178e1051a39Sopenharmony_ci size_t l = 0; 179e1051a39Sopenharmony_ci 180e1051a39Sopenharmony_ci if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value, ':')) 181e1051a39Sopenharmony_ci return 0; 182e1051a39Sopenharmony_ci } else { 183e1051a39Sopenharmony_ci memcpy(buf, value, buf_n); 184e1051a39Sopenharmony_ci } 185e1051a39Sopenharmony_ci break; 186e1051a39Sopenharmony_ci } 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_ci *to = *paramdef; 190e1051a39Sopenharmony_ci to->data = buf; 191e1051a39Sopenharmony_ci to->data_size = buf_n; 192e1051a39Sopenharmony_ci to->return_size = OSSL_PARAM_UNMODIFIED; 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_ci return 1; 195e1051a39Sopenharmony_ci} 196e1051a39Sopenharmony_ci 197e1051a39Sopenharmony_ciint OSSL_PARAM_allocate_from_text(OSSL_PARAM *to, 198e1051a39Sopenharmony_ci const OSSL_PARAM *paramdefs, 199e1051a39Sopenharmony_ci const char *key, const char *value, 200e1051a39Sopenharmony_ci size_t value_n, int *found) 201e1051a39Sopenharmony_ci{ 202e1051a39Sopenharmony_ci const OSSL_PARAM *paramdef = NULL; 203e1051a39Sopenharmony_ci int ishex = 0; 204e1051a39Sopenharmony_ci void *buf = NULL; 205e1051a39Sopenharmony_ci size_t buf_n = 0; 206e1051a39Sopenharmony_ci BIGNUM *tmpbn = NULL; 207e1051a39Sopenharmony_ci int ok = 0; 208e1051a39Sopenharmony_ci 209e1051a39Sopenharmony_ci if (to == NULL || paramdefs == NULL) 210e1051a39Sopenharmony_ci return 0; 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci if (!prepare_from_text(paramdefs, key, value, value_n, 213e1051a39Sopenharmony_ci ¶mdef, &ishex, &buf_n, &tmpbn, found)) 214e1051a39Sopenharmony_ci goto err; 215e1051a39Sopenharmony_ci 216e1051a39Sopenharmony_ci if ((buf = OPENSSL_zalloc(buf_n > 0 ? buf_n : 1)) == NULL) { 217e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 218e1051a39Sopenharmony_ci goto err; 219e1051a39Sopenharmony_ci } 220e1051a39Sopenharmony_ci 221e1051a39Sopenharmony_ci ok = construct_from_text(to, paramdef, value, value_n, ishex, 222e1051a39Sopenharmony_ci buf, buf_n, tmpbn); 223e1051a39Sopenharmony_ci BN_free(tmpbn); 224e1051a39Sopenharmony_ci if (!ok) 225e1051a39Sopenharmony_ci OPENSSL_free(buf); 226e1051a39Sopenharmony_ci return ok; 227e1051a39Sopenharmony_ci err: 228e1051a39Sopenharmony_ci BN_free(tmpbn); 229e1051a39Sopenharmony_ci return 0; 230e1051a39Sopenharmony_ci} 231