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