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