1 | /* |
2 | * Copyright 2019 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/err.h> |
13 | #include <openssl/params.h> |
14 | |
15 | /* |
16 | * When processing text to params, we're trying to be smart with numbers. |
17 | * Instead of handling each specific separate integer type, we use a bignum |
18 | * and ensure that it isn't larger than the expected size, and we then make |
19 | * sure it is the expected size... if there is one given. |
20 | * (if the size can be arbitrary, then we give whatever we have) |
21 | */ |
22 | |
23 | static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key, |
24 | const char *value, size_t value_n, |
25 | /* Output parameters */ |
26 | const OSSL_PARAM **paramdef, int *ishex, |
27 | size_t *buf_n, BIGNUM **tmpbn) |
28 | { |
29 | const OSSL_PARAM *p; |
30 | |
31 | /* |
32 | * ishex is used to translate legacy style string controls in hex format |
33 | * to octet string parameters. |
34 | */ |
35 | *ishex = strncmp(key, "hex" , 3) == 0; |
36 | |
37 | if (*ishex) |
38 | key += 3; |
39 | |
40 | p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key); |
41 | if (p == NULL) |
42 | return 0; |
43 | |
44 | switch (p->data_type) { |
45 | case OSSL_PARAM_INTEGER: |
46 | case OSSL_PARAM_UNSIGNED_INTEGER: |
47 | if (*ishex) |
48 | BN_hex2bn(tmpbn, value); |
49 | else |
50 | BN_dec2bn(tmpbn, value); |
51 | |
52 | if (*tmpbn == NULL) |
53 | return 0; |
54 | |
55 | /* |
56 | * 2s complement negate, part 1 |
57 | * |
58 | * BN_bn2nativepad puts the absolute value of the number in the |
59 | * buffer, i.e. if it's negative, we need to deal with it. We do |
60 | * it by subtracting 1 here and inverting the bytes in |
61 | * construct_from_text() below. |
62 | */ |
63 | if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn) |
64 | && !BN_sub_word(*tmpbn, 1)) { |
65 | return 0; |
66 | } |
67 | |
68 | *buf_n = BN_num_bytes(*tmpbn); |
69 | |
70 | /* |
71 | * TODO(v3.0) is this the right way to do this? This code expects |
72 | * a zero data size to simply mean "arbitrary size". |
73 | */ |
74 | if (p->data_size > 0) { |
75 | if (*buf_n >= p->data_size) { |
76 | CRYPTOerr(0, CRYPTO_R_TOO_SMALL_BUFFER); |
77 | /* Since this is a different error, we don't break */ |
78 | return 0; |
79 | } |
80 | /* Change actual size to become the desired size. */ |
81 | *buf_n = p->data_size; |
82 | } |
83 | break; |
84 | case OSSL_PARAM_UTF8_STRING: |
85 | if (*ishex) { |
86 | CRYPTOerr(0, ERR_R_PASSED_INVALID_ARGUMENT); |
87 | return 0; |
88 | } |
89 | *buf_n = strlen(value) + 1; |
90 | break; |
91 | case OSSL_PARAM_OCTET_STRING: |
92 | if (*ishex) { |
93 | *buf_n = strlen(value) >> 1; |
94 | } else { |
95 | *buf_n = value_n; |
96 | } |
97 | break; |
98 | } |
99 | |
100 | return 1; |
101 | } |
102 | |
103 | static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef, |
104 | const char *value, size_t value_n, int ishex, |
105 | void *buf, size_t buf_n, BIGNUM *tmpbn) |
106 | { |
107 | if (buf == NULL) |
108 | return 0; |
109 | |
110 | if (buf_n > 0) { |
111 | switch (paramdef->data_type) { |
112 | case OSSL_PARAM_INTEGER: |
113 | case OSSL_PARAM_UNSIGNED_INTEGER: |
114 | /* |
115 | { |
116 | if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) { |
117 | BN_free(a); |
118 | break; |
119 | } |
120 | */ |
121 | |
122 | BN_bn2nativepad(tmpbn, buf, buf_n); |
123 | |
124 | /* |
125 | * 2s complement negate, part two. |
126 | * |
127 | * Because we did the first part on the BIGNUM itself, we can just |
128 | * invert all the bytes here and be done with it. |
129 | */ |
130 | if (paramdef->data_type == OSSL_PARAM_INTEGER |
131 | && BN_is_negative(tmpbn)) { |
132 | unsigned char *cp; |
133 | size_t i = buf_n; |
134 | |
135 | for (cp = buf; i-- > 0; cp++) |
136 | *cp ^= 0xFF; |
137 | } |
138 | break; |
139 | case OSSL_PARAM_UTF8_STRING: |
140 | strncpy(buf, value, buf_n); |
141 | break; |
142 | case OSSL_PARAM_OCTET_STRING: |
143 | if (ishex) { |
144 | size_t l = 0; |
145 | |
146 | if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value)) |
147 | return 0; |
148 | } else { |
149 | memcpy(buf, value, buf_n); |
150 | } |
151 | break; |
152 | } |
153 | } |
154 | |
155 | *to = *paramdef; |
156 | to->data = buf; |
157 | to->data_size = buf_n; |
158 | to->return_size = 0; |
159 | |
160 | return 1; |
161 | } |
162 | |
163 | int OSSL_PARAM_construct_from_text(OSSL_PARAM *to, |
164 | const OSSL_PARAM *paramdefs, |
165 | const char *key, const char *value, |
166 | size_t value_n, |
167 | void *buf, size_t *buf_n) |
168 | { |
169 | const OSSL_PARAM *paramdef = NULL; |
170 | int ishex = 0; |
171 | BIGNUM *tmpbn = NULL; |
172 | int ok = 0; |
173 | |
174 | if (to == NULL || paramdefs == NULL) |
175 | return 0; |
176 | |
177 | if (!prepare_from_text(paramdefs, key, value, value_n, |
178 | ¶mdef, &ishex, buf_n, &tmpbn)) |
179 | return 0; |
180 | |
181 | /* |
182 | * The user gets the expected buffer size back even if the buffer isn't |
183 | * allocated. |
184 | */ |
185 | if (buf == NULL) |
186 | return 1; |
187 | |
188 | ok = construct_from_text(to, paramdef, value, value_n, ishex, |
189 | buf, *buf_n, tmpbn); |
190 | BN_free(tmpbn); |
191 | return ok; |
192 | } |
193 | |
194 | int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to, |
195 | const OSSL_PARAM *paramdefs, |
196 | const char *key, const char *value, |
197 | size_t value_n) |
198 | { |
199 | const OSSL_PARAM *paramdef = NULL; |
200 | int ishex = 0; |
201 | void *buf = NULL; |
202 | size_t buf_n = 0; |
203 | BIGNUM *tmpbn = NULL; |
204 | int ok = 0; |
205 | |
206 | if (to == NULL || paramdefs == NULL) |
207 | return 0; |
208 | |
209 | if (!prepare_from_text(paramdefs, key, value, value_n, |
210 | ¶mdef, &ishex, &buf_n, &tmpbn)) |
211 | return 0; |
212 | |
213 | if ((buf = OPENSSL_zalloc(buf_n > 0 ? buf_n : 1)) == NULL) { |
214 | CRYPTOerr(0, ERR_R_MALLOC_FAILURE); |
215 | return 0; |
216 | } |
217 | |
218 | ok = construct_from_text(to, paramdef, value, value_n, ishex, |
219 | buf, buf_n, tmpbn); |
220 | BN_free(tmpbn); |
221 | if (!ok) |
222 | OPENSSL_free(buf); |
223 | return ok; |
224 | } |
225 | |