2 * Copyright 2021-2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
11 #include <openssl/params.h>
12 #include <openssl/param_build.h>
13 #include "internal/param_build_set.h"
15 #define OSSL_PARAM_ALLOCATED_END 127
16 #define OSSL_PARAM_MERGE_LIST_MAX 128
18 #define OSSL_PARAM_BUF_PUBLIC 0
19 #define OSSL_PARAM_BUF_SECURE 1
20 #define OSSL_PARAM_BUF_MAX (OSSL_PARAM_BUF_SECURE + 1)
23 OSSL_PARAM_ALIGNED_BLOCK
*alloc
; /* The allocated buffer */
24 OSSL_PARAM_ALIGNED_BLOCK
*cur
; /* Current position in the allocated buf */
25 size_t blocks
; /* Number of aligned blocks */
26 size_t alloc_sz
; /* The size of the allocated buffer (in bytes) */
29 size_t ossl_param_bytes_to_blocks(size_t bytes
)
31 return (bytes
+ OSSL_PARAM_ALIGN_SIZE
- 1) / OSSL_PARAM_ALIGN_SIZE
;
34 static int ossl_param_buf_alloc(OSSL_PARAM_BUF
*out
, size_t extra_blocks
,
37 size_t sz
= OSSL_PARAM_ALIGN_SIZE
* (extra_blocks
+ out
->blocks
);
39 out
->alloc
= is_secure
? OPENSSL_secure_zalloc(sz
) : OPENSSL_zalloc(sz
);
40 if (out
->alloc
== NULL
)
43 out
->cur
= out
->alloc
+ extra_blocks
;
47 void ossl_param_set_secure_block(OSSL_PARAM
*last
, void *secure_buffer
,
48 size_t secure_buffer_sz
)
51 last
->data_size
= secure_buffer_sz
;
52 last
->data
= secure_buffer
;
53 last
->data_type
= OSSL_PARAM_ALLOCATED_END
;
56 static OSSL_PARAM
*ossl_param_dup(const OSSL_PARAM
*src
, OSSL_PARAM
*dst
,
57 OSSL_PARAM_BUF buf
[OSSL_PARAM_BUF_MAX
],
61 int has_dst
= (dst
!= NULL
);
63 size_t param_sz
, blks
;
65 for (in
= src
; in
->key
!= NULL
; in
++) {
66 is_secure
= CRYPTO_secure_allocated(in
->data
);
69 dst
->data
= buf
[is_secure
].cur
;
72 if (in
->data_type
== OSSL_PARAM_OCTET_PTR
73 || in
->data_type
== OSSL_PARAM_UTF8_PTR
) {
74 param_sz
= sizeof(in
->data
);
76 *((const void **)dst
->data
) = *(const void **)in
->data
;
78 param_sz
= in
->data_size
;
80 memcpy(dst
->data
, in
->data
, param_sz
);
82 if (in
->data_type
== OSSL_PARAM_UTF8_STRING
)
83 param_sz
++; /* NULL terminator */
84 blks
= ossl_param_bytes_to_blocks(param_sz
);
88 buf
[is_secure
].cur
+= blks
;
90 buf
[is_secure
].blocks
+= blks
;
92 if (param_count
!= NULL
)
98 OSSL_PARAM
*OSSL_PARAM_dup(const OSSL_PARAM
*src
)
101 OSSL_PARAM_BUF buf
[OSSL_PARAM_BUF_MAX
];
102 OSSL_PARAM
*last
, *dst
;
103 int param_count
= 1; /* Include terminator in the count */
106 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
110 memset(buf
, 0, sizeof(buf
));
112 /* First Pass: get the param_count and block sizes required */
113 (void)ossl_param_dup(src
, NULL
, buf
, ¶m_count
);
115 param_blocks
= ossl_param_bytes_to_blocks(param_count
* sizeof(*src
));
117 * The allocated buffer consists of an array of OSSL_PARAM followed by
118 * aligned data bytes that the array elements will point to.
120 if (!ossl_param_buf_alloc(&buf
[OSSL_PARAM_BUF_PUBLIC
], param_blocks
, 0))
123 /* Allocate a secure memory buffer if required */
124 if (buf
[OSSL_PARAM_BUF_SECURE
].blocks
> 0
125 && !ossl_param_buf_alloc(&buf
[OSSL_PARAM_BUF_SECURE
], 0, 1)) {
126 OPENSSL_free(buf
[OSSL_PARAM_BUF_PUBLIC
].alloc
);
130 dst
= (OSSL_PARAM
*)buf
[OSSL_PARAM_BUF_PUBLIC
].alloc
;
131 last
= ossl_param_dup(src
, dst
, buf
, NULL
);
132 /* Store the allocated secure memory buffer in the last param block */
133 ossl_param_set_secure_block(last
, buf
[OSSL_PARAM_BUF_SECURE
].alloc
,
134 buf
[OSSL_PARAM_BUF_SECURE
].alloc_sz
);
138 static int compare_params(const void *left
, const void *right
)
140 const OSSL_PARAM
*l
= *(const OSSL_PARAM
**)left
;
141 const OSSL_PARAM
*r
= *(const OSSL_PARAM
**)right
;
143 return OPENSSL_strcasecmp(l
->key
, r
->key
);
146 OSSL_PARAM
*OSSL_PARAM_merge(const OSSL_PARAM
*p1
, const OSSL_PARAM
*p2
)
148 const OSSL_PARAM
*list1
[OSSL_PARAM_MERGE_LIST_MAX
+ 1];
149 const OSSL_PARAM
*list2
[OSSL_PARAM_MERGE_LIST_MAX
+ 1];
150 const OSSL_PARAM
*p
= NULL
;
151 const OSSL_PARAM
**p1cur
, **p2cur
;
152 OSSL_PARAM
*params
, *dst
;
153 size_t list1_sz
= 0, list2_sz
= 0;
156 if (p1
== NULL
&& p2
== NULL
) {
157 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
161 /* Copy p1 to list1 */
163 for (p
= p1
; p
->key
!= NULL
&& list1_sz
< OSSL_PARAM_MERGE_LIST_MAX
; p
++)
164 list1
[list1_sz
++] = p
;
166 list1
[list1_sz
] = NULL
;
168 /* copy p2 to a list2 */
170 for (p
= p2
; p
->key
!= NULL
&& list2_sz
< OSSL_PARAM_MERGE_LIST_MAX
; p
++)
171 list2
[list2_sz
++] = p
;
173 list2
[list2_sz
] = NULL
;
174 if (list1_sz
== 0 && list2_sz
== 0) {
175 ERR_raise(ERR_LIB_CRYPTO
, CRYPTO_R_NO_PARAMS_TO_MERGE
);
179 /* Sort the 2 lists */
180 qsort(list1
, list1_sz
, sizeof(OSSL_PARAM
*), compare_params
);
181 qsort(list2
, list2_sz
, sizeof(OSSL_PARAM
*), compare_params
);
183 /* Allocate enough space to store the merged parameters */
184 params
= OPENSSL_zalloc((list1_sz
+ list2_sz
+ 1) * sizeof(*p1
));
191 /* If list1 is finished just tack list2 onto the end */
192 if (*p1cur
== NULL
) {
196 } while (*p2cur
!= NULL
);
199 /* If list2 is finished just tack list1 onto the end */
200 if (*p2cur
== NULL
) {
204 } while (*p1cur
!= NULL
);
207 /* consume the list element with the smaller key */
208 diff
= OPENSSL_strcasecmp((*p1cur
)->key
, (*p2cur
)->key
);
210 /* If the keys are the same then throw away the list1 element */
214 } else if (diff
> 0) {
225 void OSSL_PARAM_free(OSSL_PARAM
*params
)
227 if (params
!= NULL
) {
230 for (p
= params
; p
->key
!= NULL
; p
++)
232 if (p
->data_type
== OSSL_PARAM_ALLOCATED_END
)
233 OPENSSL_secure_clear_free(p
->data
, p
->data_size
);
234 OPENSSL_free(params
);