Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #ifndef _GNU_SOURCE
17 : : #define _GNU_SOURCE
18 : : #endif
19 : :
20 : : #include "crypto/s2n_certificate.h"
21 : :
22 : : #include <openssl/pem.h>
23 : : #include <openssl/x509v3.h>
24 : : #include <string.h>
25 : : #include <strings.h>
26 : :
27 : : #include "api/s2n.h"
28 : : #include "crypto/s2n_mldsa.h"
29 : : #include "crypto/s2n_openssl_x509.h"
30 : : #include "tls/extensions/s2n_extension_list.h"
31 : : #include "tls/s2n_connection.h"
32 : : #include "utils/s2n_array.h"
33 : : #include "utils/s2n_mem.h"
34 : : #include "utils/s2n_safety.h"
35 : :
36 : : int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type)
37 : 841 : {
38 [ - + ][ # # ]: 841 : POSIX_ENSURE_REF(cert);
39 : 841 : cert->pkey_type = pkey_type;
40 [ - + ]: 841 : POSIX_GUARD_RESULT(s2n_pkey_setup_for_type(&cert->public_key, pkey_type));
41 : 841 : return 0;
42 : 841 : }
43 : :
44 : : int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer)
45 : 906 : {
46 : 906 : DEFER_CLEANUP(struct s2n_stuffer cert_out_stuffer = { 0 }, s2n_stuffer_free);
47 [ - + ]: 906 : POSIX_GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048));
48 : :
49 : 906 : struct s2n_cert **insert = &cert_chain_out->head;
50 : 906 : uint32_t chain_size = 0;
51 [ + + ]: 2928 : while (s2n_stuffer_has_pem_encapsulated_block(chain_in_stuffer)) {
52 : 2053 : int result = s2n_stuffer_certificate_from_pem(chain_in_stuffer, &cert_out_stuffer);
53 [ + - ][ + + ]: 2053 : POSIX_ENSURE(result == S2N_SUCCESS, S2N_ERR_INVALID_PEM);
54 : :
55 : 2024 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
56 [ - + ]: 2024 : POSIX_GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert)));
57 [ - + ]: 2024 : POSIX_GUARD(s2n_blob_zero(&mem));
58 : :
59 : 2024 : struct s2n_cert *new_node = (struct s2n_cert *) (void *) mem.data;
60 [ - + ]: 2024 : POSIX_GUARD(s2n_alloc(&new_node->raw, s2n_stuffer_data_available(&cert_out_stuffer)));
61 [ + + ]: 2024 : POSIX_GUARD(s2n_stuffer_read(&cert_out_stuffer, &new_node->raw));
62 : 2022 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
63 : :
64 : : /* Additional 3 bytes for the length field in the protocol */
65 : 2022 : chain_size += new_node->raw.size + 3;
66 : 2022 : new_node->next = NULL;
67 : 2022 : *insert = new_node;
68 : 2022 : insert = &new_node->next;
69 : 2022 : };
70 : :
71 [ - + ][ # # ]: 875 : POSIX_ENSURE(chain_size > 0, S2N_ERR_NO_CERTIFICATE_IN_PEM);
72 : 875 : cert_chain_out->chain_size = chain_size;
73 : :
74 : 875 : return S2N_SUCCESS;
75 : 875 : }
76 : :
77 : : int s2n_cert_chain_and_key_set_cert_chain_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key, struct s2n_stuffer *chain_in_stuffer)
78 : 847 : {
79 [ - + ][ # # ]: 847 : POSIX_ENSURE_REF(cert_and_key);
80 [ - + ][ # # ]: 847 : POSIX_ENSURE_REF(cert_and_key->cert_chain);
81 : 847 : return s2n_create_cert_chain_from_stuffer(cert_and_key->cert_chain, chain_in_stuffer);
82 : 847 : }
83 : :
84 : : int s2n_cert_chain_and_key_set_cert_chain_bytes(struct s2n_cert_chain_and_key *cert_and_key, uint8_t *cert_chain_pem, uint32_t cert_chain_len)
85 : 93 : {
86 : 93 : DEFER_CLEANUP(struct s2n_stuffer chain_in_stuffer = { 0 }, s2n_stuffer_free);
87 : :
88 [ - + ]: 93 : POSIX_GUARD(s2n_stuffer_init_ro_from_string(&chain_in_stuffer, cert_chain_pem, cert_chain_len));
89 [ - + ]: 93 : POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer));
90 : :
91 : 93 : return S2N_SUCCESS;
92 : 93 : }
93 : :
94 : : int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem)
95 : 754 : {
96 : 754 : DEFER_CLEANUP(struct s2n_stuffer chain_in_stuffer = { 0 }, s2n_stuffer_free);
97 : :
98 : : /* Turn the chain into a stuffer */
99 [ - + ]: 754 : POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem));
100 [ + + ]: 754 : POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer));
101 : :
102 : 751 : return S2N_SUCCESS;
103 : 754 : }
104 : :
105 : : int s2n_cert_chain_and_key_set_private_key_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key,
106 : : struct s2n_stuffer *key_in_stuffer, struct s2n_stuffer *key_out_stuffer)
107 : 763 : {
108 [ - + ][ # # ]: 763 : POSIX_ENSURE_REF(cert_and_key);
109 [ - + ][ # # ]: 763 : POSIX_ENSURE_REF(cert_and_key->private_key);
110 : :
111 : 763 : struct s2n_blob key_blob = { 0 };
112 : :
113 [ - + ]: 763 : POSIX_GUARD(s2n_pkey_zero_init(cert_and_key->private_key));
114 : :
115 : : /* Convert pem to asn1 and asn1 to the private key. Handles both PKCS#1 and PKCS#8 formats */
116 : 763 : int type_hint = 0;
117 [ + + ]: 763 : POSIX_GUARD(s2n_stuffer_private_key_from_pem(key_in_stuffer, key_out_stuffer, &type_hint));
118 : 761 : key_blob.size = s2n_stuffer_data_available(key_out_stuffer);
119 : 761 : key_blob.data = s2n_stuffer_raw_read(key_out_stuffer, key_blob.size);
120 [ - + ][ # # ]: 761 : POSIX_ENSURE_REF(key_blob.data);
121 : :
122 [ + + ]: 761 : POSIX_GUARD_RESULT(s2n_asn1der_to_private_key(cert_and_key->private_key, &key_blob, type_hint));
123 : 760 : return S2N_SUCCESS;
124 : 761 : }
125 : :
126 : : int s2n_cert_chain_and_key_set_private_key_bytes(struct s2n_cert_chain_and_key *cert_and_key, uint8_t *private_key_pem, uint32_t private_key_len)
127 : 12 : {
128 : 12 : DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = { 0 }, s2n_stuffer_free);
129 : 12 : DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = { 0 }, s2n_stuffer_free);
130 : :
131 : : /* Put the private key pem in a stuffer */
132 [ - + ]: 12 : POSIX_GUARD(s2n_stuffer_init_ro_from_string(&key_in_stuffer, private_key_pem, private_key_len));
133 [ - + ]: 12 : POSIX_GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, private_key_len));
134 : :
135 [ - + ]: 12 : POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_from_stuffer(cert_and_key, &key_in_stuffer, &key_out_stuffer));
136 : :
137 : 12 : return S2N_SUCCESS;
138 : 12 : }
139 : :
140 : : int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem)
141 : 751 : {
142 [ - + ][ # # ]: 751 : POSIX_ENSURE_REF(private_key_pem);
143 : :
144 : 751 : DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = { 0 }, s2n_stuffer_free);
145 : 751 : DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = { 0 }, s2n_stuffer_free);
146 : :
147 : : /* Put the private key pem in a stuffer */
148 [ - + ]: 751 : POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem));
149 [ - + ]: 751 : POSIX_GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem)));
150 : :
151 [ + + ]: 751 : POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_from_stuffer(cert_and_key, &key_in_stuffer, &key_out_stuffer));
152 : :
153 : 748 : return S2N_SUCCESS;
154 : 751 : }
155 : :
156 : : int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length)
157 : 32 : {
158 [ + - ][ + + ]: 32 : POSIX_ENSURE_REF(chain_and_key);
159 [ - + ]: 31 : POSIX_GUARD(s2n_free(&chain_and_key->ocsp_status));
160 [ + + ][ + - ]: 31 : if (data && length) {
161 [ - + ]: 30 : POSIX_GUARD(s2n_alloc(&chain_and_key->ocsp_status, length));
162 [ # # ][ - + ]: 30 : POSIX_CHECKED_MEMCPY(chain_and_key->ocsp_status.data, data, length);
[ + - ]
163 : 30 : }
164 : 31 : return 0;
165 : 31 : }
166 : :
167 : : int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length)
168 : 15 : {
169 [ + - ][ + + ]: 15 : POSIX_ENSURE_REF(chain_and_key);
170 [ - + ]: 14 : POSIX_GUARD(s2n_free(&chain_and_key->sct_list));
171 [ + + ][ + - ]: 14 : if (data && length) {
172 [ - + ]: 13 : POSIX_GUARD(s2n_alloc(&chain_and_key->sct_list, length));
173 [ # # ][ - + ]: 13 : POSIX_CHECKED_MEMCPY(chain_and_key->sct_list.data, data, length);
[ + - ]
174 : 13 : }
175 : 14 : return 0;
176 : 14 : }
177 : :
178 : : struct s2n_cert_chain_and_key *s2n_cert_chain_and_key_new(void)
179 : 936 : {
180 : 936 : DEFER_CLEANUP(struct s2n_blob chain_and_key_mem = { 0 }, s2n_free);
181 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_alloc(&chain_and_key_mem, sizeof(struct s2n_cert_chain_and_key)));
182 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_blob_zero(&chain_and_key_mem));
183 : :
184 : 936 : DEFER_CLEANUP(struct s2n_blob cert_chain_mem = { 0 }, s2n_free);
185 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)));
186 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_blob_zero(&cert_chain_mem));
187 : :
188 : 936 : DEFER_CLEANUP(struct s2n_blob pkey_mem = { 0 }, s2n_free);
189 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)));
190 [ - + ]: 936 : PTR_GUARD_POSIX(s2n_blob_zero(&pkey_mem));
191 : :
192 : 936 : DEFER_CLEANUP(struct s2n_array *cn_names = NULL, s2n_array_free_p);
193 : 936 : cn_names = s2n_array_new(sizeof(struct s2n_blob));
194 [ - + ][ # # ]: 936 : PTR_ENSURE_REF(cn_names);
195 : :
196 : 936 : DEFER_CLEANUP(struct s2n_array *san_names = NULL, s2n_array_free_p);
197 : 936 : san_names = s2n_array_new(sizeof(struct s2n_blob));
198 [ - + ][ # # ]: 936 : PTR_ENSURE_REF(san_names);
199 : :
200 : 936 : struct s2n_cert_chain_and_key *chain_and_key = (struct s2n_cert_chain_and_key *) (void *) chain_and_key_mem.data;
201 : 936 : chain_and_key->cert_chain = (struct s2n_cert_chain *) (void *) cert_chain_mem.data;
202 : 936 : chain_and_key->private_key = (s2n_cert_private_key *) (void *) pkey_mem.data;
203 : 936 : chain_and_key->cn_names = cn_names;
204 : 936 : chain_and_key->san_names = san_names;
205 : :
206 : 936 : ZERO_TO_DISABLE_DEFER_CLEANUP(chain_and_key_mem);
207 : 936 : ZERO_TO_DISABLE_DEFER_CLEANUP(cert_chain_mem);
208 : 936 : ZERO_TO_DISABLE_DEFER_CLEANUP(pkey_mem);
209 : 936 : ZERO_TO_DISABLE_DEFER_CLEANUP(cn_names);
210 : 936 : ZERO_TO_DISABLE_DEFER_CLEANUP(san_names);
211 : 936 : return chain_and_key;
212 : 936 : }
213 : :
214 : : DEFINE_POINTER_CLEANUP_FUNC(GENERAL_NAMES *, GENERAL_NAMES_free);
215 : :
216 : : int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert)
217 : 823 : {
218 [ - + ][ # # ]: 823 : POSIX_ENSURE_REF(chain_and_key->san_names);
219 [ # # ][ - + ]: 823 : POSIX_ENSURE_REF(x509_cert);
220 : :
221 : 823 : DEFER_CLEANUP(GENERAL_NAMES *san_names = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL), GENERAL_NAMES_free_pointer);
222 [ + + ]: 823 : if (san_names == NULL) {
223 : : /* No SAN extension */
224 : 110 : return 0;
225 : 110 : }
226 : :
227 : 713 : const int num_san_names = sk_GENERAL_NAME_num(san_names);
228 [ + + ]: 1432 : for (int i = 0; i < num_san_names; i++) {
229 : 719 : GENERAL_NAME *san_name = sk_GENERAL_NAME_value(san_names, i);
230 [ - + ]: 719 : if (!san_name) {
231 : 0 : continue;
232 : 0 : }
233 : :
234 [ + + ]: 719 : if (san_name->type == GEN_DNS) {
235 : : /* Decoding isn't necessary here since a DNS SAN name is ASCII(type V_ASN1_IA5STRING) */
236 : 715 : const unsigned char *san_str = S2N_ASN1_STRING_DATA(san_name->d.dNSName);
237 : 715 : const size_t san_str_len = ASN1_STRING_length(san_name->d.dNSName);
238 : 715 : struct s2n_blob *san_blob = NULL;
239 [ - + ]: 715 : POSIX_GUARD_RESULT(s2n_array_pushback(chain_and_key->san_names, (void **) &san_blob));
240 [ - + ]: 715 : if (!san_blob) {
241 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_NULL_SANS);
242 : 0 : }
243 : :
244 [ - + ]: 715 : if (s2n_alloc(san_blob, san_str_len)) {
245 : 0 : S2N_ERROR_PRESERVE_ERRNO();
246 : 0 : }
247 : :
248 [ # # ][ - + ]: 715 : POSIX_CHECKED_MEMCPY(san_blob->data, san_str, san_str_len);
[ + - ]
249 : 715 : san_blob->size = san_str_len;
250 : : /* normalize san_blob to lowercase */
251 [ - + ]: 715 : POSIX_GUARD(s2n_blob_char_to_lower(san_blob));
252 : 715 : }
253 : 719 : }
254 : :
255 : 713 : return 0;
256 : 713 : }
257 : :
258 : : /* Parse CN names from the Subject of the leaf certificate. Technically there can by multiple CNs
259 : : * in the Subject but practically very few certificates in the wild will have more than one CN.
260 : : * Since the data for this certificate is coming from the application and not from an untrusted
261 : : * source, we will try our best to parse all of the CNs.
262 : : *
263 : : * A recent CAB thread proposed removing support for multiple CNs:
264 : : * https://cabforum.org/pipermail/public/2016-April/007242.html
265 : : */
266 : :
267 : 828 : DEFINE_POINTER_CLEANUP_FUNC(unsigned char *, OPENSSL_free);
268 : :
269 : : int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert)
270 : 826 : {
271 [ - + ][ # # ]: 826 : POSIX_ENSURE_REF(chain_and_key->cn_names);
272 [ - + ][ # # ]: 826 : POSIX_ENSURE_REF(x509_cert);
273 : :
274 : 826 : S2N_X509_CONST X509_NAME *subject = X509_get_subject_name(x509_cert);
275 [ - + ]: 826 : if (!subject) {
276 : 0 : return 0;
277 : 0 : }
278 : :
279 : 826 : int lastpos = -1;
280 [ + + ]: 1654 : while ((lastpos = X509_NAME_get_index_by_NID(subject, NID_commonName, lastpos)) >= 0) {
281 : 828 : S2N_X509_CONST X509_NAME_ENTRY *name_entry = X509_NAME_get_entry(subject, lastpos);
282 [ - + ]: 828 : if (!name_entry) {
283 : 0 : continue;
284 : 0 : }
285 : :
286 : 828 : S2N_X509_CONST ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(name_entry);
287 [ - + ]: 828 : if (!asn1_str) {
288 : 0 : continue;
289 : 0 : }
290 : :
291 : : /* We need to try and decode the CN since it may be encoded as unicode with a
292 : : * direct ASCII equivalent. Any non ASCII bytes in the string will fail later when we
293 : : * actually compare hostnames.
294 : : *
295 : : * `ASN1_STRING_to_UTF8` allocates in both the success case and in the zero return case, but
296 : : * not in the failure case (negative return value). Therefore, we use `ZERO_TO_DISABLE_DEFER_CLEANUP`
297 : : * in the failure case to prevent double-freeing `utf8_str`. For the zero and success cases, `utf8_str`
298 : : * will be freed by the `DEFER_CLEANUP`.
299 : : */
300 : 828 : DEFER_CLEANUP(unsigned char *utf8_str, OPENSSL_free_pointer);
301 : 828 : const int utf8_out_len = ASN1_STRING_to_UTF8(&utf8_str, asn1_str);
302 [ + + ]: 828 : if (utf8_out_len < 0) {
303 : : /* On failure, ASN1_STRING_to_UTF8 does not allocate any memory */
304 : 2 : ZERO_TO_DISABLE_DEFER_CLEANUP(utf8_str);
305 : 2 : continue;
306 [ + + ]: 826 : } else if (utf8_out_len == 0) {
307 : : /* We still need to free memory for this case, so let the DEFER_CLEANUP free it
308 : : * see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7521 and
309 : : * https://security.archlinux.org/CVE-2017-7521
310 : : */
311 : 823 : } else {
312 : 823 : struct s2n_blob *cn_name = NULL;
313 [ - + ]: 823 : POSIX_GUARD_RESULT(s2n_array_pushback(chain_and_key->cn_names, (void **) &cn_name));
314 [ - + ]: 823 : if (cn_name == NULL) {
315 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_NULL_CN_NAME);
316 : 0 : }
317 : :
318 [ - + ]: 823 : if (s2n_alloc(cn_name, utf8_out_len) < 0) {
319 : 0 : S2N_ERROR_PRESERVE_ERRNO();
320 : 0 : }
321 [ - + ][ # # ]: 823 : POSIX_CHECKED_MEMCPY(cn_name->data, utf8_str, utf8_out_len);
[ + - ]
322 : 823 : cn_name->size = utf8_out_len;
323 : : /* normalize cn_name to lowercase */
324 [ - + ]: 823 : POSIX_GUARD(s2n_blob_char_to_lower(cn_name));
325 : 823 : }
326 : 828 : }
327 : :
328 : 826 : return 0;
329 : 826 : }
330 : :
331 : : static int s2n_cert_chain_and_key_set_names(struct s2n_cert_chain_and_key *chain_and_key, X509 *cert)
332 : 823 : {
333 [ - + ]: 823 : POSIX_GUARD(s2n_cert_chain_and_key_load_sans(chain_and_key, cert));
334 : : /* For current use cases, we *could* avoid populating the common names if any sans were loaded in
335 : : * s2n_cert_chain_and_key_load_sans. Let's unconditionally populate this field to avoid surprises
336 : : * in the future.
337 : : */
338 [ - + ]: 823 : POSIX_GUARD(s2n_cert_chain_and_key_load_cns(chain_and_key, cert));
339 : 823 : return 0;
340 : 823 : }
341 : :
342 : : int s2n_cert_chain_and_key_load(struct s2n_cert_chain_and_key *chain_and_key)
343 : 837 : {
344 [ # # ][ - + ]: 837 : POSIX_ENSURE_REF(chain_and_key);
345 [ # # ][ - + ]: 837 : POSIX_ENSURE_REF(chain_and_key->cert_chain);
346 [ - + ][ # # ]: 837 : POSIX_ENSURE_REF(chain_and_key->cert_chain->head);
347 [ # # ][ - + ]: 837 : POSIX_ENSURE_REF(chain_and_key->private_key);
348 : 837 : struct s2n_cert *head = chain_and_key->cert_chain->head;
349 : :
350 : 837 : DEFER_CLEANUP(X509 *leaf_cert = NULL, X509_free_pointer);
351 [ - + ]: 837 : POSIX_GUARD_RESULT(s2n_openssl_x509_parse(&head->raw, &leaf_cert));
352 [ - + ]: 837 : POSIX_GUARD_RESULT(s2n_openssl_x509_get_cert_info(leaf_cert, &head->info));
353 : :
354 : : /* Parse the leaf cert for the public key and certificate type */
355 : 837 : DEFER_CLEANUP(struct s2n_pkey public_key = { 0 }, s2n_pkey_free);
356 : 837 : s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN;
357 [ - + ]: 837 : POSIX_GUARD_RESULT(s2n_pkey_from_x509(leaf_cert, &public_key, &pkey_type));
358 : :
359 [ - + ][ # # ]: 837 : POSIX_ENSURE(pkey_type != S2N_PKEY_TYPE_UNKNOWN, S2N_ERR_CERT_TYPE_UNSUPPORTED);
360 [ - + ]: 837 : POSIX_GUARD(s2n_cert_set_cert_type(head, pkey_type));
361 : :
362 : : /* Validate the leaf cert's public key matches the provided private key */
363 [ + + ]: 837 : if (s2n_pkey_check_key_exists(chain_and_key->private_key) == S2N_SUCCESS) {
364 [ + + ]: 756 : POSIX_GUARD(s2n_pkey_match(&public_key, chain_and_key->private_key));
365 : 756 : }
366 : :
367 : : /* Populate name information from the SAN/CN for the leaf certificate */
368 [ - + ]: 823 : POSIX_GUARD(s2n_cert_chain_and_key_set_names(chain_and_key, leaf_cert));
369 : :
370 : : /* populate libcrypto nid's required for cert restrictions */
371 : 823 : struct s2n_cert *current = head->next;
372 [ + + ]: 1840 : while (current != NULL) {
373 : 1017 : DEFER_CLEANUP(X509 *parsed_cert = NULL, X509_free_pointer);
374 [ - + ]: 1017 : POSIX_GUARD_RESULT(s2n_openssl_x509_parse(¤t->raw, &parsed_cert));
375 [ - + ]: 1017 : POSIX_GUARD_RESULT(s2n_openssl_x509_get_cert_info(parsed_cert, ¤t->info));
376 : :
377 : 1017 : current = current->next;
378 : 1017 : }
379 : :
380 : 823 : return S2N_SUCCESS;
381 : 823 : }
382 : :
383 : : int s2n_cert_chain_and_key_load_pem(struct s2n_cert_chain_and_key *chain_and_key, const char *chain_pem, const char *private_key_pem)
384 : 750 : {
385 [ # # ][ - + ]: 750 : POSIX_ENSURE_REF(chain_and_key);
386 : :
387 [ + + ]: 750 : POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain(chain_and_key, chain_pem));
388 [ + + ]: 747 : POSIX_GUARD(s2n_cert_chain_and_key_set_private_key(chain_and_key, private_key_pem));
389 : :
390 [ + + ]: 744 : POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
391 : :
392 : 736 : return S2N_SUCCESS;
393 : 744 : }
394 : :
395 : : int s2n_cert_chain_and_key_load_public_pem_bytes(struct s2n_cert_chain_and_key *chain_and_key, uint8_t *chain_pem, uint32_t chain_pem_len)
396 : 81 : {
397 [ - + ][ # # ]: 81 : POSIX_ENSURE_REF(chain_and_key);
398 [ - + ]: 81 : POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_bytes(chain_and_key, chain_pem, chain_pem_len));
399 [ - + ]: 81 : POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
400 : 81 : return S2N_SUCCESS;
401 : 81 : }
402 : :
403 : : int s2n_cert_chain_and_key_load_pem_bytes(struct s2n_cert_chain_and_key *chain_and_key, uint8_t *chain_pem,
404 : : uint32_t chain_pem_len, uint8_t *private_key_pem, uint32_t private_key_pem_len)
405 : 12 : {
406 [ - + ][ # # ]: 12 : POSIX_ENSURE_REF(chain_and_key);
407 : :
408 [ - + ]: 12 : POSIX_GUARD(s2n_cert_chain_and_key_set_cert_chain_bytes(chain_and_key, chain_pem, chain_pem_len));
409 [ - + ]: 12 : POSIX_GUARD(s2n_cert_chain_and_key_set_private_key_bytes(chain_and_key, private_key_pem, private_key_pem_len));
410 : :
411 [ + + ]: 12 : POSIX_GUARD(s2n_cert_chain_and_key_load(chain_and_key));
412 : :
413 : 6 : return S2N_SUCCESS;
414 : 12 : }
415 : :
416 : : S2N_CLEANUP_RESULT s2n_cert_chain_and_key_ptr_free(struct s2n_cert_chain_and_key **cert_and_key)
417 : 512 : {
418 [ - + ][ # # ]: 512 : RESULT_ENSURE_REF(cert_and_key);
419 [ - + ]: 512 : RESULT_GUARD_POSIX(s2n_cert_chain_and_key_free(*cert_and_key));
420 : 512 : *cert_and_key = NULL;
421 : 512 : return S2N_RESULT_OK;
422 : 512 : }
423 : :
424 : : int s2n_cert_chain_and_key_free(struct s2n_cert_chain_and_key *cert_and_key)
425 : 988 : {
426 [ + + ]: 988 : if (cert_and_key == NULL) {
427 : 52 : return 0;
428 : 52 : }
429 : :
430 : : /* Walk the chain and free the certs */
431 [ + - ]: 936 : if (cert_and_key->cert_chain) {
432 : 936 : struct s2n_cert *node = cert_and_key->cert_chain->head;
433 [ + + ]: 3009 : while (node) {
434 : : /* Free the cert */
435 [ - + ]: 2073 : POSIX_GUARD(s2n_free(&node->raw));
436 : : /* update head so it won't point to freed memory */
437 : 2073 : cert_and_key->cert_chain->head = node->next;
438 : : /* Free the node */
439 [ - + ]: 2073 : POSIX_GUARD(s2n_free_object((uint8_t **) &node, sizeof(struct s2n_cert)));
440 : 2073 : node = cert_and_key->cert_chain->head;
441 : 2073 : }
442 : :
443 [ - + ]: 936 : POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key->cert_chain, sizeof(struct s2n_cert_chain)));
444 : 936 : }
445 : :
446 [ + + ]: 936 : if (cert_and_key->private_key) {
447 [ - + ]: 930 : POSIX_GUARD(s2n_pkey_free(cert_and_key->private_key));
448 [ - + ]: 930 : POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key->private_key, sizeof(s2n_cert_private_key)));
449 : 930 : }
450 : :
451 : 936 : uint32_t len = 0;
452 : :
453 [ + - ]: 936 : if (cert_and_key->san_names) {
454 [ - + ]: 936 : POSIX_GUARD_RESULT(s2n_array_num_elements(cert_and_key->san_names, &len));
455 [ + + ]: 1651 : for (uint32_t i = 0; i < len; i++) {
456 : 715 : struct s2n_blob *san_name = NULL;
457 [ - + ]: 715 : POSIX_GUARD_RESULT(s2n_array_get(cert_and_key->san_names, i, (void **) &san_name));
458 [ - + ]: 715 : POSIX_GUARD(s2n_free(san_name));
459 : 715 : }
460 [ - + ]: 936 : POSIX_GUARD_RESULT(s2n_array_free(cert_and_key->san_names));
461 : 936 : cert_and_key->san_names = NULL;
462 : 936 : }
463 : :
464 [ + - ]: 936 : if (cert_and_key->cn_names) {
465 [ - + ]: 936 : POSIX_GUARD_RESULT(s2n_array_num_elements(cert_and_key->cn_names, &len));
466 [ + + ]: 1759 : for (uint32_t i = 0; i < len; i++) {
467 : 823 : struct s2n_blob *cn_name = NULL;
468 [ - + ]: 823 : POSIX_GUARD_RESULT(s2n_array_get(cert_and_key->cn_names, i, (void **) &cn_name));
469 [ - + ]: 823 : POSIX_GUARD(s2n_free(cn_name));
470 : 823 : }
471 [ - + ]: 936 : POSIX_GUARD_RESULT(s2n_array_free(cert_and_key->cn_names));
472 : 936 : cert_and_key->cn_names = NULL;
473 : 936 : }
474 : :
475 [ - + ]: 936 : POSIX_GUARD(s2n_free(&cert_and_key->ocsp_status));
476 [ - + ]: 936 : POSIX_GUARD(s2n_free(&cert_and_key->sct_list));
477 : :
478 [ - + ]: 936 : POSIX_GUARD(s2n_free_object((uint8_t **) &cert_and_key, sizeof(struct s2n_cert_chain_and_key)));
479 : 936 : return 0;
480 : 936 : }
481 : :
482 : : int s2n_cert_chain_free(struct s2n_cert_chain *cert_chain)
483 : 1 : {
484 : : /* Walk the chain and free the certs/nodes allocated prior to failure */
485 [ + - ]: 1 : if (cert_chain) {
486 : 1 : struct s2n_cert *node = cert_chain->head;
487 [ - + ]: 1 : while (node) {
488 : : /* Free the cert */
489 [ # # ]: 0 : POSIX_GUARD(s2n_free(&node->raw));
490 : : /* update head so it won't point to freed memory */
491 : 0 : cert_chain->head = node->next;
492 : : /* Free the node */
493 [ # # ]: 0 : POSIX_GUARD(s2n_free_object((uint8_t **) &node, sizeof(struct s2n_cert)));
494 : 0 : node = cert_chain->head;
495 : 0 : }
496 : 1 : }
497 : :
498 : 1 : return S2N_SUCCESS;
499 : 1 : }
500 : :
501 : : int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key)
502 : 5947 : {
503 [ - + ][ # # ]: 5947 : POSIX_ENSURE_REF(conn);
504 [ - + ][ # # ]: 5947 : POSIX_ENSURE_REF(out);
505 [ - + ][ # # ]: 5947 : POSIX_ENSURE_REF(chain_and_key);
506 : 5947 : struct s2n_cert_chain *chain = chain_and_key->cert_chain;
507 [ - + ][ # # ]: 5947 : POSIX_ENSURE_REF(chain);
508 : 5947 : struct s2n_cert *cur_cert = chain->head;
509 [ - + ][ # # ]: 5947 : POSIX_ENSURE_REF(cur_cert);
510 : :
511 : 5947 : struct s2n_stuffer_reservation cert_chain_size = { 0 };
512 [ - + ]: 5947 : POSIX_GUARD(s2n_stuffer_reserve_uint24(out, &cert_chain_size));
513 : :
514 : : /* Send certs and extensions (in TLS 1.3) */
515 : 5947 : bool first_entry = true;
516 [ + + ]: 21459 : while (cur_cert) {
517 [ - + ][ # # ]: 15512 : POSIX_ENSURE_REF(cur_cert);
518 [ - + ]: 15512 : POSIX_GUARD(s2n_stuffer_write_uint24(out, cur_cert->raw.size));
519 [ - + ]: 15512 : POSIX_GUARD(s2n_stuffer_write_bytes(out, cur_cert->raw.data, cur_cert->raw.size));
520 : :
521 : : /* According to https://tools.ietf.org/html/rfc8446#section-4.4.2,
522 : : * If an extension applies to the entire chain, it SHOULD be included in
523 : : * the first CertificateEntry.
524 : : * While the spec allow extensions to be included in other certificate
525 : : * entries, only the first matter to use here */
526 [ + + ]: 15512 : if (conn->actual_protocol_version >= S2N_TLS13) {
527 [ + + ]: 8730 : if (first_entry) {
528 [ - + ]: 3473 : POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERTIFICATE, conn, out));
529 : 3473 : first_entry = false;
530 : 5257 : } else {
531 [ - + ]: 5257 : POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_EMPTY, conn, out));
532 : 5257 : }
533 : 8730 : }
534 : 15512 : cur_cert = cur_cert->next;
535 : 15512 : }
536 : :
537 [ - + ]: 5947 : POSIX_GUARD(s2n_stuffer_write_vector_size(&cert_chain_size));
538 : :
539 : 5947 : return 0;
540 : 5947 : }
541 : :
542 : : int s2n_send_empty_cert_chain(struct s2n_stuffer *out)
543 : 34 : {
544 [ # # ][ - + ]: 34 : POSIX_ENSURE_REF(out);
545 [ - + ]: 34 : POSIX_GUARD(s2n_stuffer_write_uint24(out, 0));
546 : 34 : return 0;
547 : 34 : }
548 : :
549 : : static int s2n_does_cert_san_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
550 : 0 : {
551 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(chain_and_key);
552 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(dns_name);
553 : :
554 : 0 : struct s2n_array *san_names = chain_and_key->san_names;
555 : 0 : uint32_t len = 0;
556 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_array_num_elements(san_names, &len));
557 [ # # ]: 0 : for (uint32_t i = 0; i < len; i++) {
558 : 0 : struct s2n_blob *san_name = NULL;
559 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_array_get(san_names, i, (void **) &san_name));
560 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(san_name);
561 [ # # ][ # # ]: 0 : if ((dns_name->size == san_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) san_name->data, dns_name->size) == 0)) {
562 : 0 : return 1;
563 : 0 : }
564 : 0 : }
565 : :
566 : 0 : return 0;
567 : 0 : }
568 : :
569 : : static int s2n_does_cert_cn_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
570 : 0 : {
571 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(chain_and_key);
572 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(dns_name);
573 : :
574 : 0 : struct s2n_array *cn_names = chain_and_key->cn_names;
575 : 0 : uint32_t len = 0;
576 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_array_num_elements(cn_names, &len));
577 [ # # ]: 0 : for (uint32_t i = 0; i < len; i++) {
578 : 0 : struct s2n_blob *cn_name = NULL;
579 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_array_get(cn_names, i, (void **) &cn_name));
580 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(cn_name);
581 [ # # ][ # # ]: 0 : if ((dns_name->size == cn_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) cn_name->data, dns_name->size) == 0)) {
582 : 0 : return 1;
583 : 0 : }
584 : 0 : }
585 : :
586 : 0 : return 0;
587 : 0 : }
588 : :
589 : : int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name)
590 : 0 : {
591 : 0 : uint32_t len = 0;
592 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_array_num_elements(chain_and_key->san_names, &len));
593 [ # # ]: 0 : if (len > 0) {
594 [ # # ]: 0 : if (s2n_does_cert_san_match_hostname(chain_and_key, dns_name)) {
595 : 0 : return 1;
596 : 0 : }
597 : 0 : } else {
598 : : /* Per https://tools.ietf.org/html/rfc6125#section-6.4.4 we only will
599 : : * consider the CN for matching if no valid DNS entries are provided
600 : : * in a SAN.
601 : : */
602 [ # # ]: 0 : if (s2n_does_cert_cn_match_hostname(chain_and_key, dns_name)) {
603 : 0 : return 1;
604 : 0 : }
605 : 0 : }
606 : :
607 : 0 : return 0;
608 : 0 : }
609 : :
610 : : int s2n_cert_chain_and_key_set_ctx(struct s2n_cert_chain_and_key *cert_and_key, void *ctx)
611 : 100 : {
612 [ # # ][ - + ]: 100 : POSIX_ENSURE_REF(cert_and_key);
613 : 100 : cert_and_key->context = ctx;
614 : 100 : return 0;
615 : 100 : }
616 : :
617 : : void *s2n_cert_chain_and_key_get_ctx(struct s2n_cert_chain_and_key *cert_and_key)
618 : 200 : {
619 [ # # ][ - + ]: 200 : PTR_ENSURE_REF(cert_and_key);
620 : 200 : return cert_and_key->context;
621 : 200 : }
622 : :
623 : : s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key)
624 : 2658 : {
625 [ - + ]: 2658 : if (chain_and_key == NULL
626 [ - + ]: 2658 : || chain_and_key->cert_chain == NULL
627 [ - + ]: 2658 : || chain_and_key->cert_chain->head == NULL) {
628 : 0 : return S2N_PKEY_TYPE_UNKNOWN;
629 : 0 : }
630 : 2658 : return chain_and_key->cert_chain->head->pkey_type;
631 : 2658 : }
632 : :
633 : : s2n_cert_private_key *s2n_cert_chain_and_key_get_private_key(struct s2n_cert_chain_and_key *chain_and_key)
634 : 895 : {
635 [ # # ][ - + ]: 895 : PTR_ENSURE_REF(chain_and_key);
636 : 895 : return chain_and_key->private_key;
637 : 895 : }
638 : :
639 : : int s2n_cert_chain_get_length(const struct s2n_cert_chain_and_key *chain_and_key, uint32_t *cert_length)
640 : 31 : {
641 [ + + ][ + - ]: 31 : POSIX_ENSURE_REF(chain_and_key);
642 [ + + ][ + - ]: 30 : POSIX_ENSURE_REF(cert_length);
643 : :
644 : 29 : struct s2n_cert *head_cert = chain_and_key->cert_chain->head;
645 [ # # ][ - + ]: 29 : POSIX_ENSURE_REF(head_cert);
646 : 29 : *cert_length = 1;
647 : 29 : struct s2n_cert *next_cert = head_cert->next;
648 [ + + ]: 233 : while (next_cert != NULL) {
649 : 204 : *cert_length += 1;
650 : 204 : next_cert = next_cert->next;
651 : 204 : }
652 : :
653 : 29 : return S2N_SUCCESS;
654 : 29 : }
655 : :
656 : : int s2n_cert_chain_get_cert(const struct s2n_cert_chain_and_key *chain_and_key, struct s2n_cert **out_cert,
657 : : const uint32_t cert_idx)
658 : 10 : {
659 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(chain_and_key);
660 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(out_cert);
661 : :
662 : 8 : struct s2n_cert *cur_cert = chain_and_key->cert_chain->head;
663 [ # # ][ - + ]: 8 : POSIX_ENSURE_REF(cur_cert);
664 : 8 : uint32_t counter = 0;
665 : :
666 : 8 : struct s2n_cert *next_cert = cur_cert->next;
667 : :
668 [ + + ][ + + ]: 13 : while ((next_cert != NULL) && (counter < cert_idx)) {
669 : 5 : cur_cert = next_cert;
670 : 5 : next_cert = next_cert->next;
671 : 5 : counter++;
672 : 5 : }
673 : :
674 [ + - ][ + + ]: 8 : POSIX_ENSURE(counter == cert_idx, S2N_ERR_NO_CERT_FOUND);
675 [ - + ][ # # ]: 7 : POSIX_ENSURE(cur_cert != NULL, S2N_ERR_NO_CERT_FOUND);
676 : 7 : *out_cert = cur_cert;
677 : :
678 : 7 : return S2N_SUCCESS;
679 : 7 : }
680 : :
681 : : int s2n_cert_get_der(const struct s2n_cert *cert, const uint8_t **out_cert_der, uint32_t *cert_length)
682 : 5 : {
683 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(cert);
684 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(out_cert_der);
685 [ + + ][ + - ]: 3 : POSIX_ENSURE_REF(cert_length);
686 : :
687 : 2 : *cert_length = cert->raw.size;
688 : 2 : *out_cert_der = cert->raw.data;
689 : :
690 : 2 : return S2N_SUCCESS;
691 : 3 : }
692 : :
693 : : static int s2n_asn1_obj_free(ASN1_OBJECT **data)
694 : 17 : {
695 [ + - ]: 17 : if (*data != NULL) {
696 : 17 : ASN1_OBJECT_free(*data);
697 : 17 : }
698 : 17 : return S2N_SUCCESS;
699 : 17 : }
700 : :
701 : : static int s2n_asn1_string_free(ASN1_STRING **data)
702 : 16 : {
703 [ + + ]: 16 : if (*data != NULL) {
704 : 8 : ASN1_STRING_free(*data);
705 : 8 : }
706 : 16 : return S2N_SUCCESS;
707 : 16 : }
708 : :
709 : : static int s2n_utf8_string_from_extension_data(const uint8_t *extension_data, uint32_t extension_len, uint8_t *out_data, uint32_t *out_len)
710 : 16 : {
711 : 16 : DEFER_CLEANUP(ASN1_STRING *asn1_str = NULL, s2n_asn1_string_free);
712 : : /* Note that d2i_ASN1_UTF8STRING increments *der_in to the byte following the parsed data.
713 : : * Using a temporary variable is mandatory to prevent memory free-ing errors.
714 : : * Ref to the warning section here for more information:
715 : : * https://www.openssl.org/docs/man1.1.0/man3/d2i_ASN1_UTF8STRING.html.
716 : : */
717 : 16 : const uint8_t *asn1_str_data = extension_data;
718 : 16 : asn1_str = d2i_ASN1_UTF8STRING(NULL, (const unsigned char **) (void *) &asn1_str_data, extension_len);
719 [ + + ][ + - ]: 16 : POSIX_ENSURE(asn1_str != NULL, S2N_ERR_INVALID_X509_EXTENSION_TYPE);
720 : : /* ASN1_STRING_type() returns the type of `asn1_str`, using standard constants such as V_ASN1_OCTET_STRING.
721 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/ASN1_STRING_type.html.
722 : : */
723 : 8 : int type = ASN1_STRING_type(asn1_str);
724 [ - + ][ # # ]: 8 : POSIX_ENSURE(type == V_ASN1_UTF8STRING, S2N_ERR_INVALID_X509_EXTENSION_TYPE);
725 : :
726 : 8 : int len = ASN1_STRING_length(asn1_str);
727 [ # # ][ - + ]: 8 : POSIX_ENSURE_GTE(len, 0);
728 [ + + ]: 8 : if (out_data != NULL) {
729 [ + - ][ + + ]: 5 : POSIX_ENSURE((int64_t) *out_len >= (int64_t) len, S2N_ERR_INSUFFICIENT_MEM_SIZE);
730 : : /* ASN1_STRING_get0_data(x) returns an internal pointer to the data of
731 : : * x. Since this is an internal pointer it should not be freed or
732 : : * modified in any way.
733 : : * Ref: https://docs.openssl.org/master/man3/ASN1_STRING_length/
734 : : */
735 : 3 : const unsigned char *internal_data = S2N_ASN1_STRING_DATA(asn1_str);
736 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(internal_data);
737 [ - + ][ # # ]: 3 : POSIX_CHECKED_MEMCPY(out_data, internal_data, len);
[ + - ]
738 : 3 : }
739 : 6 : *out_len = len;
740 : 6 : return S2N_SUCCESS;
741 : 8 : }
742 : :
743 : : int s2n_cert_get_utf8_string_from_extension_data_length(const uint8_t *extension_data, uint32_t extension_len, uint32_t *utf8_str_len)
744 : 10 : {
745 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(extension_data);
746 [ + + ][ + - ]: 9 : POSIX_ENSURE_GT(extension_len, 0);
747 [ + - ][ + + ]: 8 : POSIX_ENSURE_REF(utf8_str_len);
748 : :
749 [ + + ]: 7 : POSIX_GUARD(s2n_utf8_string_from_extension_data(extension_data, extension_len, NULL, utf8_str_len));
750 : :
751 : 3 : return S2N_SUCCESS;
752 : 7 : }
753 : :
754 : : int s2n_cert_get_utf8_string_from_extension_data(const uint8_t *extension_data, uint32_t extension_len, uint8_t *out_data, uint32_t *out_len)
755 : 13 : {
756 [ + - ][ + + ]: 13 : POSIX_ENSURE_REF(extension_data);
757 [ + - ][ + + ]: 12 : POSIX_ENSURE_GT(extension_len, 0);
758 [ + + ][ + - ]: 11 : POSIX_ENSURE_REF(out_data);
759 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(out_len);
760 : :
761 [ + + ]: 9 : POSIX_GUARD(s2n_utf8_string_from_extension_data(extension_data, extension_len, out_data, out_len));
762 : :
763 : 3 : return S2N_SUCCESS;
764 : 9 : }
765 : :
766 : : static int s2n_parse_x509_extension(struct s2n_cert *cert, const uint8_t *oid,
767 : : uint8_t *ext_value, uint32_t *ext_value_len, bool *critical)
768 : 17 : {
769 [ - + ][ # # ]: 17 : POSIX_ENSURE_REF(cert->raw.data);
770 : : /* Obtain the openssl x509 cert from the ASN1 DER certificate input.
771 : : * Note that d2i_X509 increments *der_in to the byte following the parsed data.
772 : : * Using a temporary variable is mandatory to prevent memory free-ing errors.
773 : : * Ref to the warning section here for more information:
774 : : * https://www.openssl.org/docs/man1.1.0/man3/d2i_X509.html.
775 : : */
776 : 17 : uint8_t *der_in = cert->raw.data;
777 : 17 : DEFER_CLEANUP(X509 *x509_cert = d2i_X509(NULL, (const unsigned char **) (void *) &der_in, cert->raw.size),
778 : 17 : X509_free_pointer);
779 [ - + ][ # # ]: 17 : POSIX_ENSURE_REF(x509_cert);
780 : :
781 : : /* Retrieve the number of x509 extensions present in the certificate
782 : : * X509_get_ext_count returns the number of extensions in the x509 certificate.
783 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext_count.html.
784 : : */
785 : 17 : int ext_count_value = X509_get_ext_count(x509_cert);
786 [ - + ][ # # ]: 17 : POSIX_ENSURE_GT(ext_count_value, 0);
787 : 17 : size_t ext_count = (size_t) ext_count_value;
788 : :
789 : : /* OBJ_txt2obj() converts the input text string into an ASN1_OBJECT structure.
790 : : * If no_name is 0 then long names and short names will be interpreted as well as numerical forms.
791 : : * If no_name is 1 only the numerical form is acceptable.
792 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/OBJ_txt2obj.html.
793 : : */
794 : 17 : DEFER_CLEANUP(ASN1_OBJECT *asn1_obj_in = OBJ_txt2obj((const char *) oid, 0), s2n_asn1_obj_free);
795 [ # # ][ - + ]: 17 : POSIX_ENSURE_REF(asn1_obj_in);
796 : :
797 [ + + ]: 73 : for (size_t loc = 0; loc < ext_count; loc++) {
798 : 71 : S2N_X509_CONST ASN1_OCTET_STRING *asn1_str = NULL;
799 : 71 : bool match_found = false;
800 : :
801 : : /* Retrieve the x509 extension at location loc.
802 : : * X509_get_ext() retrieves extension loc from x.
803 : : * The index loc can take any value from 0 to X509_get_ext_count(x) - 1.
804 : : * The returned extension is an internal pointer which must not be freed up by the application.
805 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html.
806 : : */
807 : 71 : S2N_X509_CONST X509_EXTENSION *x509_ext = X509_get_ext(x509_cert, loc);
808 [ - + ][ # # ]: 71 : POSIX_ENSURE_REF(x509_ext);
809 : :
810 : : /* Retrieve the extension object/OID/extnId.
811 : : * X509_EXTENSION_get_object() returns the extension type of `x509_ext` as an ASN1_OBJECT pointer.
812 : : * The returned pointer is an internal value which must not be freed up.
813 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_object.html.
814 : : */
815 : 71 : S2N_X509_CONST ASN1_OBJECT *asn1_obj = X509_EXTENSION_get_object(x509_ext);
816 [ # # ][ - + ]: 71 : POSIX_ENSURE_REF(asn1_obj);
817 : :
818 : : /* OBJ_cmp() compares two ASN1_OBJECT objects. If the two are identical 0 is returned.
819 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/OBJ_cmp.html.
820 : : */
821 : 71 : match_found = (0 == OBJ_cmp(asn1_obj_in, asn1_obj));
822 : :
823 : : /* If match found, retrieve the corresponding OID value for the x509 extension */
824 [ + + ]: 71 : if (match_found) {
825 : : /* X509_EXTENSION_get_data() returns the data of extension `x509_ext`.
826 : : * The returned pointer is an internal value which must not be freed up.
827 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_data.html.
828 : : */
829 : 15 : asn1_str = X509_EXTENSION_get_data(x509_ext);
830 [ # # ][ - + ]: 15 : POSIX_ENSURE_REF(asn1_str);
831 : : /* ASN1_STRING_length() returns the length of the content of `asn1_str`.
832 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/ASN1_STRING_length.html.
833 : : */
834 : 15 : int len = ASN1_STRING_length(asn1_str);
835 [ + + ]: 15 : if (ext_value != NULL) {
836 [ - + ][ # # ]: 8 : POSIX_ENSURE_GTE(len, 0);
837 [ + + ][ + - ]: 8 : POSIX_ENSURE(*ext_value_len >= (uint32_t) len, S2N_ERR_INSUFFICIENT_MEM_SIZE);
838 : : /* ASN1_STRING_get0_data(x) returns an internal pointer to the data of
839 : : * x. Since this is an internal pointer it should not be freed or
840 : : * modified in any way.
841 : : * Ref: https://docs.openssl.org/master/man3/ASN1_STRING_length/
842 : : */
843 : 7 : const unsigned char *internal_data = S2N_ASN1_STRING_DATA(asn1_str);
844 [ # # ][ - + ]: 7 : POSIX_ENSURE_REF(internal_data);
845 [ # # ][ - + ]: 7 : POSIX_CHECKED_MEMCPY(ext_value, internal_data, len);
[ + - ]
846 : 7 : }
847 [ + + ]: 14 : if (critical != NULL) {
848 : : /* Retrieve the x509 extension's critical value.
849 : : * X509_EXTENSION_get_critical() returns the criticality of extension `x509_ext`,
850 : : * it returns 1 for critical and 0 for non-critical.
851 : : * Ref: https://www.openssl.org/docs/man1.1.0/man3/X509_EXTENSION_get_critical.html.
852 : : */
853 : 7 : *critical = X509_EXTENSION_get_critical(x509_ext);
854 : 7 : }
855 : 14 : *ext_value_len = len;
856 : 14 : return S2N_SUCCESS;
857 : 15 : }
858 : 71 : }
859 : :
860 [ + - ]: 2 : POSIX_BAIL(S2N_ERR_X509_EXTENSION_VALUE_NOT_FOUND);
861 : 2 : }
862 : :
863 : : int s2n_cert_get_x509_extension_value_length(struct s2n_cert *cert, const uint8_t *oid, uint32_t *ext_value_len)
864 : 11 : {
865 [ + + ][ + - ]: 11 : POSIX_ENSURE_REF(cert);
866 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(oid);
867 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(ext_value_len);
868 : :
869 [ + + ]: 8 : POSIX_GUARD(s2n_parse_x509_extension(cert, oid, NULL, ext_value_len, NULL));
870 : :
871 : 7 : return S2N_SUCCESS;
872 : 8 : }
873 : :
874 : : int s2n_cert_get_x509_extension_value(struct s2n_cert *cert, const uint8_t *oid,
875 : : uint8_t *ext_value, uint32_t *ext_value_len, bool *critical)
876 : 14 : {
877 [ + - ][ + + ]: 14 : POSIX_ENSURE_REF(cert);
878 [ + + ][ + - ]: 13 : POSIX_ENSURE_REF(oid);
879 [ + - ][ + + ]: 12 : POSIX_ENSURE_REF(ext_value);
880 [ + + ][ + - ]: 11 : POSIX_ENSURE_REF(ext_value_len);
881 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(critical);
882 : :
883 [ + + ]: 9 : POSIX_GUARD(s2n_parse_x509_extension(cert, oid, ext_value, ext_value_len, critical));
884 : :
885 : 7 : return S2N_SUCCESS;
886 : 9 : }
887 : :
888 : : /* Maximum buffer size for public key string:
889 : : * - RSA: "rsa" (3) + max digits for key size (5 for 65536) + null = 9 bytes
890 : : * - ECDSA: "ecdsa_secp521r1" (15) + null = 16 bytes
891 : : * - ML-DSA: "mldsa87" (7) + null = 8 bytes
892 : : * Maximum: 16 bytes
893 : : */
894 : : #define S2N_PUBLIC_KEY_STRING_MAX_SIZE 16
895 : :
896 : : S2N_RESULT s2n_cert_info_format_public_key_string(const struct s2n_cert_info *cert_info,
897 : : char *output, uint32_t output_size, uint32_t *required_size)
898 : 212 : {
899 [ - + ][ # # ]: 212 : RESULT_ENSURE_REF(cert_info);
900 [ - + ][ # # ]: 212 : RESULT_ENSURE_REF(required_size);
901 : :
902 : : /* Static NID-to-string lookup table for ECDSA and ML-DSA key types */
903 : 212 : static const struct {
904 : 212 : int nid;
905 : 212 : const char *str;
906 : 212 : } static_mappings[] = {
907 : 212 : { NID_X9_62_prime256v1, "ecdsa_secp256r1" },
908 : 212 : { NID_secp384r1, "ecdsa_secp384r1" },
909 : 212 : { NID_secp521r1, "ecdsa_secp521r1" },
910 : 212 : { S2N_NID_MLDSA44, "mldsa44" },
911 : 212 : { S2N_NID_MLDSA65, "mldsa65" },
912 : 212 : { S2N_NID_MLDSA87, "mldsa87" },
913 : 212 : };
914 : :
915 : 212 : const char *result_str = NULL;
916 : 212 : uint32_t result_size = 0;
917 : 212 : char rsa_buffer[S2N_PUBLIC_KEY_STRING_MAX_SIZE] = { 0 };
918 : :
919 : 212 : int public_key_nid = cert_info->public_key_nid;
920 : :
921 : : /* RSA and RSA-PSS: dynamic format "rsa<bits>" */
922 [ + + ][ + + ]: 212 : if (public_key_nid == NID_rsaEncryption || public_key_nid == NID_rsassaPss) {
923 : 208 : int written = snprintf(rsa_buffer, sizeof(rsa_buffer), "rsa%d", cert_info->public_key_bits);
924 [ - + ][ # # ]: 208 : RESULT_ENSURE_GT(written, 0);
925 [ - + ][ # # ]: 208 : RESULT_ENSURE_LT(written, (int) sizeof(rsa_buffer));
926 : 208 : result_str = rsa_buffer;
927 : 208 : result_size = (uint32_t) written + 1; /* +1 for null terminator */
928 : 208 : } else {
929 : : /* ECDSA and ML-DSA: lookup by public_key_nid */
930 [ + - ]: 7 : for (size_t i = 0; i < s2n_array_len(static_mappings); i++) {
931 [ + - ][ + + ]: 7 : if (public_key_nid != NID_undef && public_key_nid == static_mappings[i].nid) {
932 : 4 : result_str = static_mappings[i].str;
933 : 4 : result_size = strlen(result_str) + 1;
934 : 4 : break;
935 : 4 : }
936 : 7 : }
937 [ # # ][ - + ]: 4 : RESULT_ENSURE(result_str != NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED);
938 : 4 : }
939 : :
940 : : /* result_size includes the null terminator */
941 : 212 : *required_size = result_size;
942 : :
943 : : /* Check if output buffer is provided and large enough */
944 [ - + ][ + + ]: 212 : if (output == NULL || output_size < result_size) {
945 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_INSUFFICIENT_MEM_SIZE);
946 : 1 : }
947 : :
948 : : /* Copy the formatted string to output buffer (including null terminator) */
949 [ - + ][ # # ]: 211 : RESULT_CHECKED_MEMCPY(output, result_str, result_size);
[ + - ]
950 : :
951 : 211 : return S2N_RESULT_OK;
952 : 211 : }
|