ca4fc4af7e7c7a920bed005ac346fa334ab8aaca
[openssl.git] / crypto / param_build.c
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 "openssl/param_build.h"
17
18 #define OSSL_PARAM_ALLOCATED_END    127
19
20 typedef union {
21     OSSL_UNION_ALIGN;
22 } OSSL_PARAM_BLD_BLOCK;
23
24 #define ALIGN_SIZE  sizeof(OSSL_PARAM_BLD_BLOCK)
25
26 static size_t bytes_to_blocks(size_t bytes)
27 {
28     return (bytes + ALIGN_SIZE - 1) / ALIGN_SIZE;
29 }
30
31 static 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
54 static 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
69 void OSSL_PARAM_BLD_init(OSSL_PARAM_BLD *bld)
70 {
71     memset(bld, 0, sizeof(*bld));
72 }
73
74 int 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
79 int 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
86 int 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
92 int 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
99 int 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
105 int 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
112 int 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
118 int 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
125 int 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
132 int 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
138 int OSSL_PARAM_BLD_push_BN(OSSL_PARAM_BLD *bld, const char *key,
139                            const BIGNUM *bn)
140 {
141     return OSSL_PARAM_BLD_push_BN_pad(bld, key, bn,
142                                       bn == NULL ? 0 : BN_num_bytes(bn));
143 }
144
145 int OSSL_PARAM_BLD_push_BN_pad(OSSL_PARAM_BLD *bld, const char *key,
146                                const BIGNUM *bn, size_t sz)
147 {
148     int n, secure = 0;
149     OSSL_PARAM_BLD_DEF *pd;
150
151     if (bn != NULL) {
152         n = BN_num_bytes(bn);
153         if (n < 0) {
154             CRYPTOerr(0, CRYPTO_R_ZERO_LENGTH_NUMBER);
155             return 0;
156         }
157         if (sz < (size_t)n) {
158             CRYPTOerr(0, CRYPTO_R_TOO_SMALL_BUFFER);
159             return 0;
160         }
161         if (BN_get_flags(bn, BN_FLG_SECURE) == BN_FLG_SECURE)
162             secure = 1;
163     }
164     pd = param_push(bld, key, sz, sz, OSSL_PARAM_UNSIGNED_INTEGER, secure);
165     if (pd == NULL)
166         return 0;
167     pd->bn = bn;
168     return 1;
169 }
170
171 int OSSL_PARAM_BLD_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key,
172                                     const char *buf, size_t bsize)
173 {
174     OSSL_PARAM_BLD_DEF *pd;
175
176     if (bsize == 0) {
177         bsize = strlen(buf) + 1;
178     } else if (bsize > INT_MAX) {
179         CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_STRING,
180                   CRYPTO_R_STRING_TOO_LONG);
181         return 0;
182     }
183     pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_UTF8_STRING, 0);
184     if (pd == NULL)
185         return 0;
186     pd->string = buf;
187     return 1;
188 }
189
190 int OSSL_PARAM_BLD_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key,
191                                  char *buf, size_t bsize)
192 {
193     OSSL_PARAM_BLD_DEF *pd;
194
195     if (bsize == 0) {
196         bsize = strlen(buf) + 1;
197     } else if (bsize > INT_MAX) {
198         CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_PTR,
199                   CRYPTO_R_STRING_TOO_LONG);
200         return 0;
201     }
202     pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_UTF8_PTR, 0);
203     if (pd == NULL)
204         return 0;
205     pd->string = buf;
206     return 1;
207 }
208
209 int OSSL_PARAM_BLD_push_octet_string(OSSL_PARAM_BLD *bld, const char *key,
210                                      const void *buf, size_t bsize)
211 {
212     OSSL_PARAM_BLD_DEF *pd;
213
214     if (bsize > INT_MAX) {
215         CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_STRING,
216                   CRYPTO_R_STRING_TOO_LONG);
217         return 0;
218     }
219     pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_OCTET_STRING, 0);
220     if (pd == NULL)
221         return 0;
222     pd->string = buf;
223     return 1;
224 }
225
226 int OSSL_PARAM_BLD_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key,
227                                   void *buf, size_t bsize)
228 {
229     OSSL_PARAM_BLD_DEF *pd;
230
231     if (bsize > INT_MAX) {
232         CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_PTR,
233                   CRYPTO_R_STRING_TOO_LONG);
234         return 0;
235     }
236     pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_OCTET_PTR, 0);
237     if (pd == NULL)
238         return 0;
239     pd->string = buf;
240     return 1;
241 }
242
243 static OSSL_PARAM *param_bld_convert(OSSL_PARAM_BLD *bld, OSSL_PARAM *param,
244                                      OSSL_PARAM_BLD_BLOCK *blk,
245                                      OSSL_PARAM_BLD_BLOCK *secure)
246 {
247     size_t i;
248     OSSL_PARAM_BLD_DEF *pd;
249     void *p;
250
251     for (i = 0; i < bld->curr; i++) {
252         pd = bld->params + i;
253         param[i].key = pd->key;
254         param[i].data_type = pd->type;
255         param[i].data_size = pd->size;
256         param[i].return_size = 0;
257
258         if (pd->secure) {
259             p = secure;
260             secure += pd->alloc_blocks;
261         } else {
262             p = blk;
263             blk += pd->alloc_blocks;
264         }
265         param[i].data = p;
266         if (pd->bn != NULL) {
267             /* BIGNUM */
268             BN_bn2nativepad(pd->bn, (unsigned char *)p, pd->size);
269         } else if (pd->type == OSSL_PARAM_OCTET_PTR
270                    || pd->type == OSSL_PARAM_UTF8_PTR) {
271             /* PTR */
272             *(const void **)p = pd->string;
273         } else if (pd->type == OSSL_PARAM_OCTET_STRING
274                    || pd->type == OSSL_PARAM_UTF8_STRING) {
275             if (pd->string != NULL)
276                 memcpy(p, pd->string, pd->size);
277             else
278                 memset(p, 0, pd->size);
279         } else {
280             /* Number, but could also be a NULL BIGNUM */
281             if (pd->size > sizeof(pd->num))
282                 memset(p, 0, pd->size);
283             else if (pd->size > 0)
284                 memcpy(p, &pd->num, pd->size);
285         }
286     }
287     param[i] = OSSL_PARAM_construct_end();
288     return param + i;
289 }
290
291 OSSL_PARAM *OSSL_PARAM_BLD_to_param(OSSL_PARAM_BLD *bld)
292 {
293     OSSL_PARAM_BLD_BLOCK *blk, *s = NULL;
294     OSSL_PARAM *params, *last;
295     const size_t p_blks = bytes_to_blocks((1 + bld->curr) * sizeof(*params));
296     const size_t total = ALIGN_SIZE * (p_blks + bld->total_blocks);
297     const size_t ss = ALIGN_SIZE * bld->secure_blocks;
298
299     if (ss > 0) {
300         s = OPENSSL_secure_malloc(ss);
301         if (s == NULL) {
302             CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM,
303                       CRYPTO_R_SECURE_MALLOC_FAILURE);
304             return NULL;
305         }
306     }
307     params = OPENSSL_malloc(total);
308     if (params == NULL) {
309         CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM, ERR_R_MALLOC_FAILURE);
310         OPENSSL_secure_free(s);
311         return NULL;
312     }
313     blk = p_blks + (OSSL_PARAM_BLD_BLOCK *)(params);
314     last = param_bld_convert(bld, params, blk, s);
315     last->data_size = ss;
316     last->data = s;
317     last->data_type = OSSL_PARAM_ALLOCATED_END;
318     return params;
319 }
320
321 void OSSL_PARAM_BLD_free(OSSL_PARAM *params)
322 {
323     if (params != NULL) {
324         OSSL_PARAM *p;
325
326         for (p = params; p->key != NULL; p++)
327             ;
328         if (p->data_type == OSSL_PARAM_ALLOCATED_END)
329             OPENSSL_secure_clear_free(p->data, p->data_size);
330         OPENSSL_free(params);
331     }
332 }