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