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
23static 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
103static 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
163int 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 &paramdef, &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
194int 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 &paramdef, &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