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/cryptoerr.h>
14#include <openssl/params.h>
15#include "internal/cryptlib.h"
16#include "internal/param_build.h"
17
18#define OSSL_PARAM_ALLOCATED_END 127
19
20typedef union {
21 OSSL_UNION_ALIGN;
22} OSSL_PARAM_BLD_BLOCK;
23
24#define ALIGN_SIZE sizeof(OSSL_PARAM_BLD_BLOCK)
25
26static size_t bytes_to_blocks(size_t bytes)
27{
28 return (bytes + ALIGN_SIZE - 1) / ALIGN_SIZE;
29}
30
31static OSSL_PARAM_BLD_DEF *param_push(OSSL_PARAM_BLD *bld, const char *key,
32 int size, size_t alloc, int type,
33 int secure)
34{
35 OSSL_PARAM_BLD_DEF *pd;
36
37 if (bld->curr >= OSSL_PARAM_BLD_MAX) {
38 CRYPTOerr(CRYPTO_F_PARAM_PUSH, CRYPTO_R_TOO_MANY_RECORDS);
39 return NULL;
40 }
41 pd = bld->params + bld->curr++;
42 memset(pd, 0, sizeof(*pd));
43 pd->key = key;
44 pd->type = type;
45 pd->size = size;
46 pd->alloc_blocks = bytes_to_blocks(size);
47 if ((pd->secure = secure) != 0)
48 bld->secure_blocks += pd->alloc_blocks;
49 else
50 bld->total_blocks += pd->alloc_blocks;
51 return pd;
52}
53
54static int param_push_num(OSSL_PARAM_BLD *bld, const char *key,
55 void *num, size_t size, int type)
56{
57 OSSL_PARAM_BLD_DEF *pd = param_push(bld, key, size, size, type, 0);
58
59 if (pd == NULL)
60 return 0;
61 if (size > sizeof(pd->num)) {
62 CRYPTOerr(CRYPTO_F_PARAM_PUSH_NUM, CRYPTO_R_TOO_MANY_BYTES);
63 return 0;
64 }
65 memcpy(&pd->num, num, size);
66 return 1;
67}
68
69void ossl_param_bld_init(OSSL_PARAM_BLD *bld)
70{
71 memset(bld, 0, sizeof(*bld));
72}
73
74int ossl_param_bld_push_int(OSSL_PARAM_BLD *bld, const char *key, int num)
75{
76 return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
77}
78
79int ossl_param_bld_push_uint(OSSL_PARAM_BLD *bld, const char *key,
80 unsigned int num)
81{
82 return param_push_num(bld, key, &num, sizeof(num),
83 OSSL_PARAM_UNSIGNED_INTEGER);
84}
85
86int ossl_param_bld_push_long(OSSL_PARAM_BLD *bld, const char *key,
87 long int num)
88{
89 return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
90}
91
92int ossl_param_bld_push_ulong(OSSL_PARAM_BLD *bld, const char *key,
93 unsigned long int num)
94{
95 return param_push_num(bld, key, &num, sizeof(num),
96 OSSL_PARAM_UNSIGNED_INTEGER);
97}
98
99int ossl_param_bld_push_int32(OSSL_PARAM_BLD *bld, const char *key,
100 int32_t num)
101{
102 return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
103}
104
105int ossl_param_bld_push_uint32(OSSL_PARAM_BLD *bld, const char *key,
106 uint32_t num)
107{
108 return param_push_num(bld, key, &num, sizeof(num),
109 OSSL_PARAM_UNSIGNED_INTEGER);
110}
111
112int ossl_param_bld_push_int64(OSSL_PARAM_BLD *bld, const char *key,
113 int64_t num)
114{
115 return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
116}
117
118int ossl_param_bld_push_uint64(OSSL_PARAM_BLD *bld, const char *key,
119 uint64_t num)
120{
121 return param_push_num(bld, key, &num, sizeof(num),
122 OSSL_PARAM_UNSIGNED_INTEGER);
123}
124
125int ossl_param_bld_push_size_t(OSSL_PARAM_BLD *bld, const char *key,
126 size_t num)
127{
128 return param_push_num(bld, key, &num, sizeof(num),
129 OSSL_PARAM_UNSIGNED_INTEGER);
130}
131
132int ossl_param_bld_push_double(OSSL_PARAM_BLD *bld, const char *key,
133 double num)
134{
135 return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_REAL);
136}
137
138int ossl_param_bld_push_BN(OSSL_PARAM_BLD *bld, const char *key,
139 const BIGNUM *bn)
140{
141 int sz = -1, secure = 0;
142 OSSL_PARAM_BLD_DEF *pd;
143
144 if (bn != NULL) {
145 sz = BN_num_bytes(bn);
146 if (sz < 0) {
147 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_BN,
148 CRYPTO_R_ZERO_LENGTH_NUMBER);
149 return 0;
150 }
151 if (BN_get_flags(bn, BN_FLG_SECURE) == BN_FLG_SECURE)
152 secure = 1;
153 }
154 pd = param_push(bld, key, sz, sz >= 0 ? sz : 0,
155 OSSL_PARAM_UNSIGNED_INTEGER, secure);
156 if (pd == NULL)
157 return 0;
158 pd->bn = bn;
159 return 1;
160}
161
162int ossl_param_bld_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key,
163 const char *buf, size_t bsize)
164{
165 OSSL_PARAM_BLD_DEF *pd;
166
167 if (bsize == 0) {
168 bsize = strlen(buf) + 1;
169 } else if (bsize > INT_MAX) {
170 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_STRING,
171 CRYPTO_R_STRING_TOO_LONG);
172 return 0;
173 }
174 pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_UTF8_STRING, 0);
175 if (pd == NULL)
176 return 0;
177 pd->string = buf;
178 return 1;
179}
180
181int ossl_param_bld_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key,
182 char *buf, size_t bsize)
183{
184 OSSL_PARAM_BLD_DEF *pd;
185
186 if (bsize == 0) {
187 bsize = strlen(buf) + 1;
188 } else if (bsize > INT_MAX) {
189 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_PTR,
190 CRYPTO_R_STRING_TOO_LONG);
191 return 0;
192 }
193 pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_UTF8_PTR, 0);
194 if (pd == NULL)
195 return 0;
196 pd->string = buf;
197 return 1;
198}
199
200int ossl_param_bld_push_octet_string(OSSL_PARAM_BLD *bld, const char *key,
201 const void *buf, size_t bsize)
202{
203 OSSL_PARAM_BLD_DEF *pd;
204
205 if (bsize > INT_MAX) {
206 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_STRING,
207 CRYPTO_R_STRING_TOO_LONG);
208 return 0;
209 }
210 pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_OCTET_STRING, 0);
211 if (pd == NULL)
212 return 0;
213 pd->string = buf;
214 return 1;
215}
216
217int ossl_param_bld_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key,
218 void *buf, size_t bsize)
219{
220 OSSL_PARAM_BLD_DEF *pd;
221
222 if (bsize > INT_MAX) {
223 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_PTR,
224 CRYPTO_R_STRING_TOO_LONG);
225 return 0;
226 }
227 pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_OCTET_PTR, 0);
228 if (pd == NULL)
229 return 0;
230 pd->string = buf;
231 return 1;
232}
233
234static OSSL_PARAM *param_bld_convert(OSSL_PARAM_BLD *bld, OSSL_PARAM *param,
235 OSSL_PARAM_BLD_BLOCK *blk,
236 OSSL_PARAM_BLD_BLOCK *secure)
237{
238 size_t i;
239 OSSL_PARAM_BLD_DEF *pd;
240 void *p;
241
242 for (i = 0; i < bld->curr; i++) {
243 pd = bld->params + i;
244 param[i].key = pd->key;
245 param[i].data_type = pd->type;
246 param[i].data_size = pd->size;
247 param[i].return_size = 0;
248
249 if (pd->secure) {
250 p = secure;
251 secure += pd->alloc_blocks;
252 } else {
253 p = blk;
254 blk += pd->alloc_blocks;
255 }
256 param[i].data = p;
257 if (pd->bn != NULL) {
258 /* BIGNUM */
259 BN_bn2nativepad(pd->bn, (unsigned char *)p, pd->size);
260 } else if (pd->type == OSSL_PARAM_OCTET_PTR
261 || pd->type == OSSL_PARAM_UTF8_PTR) {
262 /* PTR */
263 *(const void **)p = pd->string;
264 } else if (pd->type == OSSL_PARAM_OCTET_STRING
265 || pd->type == OSSL_PARAM_UTF8_STRING) {
266 if (pd->string != NULL)
267 memcpy(p, pd->string, pd->size);
268 else
269 memset(p, 0, pd->size);
270 } else {
271 /* Number, but could also be a NULL BIGNUM */
272 if (pd->size > sizeof(pd->num))
273 memset(p, 0, pd->size);
274 else if (pd->size > 0)
275 memcpy(p, &pd->num, pd->size);
276 }
277 }
278 param[i] = OSSL_PARAM_construct_end();
279 return param + i;
280}
281
282OSSL_PARAM *ossl_param_bld_to_param(OSSL_PARAM_BLD *bld)
283{
284 OSSL_PARAM_BLD_BLOCK *blk, *s = NULL;
285 OSSL_PARAM *params, *last;
286 const size_t p_blks = bytes_to_blocks((1 + bld->curr) * sizeof(*params));
287 const size_t total = ALIGN_SIZE * (p_blks + bld->total_blocks);
288 const size_t ss = ALIGN_SIZE * bld->secure_blocks;
289
290 if (ss > 0) {
291 s = OPENSSL_secure_malloc(ss);
292 if (s == NULL) {
293 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM,
294 CRYPTO_R_SECURE_MALLOC_FAILURE);
295 return NULL;
296 }
297 }
298 params = OPENSSL_malloc(total);
299 if (params == NULL) {
300 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM, ERR_R_MALLOC_FAILURE);
301 OPENSSL_secure_free(s);
302 return NULL;
303 }
304 blk = p_blks + (OSSL_PARAM_BLD_BLOCK *)(params);
305 last = param_bld_convert(bld, params, blk, s);
306 last->data_size = ss;
307 last->data = s;
308 last->data_type = OSSL_PARAM_ALLOCATED_END;
309 return params;
310}
311
312void ossl_param_bld_free(OSSL_PARAM *params)
313{
314 if (params != NULL) {
315 OSSL_PARAM *p;
316
317 for (p = params; p->key != NULL; p++)
318 ;
319 if (p->data_type == OSSL_PARAM_ALLOCATED_END)
320 OPENSSL_secure_clear_free(p->data, p->data_size);
321 OPENSSL_free(params);
322 }
323}
324
325OSSL_PARAM *ossl_param_bld_to_param_ex(OSSL_PARAM_BLD *bld, OSSL_PARAM *params,
326 size_t param_n, void *data,
327 size_t data_n, void *secure,
328 size_t secure_n)
329{
330 if (params == NULL || data == NULL) {
331 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
332 CRYPTO_R_INVALID_NULL_ARGUMENT);
333 return NULL;
334 }
335 if (param_n < bld->curr + 1) {
336 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
337 CRYPTO_R_INSUFFICIENT_PARAM_SIZE);
338 return NULL;
339 }
340 if (data_n < ALIGN_SIZE * bld->total_blocks) {
341 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
342 CRYPTO_R_INSUFFICIENT_DATA_SPACE);
343 return NULL;
344 }
345 if (bld->secure_blocks > 0 && secure_n < ALIGN_SIZE * bld->secure_blocks) {
346 CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
347 CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE);
348 return NULL;
349 }
350 param_bld_convert(bld, params, (OSSL_PARAM_BLD_BLOCK *)data,
351 (OSSL_PARAM_BLD_BLOCK *)secure);
352 return params;
353}
354