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 : : #include <arpa/inet.h>
17 : : #include <netinet/in.h>
18 : : #include <openssl/asn1.h>
19 : : #include <openssl/err.h>
20 : : #include <openssl/x509.h>
21 : : #include <sys/socket.h>
22 : :
23 : : #include "crypto/s2n_libcrypto.h"
24 : : #include "crypto/s2n_openssl_x509.h"
25 : : #include "crypto/s2n_pkey.h"
26 : : #include "tls/extensions/s2n_extension_list.h"
27 : : #include "tls/s2n_config.h"
28 : : #include "tls/s2n_connection.h"
29 : : #include "tls/s2n_crl.h"
30 : : #include "tls/s2n_security_policies.h"
31 : : #include "utils/s2n_result.h"
32 : : #include "utils/s2n_rfc5952.h"
33 : : #include "utils/s2n_safety.h"
34 : :
35 : : #if S2N_OCSP_STAPLING_SUPPORTED
36 : : #include <openssl/ocsp.h>
37 : : DEFINE_POINTER_CLEANUP_FUNC(OCSP_RESPONSE *, OCSP_RESPONSE_free);
38 : : DEFINE_POINTER_CLEANUP_FUNC(OCSP_BASICRESP *, OCSP_BASICRESP_free);
39 : :
40 : : #endif
41 : :
42 : : #ifndef X509_V_FLAG_PARTIAL_CHAIN
43 : : #define X509_V_FLAG_PARTIAL_CHAIN 0x80000
44 : : #endif
45 : :
46 : 3561407 : #define DEFAULT_MAX_CHAIN_DEPTH 7
47 : : /* Time used by default for nextUpdate if none provided in OCSP: 1 hour since thisUpdate. */
48 : : #define DEFAULT_OCSP_NEXT_UPDATE_PERIOD 3600
49 : :
50 : : /* s2n's internal clock measures epoch-nanoseconds stored with a uint64_t. The
51 : : * maximum representable timestamp is Sunday, July 21, 2554. time_t measures
52 : : * epoch-seconds in a int64_t or int32_t (platform dependent). If time_t is an
53 : : * int32_t, the maximum representable timestamp is January 19, 2038.
54 : : *
55 : : * This means that converting from the internal clock to a time_t is not safe,
56 : : * because the internal clock might hold a value that is too large to represent
57 : : * in a time_t. This constant represents the largest internal clock value that
58 : : * can be safely represented as a time_t.
59 : : */
60 : : #define MAX_32_TIMESTAMP_NANOS 2147483647 * ONE_SEC_IN_NANOS
61 : :
62 : 0 : #define OSSL_VERIFY_CALLBACK_IGNORE_ERROR 1
63 : :
64 : 380 : DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(X509_CRL) *, sk_X509_CRL_free);
65 : : DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(GENERAL_NAME) *, GENERAL_NAMES_free);
66 : :
67 : : uint8_t s2n_x509_ocsp_stapling_supported(void)
68 : 314 : {
69 : 314 : return S2N_OCSP_STAPLING_SUPPORTED;
70 : 314 : }
71 : :
72 : : void s2n_x509_trust_store_init_empty(struct s2n_x509_trust_store *store)
73 : 3004 : {
74 : 3004 : store->trust_store = NULL;
75 : 3004 : }
76 : :
77 : : uint8_t s2n_x509_trust_store_has_certs(struct s2n_x509_trust_store *store)
78 : 417 : {
79 [ + + ]: 417 : return store->trust_store ? (uint8_t) 1 : (uint8_t) 0;
80 : 417 : }
81 : :
82 : : int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char *pem)
83 : 56 : {
84 [ - + ][ # # ]: 56 : POSIX_ENSURE_REF(store);
85 [ - + ][ # # ]: 56 : POSIX_ENSURE_REF(pem);
86 : :
87 [ + + ]: 56 : if (!store->trust_store) {
88 : 35 : store->trust_store = X509_STORE_new();
89 : 35 : }
90 : :
91 : 56 : DEFER_CLEANUP(struct s2n_stuffer pem_in_stuffer = { 0 }, s2n_stuffer_free);
92 : 56 : DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = { 0 }, s2n_stuffer_free);
93 : :
94 [ - + ]: 56 : POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem));
95 [ - + ]: 56 : POSIX_GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048));
96 : :
97 : 274 : do {
98 : 274 : DEFER_CLEANUP(struct s2n_blob next_cert = { 0 }, s2n_free);
99 : :
100 [ + + ]: 274 : POSIX_GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer));
101 [ - + ]: 273 : POSIX_GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer)));
102 [ - + ]: 273 : POSIX_GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert));
103 : :
104 : 273 : const uint8_t *data = next_cert.data;
105 : 273 : DEFER_CLEANUP(X509 *ca_cert = d2i_X509(NULL, &data, next_cert.size), X509_free_pointer);
106 [ - + ][ # # ]: 273 : S2N_ERROR_IF(ca_cert == NULL, S2N_ERR_DECODE_CERTIFICATE);
107 : :
108 [ - + ]: 273 : if (!X509_STORE_add_cert(store->trust_store, ca_cert)) {
109 : 0 : unsigned long error = ERR_get_error();
110 [ # # ][ # # ]: 0 : POSIX_ENSURE(ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE, S2N_ERR_DECODE_CERTIFICATE);
111 : 0 : }
112 [ + + ]: 273 : } while (s2n_stuffer_data_available(&pem_in_stuffer));
113 : :
114 : 55 : return 0;
115 : 56 : }
116 : :
117 : : int s2n_x509_trust_store_from_ca_file(struct s2n_x509_trust_store *store, const char *ca_pem_filename, const char *ca_dir)
118 : 318 : {
119 [ + + ]: 318 : if (!store->trust_store) {
120 : 107 : store->trust_store = X509_STORE_new();
121 [ - + ][ # # ]: 107 : POSIX_ENSURE_REF(store->trust_store);
122 : 107 : }
123 : :
124 : 318 : int err_code = X509_STORE_load_locations(store->trust_store, ca_pem_filename, ca_dir);
125 [ + + ]: 318 : if (!err_code) {
126 : 2 : s2n_x509_trust_store_wipe(store);
127 [ + - ]: 2 : POSIX_BAIL(S2N_ERR_X509_TRUST_STORE);
128 : 2 : }
129 : :
130 : 316 : return 0;
131 : 318 : }
132 : :
133 : : void s2n_x509_trust_store_wipe(struct s2n_x509_trust_store *store)
134 : 3656 : {
135 [ + + ]: 3656 : if (store->trust_store) {
136 : 2634 : X509_STORE_free(store->trust_store);
137 : 2634 : store->trust_store = NULL;
138 : 2634 : store->loaded_system_certs = false;
139 : 2634 : }
140 : 3656 : }
141 : :
142 : : int s2n_x509_validator_init_no_x509_validation(struct s2n_x509_validator *validator)
143 : 10255 : {
144 [ - + ][ # # ]: 10255 : POSIX_ENSURE_REF(validator);
145 : 10255 : validator->trust_store = NULL;
146 : 10255 : validator->store_ctx = NULL;
147 : 10255 : validator->skip_cert_validation = 1;
148 : 10255 : validator->check_stapled_ocsp = 0;
149 : 10255 : validator->max_chain_depth = DEFAULT_MAX_CHAIN_DEPTH;
150 : 10255 : validator->state = INIT;
151 : 10255 : validator->cert_chain_from_wire = sk_X509_new_null();
152 : 10255 : validator->crl_lookup_list = NULL;
153 : 10255 : validator->cert_validation_info = (struct s2n_cert_validation_info){ 0 };
154 : 10255 : validator->cert_validation_cb_invoked = false;
155 : :
156 : 10255 : return 0;
157 : 10255 : }
158 : :
159 : : int s2n_x509_validator_init(struct s2n_x509_validator *validator, struct s2n_x509_trust_store *trust_store, uint8_t check_ocsp)
160 : 3551152 : {
161 [ - + ][ # # ]: 3551152 : POSIX_ENSURE_REF(trust_store);
162 : 3551152 : validator->trust_store = trust_store;
163 : 3551152 : validator->skip_cert_validation = 0;
164 : 3551152 : validator->check_stapled_ocsp = check_ocsp;
165 : 3551152 : validator->max_chain_depth = DEFAULT_MAX_CHAIN_DEPTH;
166 : 3551152 : validator->store_ctx = NULL;
167 [ + + ]: 3551152 : if (validator->trust_store->trust_store) {
168 : 3549831 : validator->store_ctx = X509_STORE_CTX_new();
169 [ - + ][ # # ]: 3549831 : POSIX_ENSURE_REF(validator->store_ctx);
170 : 3549831 : }
171 : 3551152 : validator->cert_chain_from_wire = sk_X509_new_null();
172 : 3551152 : validator->state = INIT;
173 : 3551152 : validator->crl_lookup_list = NULL;
174 : 3551152 : validator->cert_validation_info = (struct s2n_cert_validation_info){ 0 };
175 : 3551152 : validator->cert_validation_cb_invoked = false;
176 : :
177 : 3551152 : return 0;
178 : 3551152 : }
179 : :
180 : : static inline void wipe_cert_chain(STACK_OF(X509) *cert_chain)
181 : 7236742 : {
182 [ + + ]: 7236742 : if (cert_chain) {
183 : 3561407 : sk_X509_pop_free(cert_chain, X509_free);
184 : 3561407 : }
185 : 7236742 : }
186 : :
187 : : int s2n_x509_validator_wipe(struct s2n_x509_validator *validator)
188 : 7236742 : {
189 [ + + ]: 7236742 : if (validator->store_ctx) {
190 : 3549831 : X509_STORE_CTX_free(validator->store_ctx);
191 : 3549831 : validator->store_ctx = NULL;
192 : 3549831 : }
193 : 7236742 : wipe_cert_chain(validator->cert_chain_from_wire);
194 : 7236742 : validator->cert_chain_from_wire = NULL;
195 : 7236742 : validator->trust_store = NULL;
196 : 7236742 : validator->skip_cert_validation = 0;
197 : 7236742 : validator->state = UNINIT;
198 : 7236742 : validator->max_chain_depth = 0;
199 [ + + ]: 7236742 : if (validator->crl_lookup_list) {
200 [ - + ]: 17 : POSIX_GUARD_RESULT(s2n_array_free(validator->crl_lookup_list));
201 : 17 : validator->crl_lookup_list = NULL;
202 : 17 : }
203 : :
204 : 7236742 : return S2N_SUCCESS;
205 : 7236742 : }
206 : :
207 : : int s2n_x509_validator_set_max_chain_depth(struct s2n_x509_validator *validator, uint16_t max_depth)
208 : 3 : {
209 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(validator);
210 [ + + ][ + - ]: 3 : S2N_ERROR_IF(max_depth == 0, S2N_ERR_INVALID_ARGUMENT);
211 : :
212 : 2 : validator->max_chain_depth = max_depth;
213 : 2 : return 0;
214 : 3 : }
215 : :
216 : : static S2N_RESULT s2n_verify_host_information_san_entry(struct s2n_connection *conn, GENERAL_NAME *current_name, bool *san_found)
217 : 341 : {
218 [ - + ][ # # ]: 341 : RESULT_ENSURE_REF(conn);
219 [ # # ][ - + ]: 341 : RESULT_ENSURE_REF(current_name);
220 [ - + ][ # # ]: 341 : RESULT_ENSURE_REF(san_found);
221 : :
222 [ + + ][ + + ]: 341 : if (current_name->type == GEN_DNS || current_name->type == GEN_URI) {
223 : 339 : *san_found = true;
224 : :
225 : 339 : const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5);
226 [ # # ][ - + ]: 339 : RESULT_ENSURE_REF(name);
227 : 339 : int name_len = ASN1_STRING_length(current_name->d.ia5);
228 [ - + ][ # # ]: 339 : RESULT_ENSURE_GT(name_len, 0);
229 : :
230 [ + + ][ + - ]: 339 : RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
231 : :
232 : 325 : return S2N_RESULT_OK;
233 : 339 : }
234 : :
235 [ + + ]: 2 : if (current_name->type == GEN_IPADD) {
236 : 1 : *san_found = true;
237 : :
238 : : /* try to validate an IP address if it's in the subject alt name. */
239 : 1 : const unsigned char *ip_addr = current_name->d.iPAddress->data;
240 [ # # ][ - + ]: 1 : RESULT_ENSURE_REF(ip_addr);
241 : 1 : int ip_addr_len = current_name->d.iPAddress->length;
242 [ - + ][ # # ]: 1 : RESULT_ENSURE_GT(ip_addr_len, 0);
243 : :
244 [ - + ][ # # ]: 2 : RESULT_STACK_BLOB(address, INET6_ADDRSTRLEN + 1, INET6_ADDRSTRLEN + 1);
[ - + ]
245 : :
246 [ - + ]: 1 : if (ip_addr_len == 4) {
247 [ # # ]: 0 : RESULT_GUARD(s2n_inet_ntop(AF_INET, ip_addr, &address));
248 [ + - ]: 1 : } else if (ip_addr_len == 16) {
249 [ - + ]: 1 : RESULT_GUARD(s2n_inet_ntop(AF_INET6, ip_addr, &address));
250 : 1 : } else {
251 : : /* we aren't able to parse this value so skip it */
252 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
253 : 0 : }
254 : :
255 : : /* strlen should be safe here since we made sure we were null terminated AND that inet_ntop succeeded */
256 : 1 : const char *name = (const char *) address.data;
257 : 1 : size_t name_len = strlen(name);
258 : :
259 [ # # ][ - + ]: 1 : RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
260 : :
261 : 1 : return S2N_RESULT_OK;
262 : 1 : }
263 : :
264 : : /* we don't understand this entry type so skip it */
265 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
266 : 1 : }
267 : :
268 : : static S2N_RESULT s2n_verify_host_information_san(struct s2n_connection *conn, X509 *public_cert, bool *san_found)
269 : 394 : {
270 [ # # ][ - + ]: 394 : RESULT_ENSURE_REF(conn);
271 [ - + ][ # # ]: 394 : RESULT_ENSURE_REF(public_cert);
272 [ - + ][ # # ]: 394 : RESULT_ENSURE_REF(san_found);
273 : :
274 : 394 : *san_found = false;
275 : :
276 : 394 : DEFER_CLEANUP(STACK_OF(GENERAL_NAME) *names_list = NULL, GENERAL_NAMES_free_pointer);
277 : 394 : names_list = X509_get_ext_d2i(public_cert, NID_subject_alt_name, NULL, NULL);
278 [ + - ][ + + ]: 394 : RESULT_ENSURE(names_list, S2N_ERR_CERT_UNTRUSTED);
279 : :
280 : 338 : int n = sk_GENERAL_NAME_num(names_list);
281 [ # # ][ - + ]: 338 : RESULT_ENSURE(n > 0, S2N_ERR_CERT_UNTRUSTED);
282 : :
283 : 338 : s2n_result result = S2N_RESULT_OK;
284 [ + + ]: 353 : for (int i = 0; i < n; i++) {
285 : 341 : GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names_list, i);
286 : :
287 : : /* return success on the first entry that passes verification */
288 : 341 : result = s2n_verify_host_information_san_entry(conn, current_name, san_found);
289 [ + + ]: 341 : if (s2n_result_is_ok(result)) {
290 : 326 : return S2N_RESULT_OK;
291 : 326 : }
292 : 341 : }
293 : :
294 : : /* if an error was set by one of the entries, then just propagate the error from the last SAN entry call */
295 [ + - ]: 12 : RESULT_GUARD(result);
296 : :
297 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
298 : 0 : }
299 : :
300 : : static S2N_RESULT s2n_verify_host_information_common_name(struct s2n_connection *conn, X509 *public_cert, bool *cn_found)
301 : 57 : {
302 [ - + ][ # # ]: 57 : RESULT_ENSURE_REF(conn);
303 [ - + ][ # # ]: 57 : RESULT_ENSURE_REF(public_cert);
304 [ # # ][ - + ]: 57 : RESULT_ENSURE_REF(cn_found);
305 : :
306 : 57 : X509_NAME *subject_name = X509_get_subject_name(public_cert);
307 [ - + ][ # # ]: 57 : RESULT_ENSURE(subject_name, S2N_ERR_CERT_UNTRUSTED);
308 : :
309 : 57 : int curr_idx = -1;
310 : 113 : while (true) {
311 : 113 : int next_idx = X509_NAME_get_index_by_NID(subject_name, NID_commonName, curr_idx);
312 [ + + ]: 113 : if (next_idx >= 0) {
313 : 56 : curr_idx = next_idx;
314 : 57 : } else {
315 : 57 : break;
316 : 57 : }
317 : 113 : }
318 : :
319 [ + - ][ + + ]: 57 : RESULT_ENSURE(curr_idx >= 0, S2N_ERR_CERT_UNTRUSTED);
320 : :
321 : 56 : ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, curr_idx));
322 [ - + ][ # # ]: 56 : RESULT_ENSURE(common_name, S2N_ERR_CERT_UNTRUSTED);
323 : :
324 : : /* X520CommonName allows the following ANSI string types per RFC 5280 Appendix A.1 */
325 [ # # ][ - + ]: 56 : RESULT_ENSURE(ASN1_STRING_type(common_name) == V_ASN1_TELETEXSTRING
[ # # ][ - + ]
[ - + ][ + - ]
326 : 56 : || ASN1_STRING_type(common_name) == V_ASN1_PRINTABLESTRING
327 : 56 : || ASN1_STRING_type(common_name) == V_ASN1_UNIVERSALSTRING
328 : 56 : || ASN1_STRING_type(common_name) == V_ASN1_UTF8STRING
329 : 56 : || ASN1_STRING_type(common_name) == V_ASN1_BMPSTRING,
330 : 56 : S2N_ERR_CERT_UNTRUSTED);
331 : :
332 : : /* at this point we have a valid CN value */
333 : 56 : *cn_found = true;
334 : :
335 : 56 : char peer_cn[255] = { 0 };
336 : 56 : int cn_len = ASN1_STRING_length(common_name);
337 [ - + ][ # # ]: 56 : RESULT_ENSURE_GT(cn_len, 0);
338 : 56 : uint32_t len = (uint32_t) cn_len;
339 [ - + ][ # # ]: 56 : RESULT_ENSURE_LTE(len, s2n_array_len(peer_cn) - 1);
340 [ - + ][ # # ]: 56 : RESULT_CHECKED_MEMCPY(peer_cn, ASN1_STRING_data(common_name), len);
[ + - ]
341 : :
342 : : /* According to https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4,
343 : : * the CN fallback only applies to fully qualified DNS domain names.
344 : : *
345 : : * An IP address is not a fully qualified DNS domain name. Per RFC 6125
346 : : * section 6.2.1, IP reference identities must only be matched against
347 : : * iPAddress SAN entries, never against CN values. Reject the CN if it
348 : : * parses as an IPv4 or IPv6 address.
349 : : */
350 : 56 : unsigned char ip_buf[sizeof(struct in6_addr)] = { 0 };
351 [ + + ][ + + ]: 56 : if (inet_pton(AF_INET, peer_cn, ip_buf) == 1 || inet_pton(AF_INET6, peer_cn, ip_buf) == 1) {
352 [ + - ]: 2 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
353 : 2 : }
354 : :
355 [ - + ][ # # ]: 54 : RESULT_ENSURE(conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
356 : :
357 : 54 : return S2N_RESULT_OK;
358 : 54 : }
359 : :
360 : : /*
361 : : * For each name in the cert. Iterate them. Call the callback. If one returns true, then consider it validated,
362 : : * if none of them return true, the cert is considered invalid.
363 : : */
364 : : static S2N_RESULT s2n_verify_host_information(struct s2n_connection *conn, X509 *public_cert)
365 : 394 : {
366 : 394 : bool entry_found = false;
367 : :
368 : : /* Check SubjectAltNames before CommonName as per RFC 6125 6.4.4 */
369 : 394 : s2n_result result = s2n_verify_host_information_san(conn, public_cert, &entry_found);
370 : :
371 : : /*
372 : : *= https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4
373 : : *# As noted, a client MUST NOT seek a match for a reference identifier
374 : : *# of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
375 : : *# URI-ID, or any application-specific identifier types supported by the
376 : : *# client.
377 : : */
378 [ + + ]: 394 : if (entry_found) {
379 : 337 : return result;
380 : 337 : }
381 : :
382 : : /*
383 : : *= https://www.rfc-editor.org/rfc/rfc6125#section-6.4.4
384 : : *# Therefore, if and only if the presented identifiers do not include a
385 : : *# DNS-ID, SRV-ID, URI-ID, or any application-specific identifier types
386 : : *# supported by the client, then the client MAY as a last resort check
387 : : *# for a string whose form matches that of a fully qualified DNS domain
388 : : *# name in a Common Name field of the subject field (i.e., a CN-ID).
389 : : */
390 : 57 : result = s2n_verify_host_information_common_name(conn, public_cert, &entry_found);
391 [ + + ]: 57 : if (entry_found) {
392 : 56 : return result;
393 : 56 : }
394 : :
395 : : /* make a null-terminated string in case the callback tries to use strlen */
396 : 1 : const char *name = "";
397 : 1 : size_t name_len = 0;
398 : :
399 : : /* at this point, we don't have anything to identify the certificate with so pass an empty string to the callback */
400 [ # # ][ - + ]: 1 : RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_INVALID_HOSTNAME);
401 : :
402 : 1 : return S2N_RESULT_OK;
403 : 1 : }
404 : :
405 : : S2N_RESULT s2n_x509_validator_read_asn1_cert(struct s2n_stuffer *cert_chain_in_stuffer,
406 : : struct s2n_blob *asn1_cert)
407 : 15564 : {
408 : 15564 : uint32_t certificate_size = 0;
409 : :
410 [ - + ]: 15564 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint24(cert_chain_in_stuffer, &certificate_size));
411 [ + + ][ + - ]: 15564 : RESULT_ENSURE(certificate_size > 0, S2N_ERR_CERT_INVALID);
412 [ + - ][ + + ]: 15560 : RESULT_ENSURE(certificate_size <= s2n_stuffer_data_available(cert_chain_in_stuffer), S2N_ERR_CERT_INVALID);
413 : :
414 : 15556 : asn1_cert->size = certificate_size;
415 : 15556 : asn1_cert->data = s2n_stuffer_raw_read(cert_chain_in_stuffer, certificate_size);
416 [ - + ][ # # ]: 15556 : RESULT_ENSURE_REF(asn1_cert->data);
417 : :
418 : 15556 : return S2N_RESULT_OK;
419 : 15556 : }
420 : :
421 : : /**
422 : : * Validates that each certificate in a peer's cert chain contains only signature algorithms in a security policy's
423 : : * certificate_signatures_preference list.
424 : : */
425 : : S2N_RESULT s2n_x509_validator_check_cert_preferences(struct s2n_connection *conn, X509 *cert)
426 : 887 : {
427 [ # # ][ - + ]: 887 : RESULT_ENSURE_REF(conn);
428 [ - + ][ # # ]: 887 : RESULT_ENSURE_REF(cert);
429 : :
430 : 887 : const struct s2n_security_policy *security_policy = NULL;
431 [ - + ]: 887 : RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy));
432 : :
433 : : /**
434 : : * We only restrict the signature algorithm on the certificates in the
435 : : * peer's certificate chain if the certificate_signature_preferences field
436 : : * is set in the security policy. This is contrary to the RFC, which
437 : : * specifies that the signatures in the "signature_algorithms" extension
438 : : * apply to signatures in the certificate chain in certain scenarios, so RFC
439 : : * compliance would imply validating that the certificate chain signature
440 : : * algorithm matches one of the algorithms specified in the
441 : : * "signature_algorithms" extension.
442 : : *
443 : : *= https://www.rfc-editor.org/rfc/rfc5246#section-7.4.2
444 : : *= type=exception
445 : : *= reason=not implemented due to lack of utility
446 : : *# If the client provided a "signature_algorithms" extension, then all
447 : : *# certificates provided by the server MUST be signed by a
448 : : *# hash/signature algorithm pair that appears in that extension.
449 : : *
450 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.3
451 : : *= type=exception
452 : : *= reason=not implemented due to lack of utility
453 : : *# If no "signature_algorithms_cert" extension is present, then the
454 : : *# "signature_algorithms" extension also applies to signatures appearing in
455 : : *# certificates.
456 : : */
457 : 887 : struct s2n_cert_info info = { 0 };
458 [ - + ]: 887 : RESULT_GUARD(s2n_openssl_x509_get_cert_info(cert, &info));
459 : :
460 [ + + ]: 887 : bool certificate_preferences_defined = security_policy->certificate_signature_preferences != NULL
461 [ - + ]: 887 : || security_policy->certificate_key_preferences != NULL;
462 [ + + ][ + + ]: 887 : if (certificate_preferences_defined && !info.self_signed && conn->actual_protocol_version == S2N_TLS13) {
[ + + ]
463 : : /* Ensure that the certificate signature does not use SHA-1. While this check
464 : : * would ideally apply to all connections, we only enforce it when certificate
465 : : * preferences exist to stay backwards compatible.
466 : : */
467 [ + - ][ + + ]: 96 : RESULT_ENSURE(info.signature_digest_nid != NID_sha1, S2N_ERR_CERT_UNTRUSTED);
468 : 96 : }
469 : :
470 [ + + ]: 884 : if (!info.self_signed) {
471 [ + + ]: 636 : RESULT_GUARD(s2n_security_policy_validate_cert_signature(security_policy, &info, S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
472 : 636 : }
473 [ + + ]: 883 : RESULT_GUARD(s2n_security_policy_validate_cert_key(security_policy, &info, S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
474 : :
475 : 882 : return S2N_RESULT_OK;
476 : 883 : }
477 : :
478 : : S2N_RESULT s2n_x509_validator_get_validated_cert_chain(const struct s2n_x509_validator *validator,
479 : : struct s2n_validated_cert_chain *validated_cert_chain)
480 : 711 : {
481 [ # # ][ - + ]: 711 : RESULT_ENSURE_REF(validator);
482 [ # # ][ - + ]: 711 : RESULT_ENSURE_REF(validated_cert_chain);
483 : :
484 [ + - ][ + + ]: 711 : RESULT_ENSURE(s2n_x509_validator_is_cert_chain_validated(validator), S2N_ERR_INVALID_CERT_STATE);
485 [ # # ][ - + ]: 710 : RESULT_ENSURE_REF(validator->store_ctx);
486 : :
487 : 710 : #if S2N_LIBCRYPTO_SUPPORTS_GET0_CHAIN
488 : : /* X509_STORE_CTX_get0_chain is used when available, since it returns a pointer to the
489 : : * validated cert chain in the X509_STORE_CTX, avoiding an allocation/copy.
490 : : */
491 : 710 : validated_cert_chain->stack = X509_STORE_CTX_get0_chain(validator->store_ctx);
492 : : #else
493 : : /* Otherwise, X509_STORE_CTX_get1_chain is used instead, which allocates a new cert chain. */
494 : : validated_cert_chain->stack = X509_STORE_CTX_get1_chain(validator->store_ctx);
495 : : #endif
496 : :
497 [ # # ][ - + ]: 710 : RESULT_ENSURE_REF(validated_cert_chain->stack);
498 : :
499 : 710 : return S2N_RESULT_OK;
500 : 710 : }
501 : :
502 : : S2N_CLEANUP_RESULT s2n_x509_validator_validated_cert_chain_free(struct s2n_validated_cert_chain *validated_cert_chain)
503 : 710 : {
504 [ # # ][ - + ]: 710 : RESULT_ENSURE_REF(validated_cert_chain);
505 : :
506 : : #if !S2N_LIBCRYPTO_SUPPORTS_GET0_CHAIN
507 : : /* When X509_STORE_CTX_get0_chain isn't supported, X509_STORE_CTX_get1_chain is used instead,
508 : : * which allocates a new cert chain that is owned by s2n-tls and MUST be freed.
509 : : *
510 : : * X509_STORE_CTX_get0_chain returns a pointer to the cert chain within the X509_STORE_CTX,
511 : : * which is NOT owned by s2n-tls and MUST NOT be manually freed.
512 : : */
513 : : RESULT_GUARD(s2n_openssl_x509_stack_pop_free(&validated_cert_chain->stack));
514 : : #endif
515 : :
516 : : /* Even though the cert chain reference is still valid in the case that get0_chain is used, set
517 : : * it to null for consistency with the get1_chain case.
518 : : */
519 : 710 : validated_cert_chain->stack = NULL;
520 : :
521 : 710 : return S2N_RESULT_OK;
522 : 710 : }
523 : :
524 : : /* Validates that the root certificate uses a key allowed by the security policy
525 : : * certificate preferences.
526 : : */
527 : : static S2N_RESULT s2n_x509_validator_check_root_cert(struct s2n_x509_validator *validator, struct s2n_connection *conn)
528 : 335 : {
529 [ - + ][ # # ]: 335 : RESULT_ENSURE_REF(validator);
530 [ - + ][ # # ]: 335 : RESULT_ENSURE_REF(conn);
531 : :
532 : 335 : const struct s2n_security_policy *security_policy = NULL;
533 [ - + ]: 335 : RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy));
534 [ # # ][ - + ]: 335 : RESULT_ENSURE_REF(security_policy);
535 : :
536 : 335 : DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
537 [ - + ]: 335 : RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
538 : 335 : STACK_OF(X509) *cert_chain = validated_cert_chain.stack;
539 [ - + ][ # # ]: 335 : RESULT_ENSURE_REF(cert_chain);
540 : :
541 : 335 : const int certs_in_chain = sk_X509_num(cert_chain);
542 [ - + ][ # # ]: 335 : RESULT_ENSURE(certs_in_chain > 0, S2N_ERR_CERT_UNTRUSTED);
543 : 335 : X509 *root = sk_X509_value(cert_chain, certs_in_chain - 1);
544 [ # # ][ - + ]: 335 : RESULT_ENSURE_REF(root);
545 : :
546 : 335 : struct s2n_cert_info info = { 0 };
547 [ - + ]: 335 : RESULT_GUARD(s2n_openssl_x509_get_cert_info(root, &info));
548 : :
549 [ + + ]: 335 : RESULT_GUARD(s2n_security_policy_validate_cert_key(security_policy, &info,
550 : 334 : S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT));
551 : :
552 : 334 : return S2N_RESULT_OK;
553 : 335 : }
554 : :
555 : : static S2N_RESULT s2n_x509_validator_read_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
556 : : uint8_t *cert_chain_in, uint32_t cert_chain_len)
557 : 4957 : {
558 [ + - ][ + + ]: 4957 : RESULT_ENSURE(validator->skip_cert_validation || s2n_x509_trust_store_has_certs(validator->trust_store), S2N_ERR_CERT_UNTRUSTED);
[ + + ]
559 [ - + ][ # # ]: 4954 : RESULT_ENSURE(validator->state == INIT, S2N_ERR_INVALID_CERT_STATE);
560 : :
561 : 4954 : struct s2n_blob cert_chain_blob = { 0 };
562 [ - + ]: 4954 : RESULT_GUARD_POSIX(s2n_blob_init(&cert_chain_blob, cert_chain_in, cert_chain_len));
563 : 4954 : DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = { 0 }, s2n_stuffer_free);
564 : :
565 [ - + ]: 4954 : RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob));
566 [ - + ]: 4954 : RESULT_GUARD_POSIX(s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob));
567 : :
568 [ + + ]: 18010 : while (s2n_stuffer_data_available(&cert_chain_in_stuffer)
569 [ + + ]: 18010 : && sk_X509_num(validator->cert_chain_from_wire) < validator->max_chain_depth) {
570 : 13068 : struct s2n_blob asn1_cert = { 0 };
571 [ + + ]: 13068 : RESULT_GUARD(s2n_x509_validator_read_asn1_cert(&cert_chain_in_stuffer, &asn1_cert));
572 : :
573 : : /* We only do the trailing byte validation when parsing the leaf cert to
574 : : * match historical s2n-tls behavior.
575 : : */
576 : 13060 : DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer);
577 [ + + ]: 13060 : if (sk_X509_num(validator->cert_chain_from_wire) == 0) {
578 [ + + ]: 4946 : RESULT_GUARD(s2n_openssl_x509_parse(&asn1_cert, &cert));
579 : 8114 : } else {
580 [ - + ]: 8114 : RESULT_GUARD(s2n_openssl_x509_parse_without_length_validation(&asn1_cert, &cert));
581 : 8114 : }
582 : :
583 [ + + ]: 13058 : if (!validator->skip_cert_validation) {
584 [ + + ]: 881 : RESULT_GUARD(s2n_x509_validator_check_cert_preferences(conn, cert));
585 : 881 : }
586 : :
587 : : /* add the cert to the chain */
588 [ # # ][ - + ]: 13056 : RESULT_ENSURE(sk_X509_push(validator->cert_chain_from_wire, cert) > 0,
589 : 13056 : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
590 : :
591 : : /* After the cert is added to cert_chain_from_wire, it will be freed
592 : : * with the call to s2n_x509_validator_wipe. We disable the cleanup
593 : : * function since cleanup is no longer "owned" by cert.
594 : : */
595 : 13056 : ZERO_TO_DISABLE_DEFER_CLEANUP(cert);
596 : :
597 : : /* certificate extensions is a field in TLS 1.3 - https://tools.ietf.org/html/rfc8446#section-4.4.2 */
598 [ + + ]: 13056 : if (conn->actual_protocol_version >= S2N_TLS13) {
599 : 6427 : s2n_parsed_extensions_list parsed_extensions_list = { 0 };
600 [ - + ]: 6427 : RESULT_GUARD_POSIX(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list));
601 : 6427 : }
602 : 13056 : }
603 : :
604 : : /* if this occurred we exceeded validator->max_chain_depth */
605 [ + - ][ + + ]: 4942 : RESULT_ENSURE(validator->skip_cert_validation || s2n_stuffer_data_available(&cert_chain_in_stuffer) == 0,
[ + + ]
606 : 4941 : S2N_ERR_CERT_MAX_CHAIN_DEPTH_EXCEEDED);
607 [ + - ][ + + ]: 4941 : RESULT_ENSURE(sk_X509_num(validator->cert_chain_from_wire) > 0, S2N_ERR_NO_CERT_FOUND);
608 : :
609 : 4940 : return S2N_RESULT_OK;
610 : 4941 : }
611 : :
612 : : static S2N_RESULT s2n_x509_validator_process_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
613 : : uint8_t *cert_chain_in, uint32_t cert_chain_len)
614 : 4957 : {
615 [ # # ][ - + ]: 4957 : RESULT_ENSURE(validator->state == INIT, S2N_ERR_INVALID_CERT_STATE);
616 : :
617 [ + + ]: 4957 : RESULT_GUARD(s2n_x509_validator_read_cert_chain(validator, conn, cert_chain_in, cert_chain_len));
618 : :
619 [ + + ]: 4940 : if (validator->skip_cert_validation) {
620 : 4546 : return S2N_RESULT_OK;
621 : 4546 : }
622 : :
623 : 394 : X509 *leaf = sk_X509_value(validator->cert_chain_from_wire, 0);
624 [ # # ][ - + ]: 394 : RESULT_ENSURE_REF(leaf);
625 : :
626 [ + - ]: 394 : if (conn->verify_host_fn) {
627 [ + + ]: 394 : RESULT_GUARD(s2n_verify_host_information(conn, leaf));
628 : 394 : }
629 : :
630 [ # # ][ - + ]: 381 : RESULT_GUARD_OSSL(X509_STORE_CTX_init(validator->store_ctx, validator->trust_store->trust_store, leaf,
631 : 381 : validator->cert_chain_from_wire),
632 : 381 : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
633 : :
634 [ + + ]: 381 : if (conn->config->crl_lookup_cb) {
635 [ + + ]: 17 : RESULT_GUARD(s2n_crl_invoke_lookup_callbacks(conn, validator));
636 [ + + ]: 16 : RESULT_GUARD(s2n_crl_handle_lookup_callback_result(validator));
637 : 16 : }
638 : :
639 : 379 : validator->state = READY_TO_VERIFY;
640 : :
641 : 379 : return S2N_RESULT_OK;
642 : 381 : }
643 : :
644 : : static S2N_RESULT s2n_x509_validator_set_no_check_time_flag(struct s2n_x509_validator *validator)
645 : 8 : {
646 [ - + ][ # # ]: 8 : RESULT_ENSURE_REF(validator);
647 [ # # ][ - + ]: 8 : RESULT_ENSURE_REF(validator->store_ctx);
648 : :
649 : 8 : X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(validator->store_ctx);
650 [ - + ][ # # ]: 8 : RESULT_ENSURE_REF(param);
651 : :
652 : 8 : #ifdef S2N_LIBCRYPTO_SUPPORTS_FLAG_NO_CHECK_TIME
653 [ - + ][ # # ]: 8 : RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_NO_CHECK_TIME),
654 : 8 : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
655 : : #else
656 : : RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
657 : : #endif
658 : :
659 : 8 : return S2N_RESULT_OK;
660 : 8 : }
661 : :
662 : : int s2n_disable_time_validation_ossl_verify_callback(int default_ossl_ret, X509_STORE_CTX *ctx)
663 : 0 : {
664 : 0 : int err = X509_STORE_CTX_get_error(ctx);
665 : 0 : switch (err) {
666 [ # # ]: 0 : case X509_V_ERR_CERT_NOT_YET_VALID:
667 [ # # ]: 0 : case X509_V_ERR_CERT_HAS_EXPIRED:
668 : 0 : return OSSL_VERIFY_CALLBACK_IGNORE_ERROR;
669 [ # # ]: 0 : default:
670 : 0 : break;
671 : 0 : }
672 : :
673 : : /* If CRL validation is enabled, setting the time validation verify callback will override the
674 : : * CRL verify callback. The CRL verify callback is manually triggered to work around this
675 : : * issue.
676 : : *
677 : : * The CRL verify callback ignores validation errors exclusively for CRL timestamp fields. So,
678 : : * if CRL validation isn't enabled, the CRL verify callback is a no-op.
679 : : */
680 : 0 : return s2n_crl_ossl_verify_callback(default_ossl_ret, ctx);
681 : 0 : }
682 : :
683 : : static S2N_RESULT s2n_x509_validator_disable_time_validation(struct s2n_connection *conn,
684 : : struct s2n_x509_validator *validator)
685 : 8 : {
686 [ # # ][ - + ]: 8 : RESULT_ENSURE_REF(conn);
687 [ - + ][ # # ]: 8 : RESULT_ENSURE_REF(conn->config);
688 [ - + ][ # # ]: 8 : RESULT_ENSURE_REF(validator);
689 [ # # ][ - + ]: 8 : RESULT_ENSURE_REF(validator->store_ctx);
690 : :
691 : : /* Setting an X509_STORE verify callback is not recommended with AWS-LC:
692 : : * https://github.com/aws/aws-lc/blob/aa90e509f2e940916fbe9fdd469a4c90c51824f6/include/openssl/x509.h#L2980-L2990
693 : : *
694 : : * If the libcrypto supports the ability to disable time validation with an X509_VERIFY_PARAM
695 : : * NO_CHECK_TIME flag, this method is preferred.
696 : : *
697 : : * However, older versions of AWS-LC and OpenSSL 1.0.2 do not support this flag. In this case,
698 : : * an X509_STORE verify callback is used. This is acceptable in older versions of AWS-LC
699 : : * because the versions are fixed, and updates to AWS-LC will not break the callback
700 : : * implementation.
701 : : */
702 [ + - ]: 8 : if (s2n_libcrypto_supports_flag_no_check_time()) {
703 [ - + ]: 8 : RESULT_GUARD(s2n_x509_validator_set_no_check_time_flag(validator));
704 : 8 : } else {
705 : 0 : X509_STORE_CTX_set_verify_cb(validator->store_ctx,
706 : 0 : s2n_disable_time_validation_ossl_verify_callback);
707 : 0 : }
708 : :
709 : 8 : return S2N_RESULT_OK;
710 : 8 : }
711 : :
712 : : int s2n_no_op_verify_custom_crit_oids_cb(X509_STORE_CTX *ctx, X509 *x509, STACK_OF(ASN1_OBJECT) *oids)
713 : 0 : {
714 : 0 : return 1;
715 : 0 : }
716 : :
717 : : static S2N_RESULT s2n_x509_validator_add_custom_extensions(struct s2n_x509_validator *validator, struct s2n_connection *conn)
718 : 380 : {
719 [ - + ][ # # ]: 380 : RESULT_ENSURE_REF(validator);
720 [ - + ][ # # ]: 380 : RESULT_ENSURE_REF(validator->store_ctx);
721 [ # # ][ - + ]: 380 : RESULT_ENSURE_REF(conn);
722 [ - + ][ # # ]: 380 : RESULT_ENSURE_REF(conn->config);
723 : :
724 [ - + ]: 380 : if (conn->config->custom_x509_extension_oids) {
725 : : #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_OID
726 : : size_t custom_oid_count = sk_ASN1_OBJECT_num(conn->config->custom_x509_extension_oids);
727 : : for (size_t i = 0; i < custom_oid_count; i++) {
728 : : ASN1_OBJECT *critical_oid = sk_ASN1_OBJECT_value(conn->config->custom_x509_extension_oids, i);
729 : : RESULT_ENSURE_REF(critical_oid);
730 : : RESULT_GUARD_OSSL(X509_STORE_CTX_add_custom_crit_oid(validator->store_ctx, critical_oid),
731 : : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
732 : : }
733 : : /* To enable AWS-LC accepting custom extensions, an X509_STORE_CTX_verify_crit_oids_cb must be set.
734 : : * See https://github.com/aws/aws-lc/blob/f0b4afedd7d45fc2517643d890b654856c57f994/include/openssl/x509.h#L2913-L2918.
735 : : *
736 : : * The `X509_STORE_CTX_verify_crit_oids_cb` callback can be used to implement the validation for the
737 : : * custom certificate extensions. However, s2n-tls consumers are expected to implement this validation
738 : : * in the `s2n_cert_validation_callback` instead. So, a no-op callback is provided to AWS-LC.
739 : : */
740 : : X509_STORE_CTX_set_verify_crit_oids(validator->store_ctx, s2n_no_op_verify_custom_crit_oids_cb);
741 : : #else
742 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
743 : 0 : #endif
744 : 0 : }
745 : 380 : return S2N_RESULT_OK;
746 : 380 : }
747 : :
748 : : static S2N_RESULT s2n_x509_validator_verify_intent_for_cert(struct s2n_connection *conn, X509 *cert, bool is_leaf)
749 : 307 : {
750 [ - + ][ # # ]: 307 : RESULT_ENSURE_REF(cert);
751 : :
752 : : /* The X509_PURPOSE values indicate the purpose that certificates must specify. For servers,
753 : : * received client certificates MUST have a TLS client purpose. For clients, received server
754 : : * certificates MUST have a TLS server purpose.
755 : : */
756 : 307 : int purpose = X509_PURPOSE_SSL_CLIENT;
757 [ + + ]: 307 : if (conn->mode == S2N_CLIENT) {
758 : 222 : purpose = X509_PURPOSE_SSL_SERVER;
759 : 222 : }
760 : :
761 [ + + ][ + - ]: 307 : RESULT_GUARD_OSSL(X509_check_purpose(cert, purpose, !is_leaf), S2N_ERR_CERT_INTENT_INVALID);
762 : :
763 : 288 : return S2N_RESULT_OK;
764 : 307 : }
765 : :
766 : : S2N_RESULT s2n_x509_validator_verify_intent(struct s2n_x509_validator *validator, struct s2n_connection *conn)
767 : 354 : {
768 [ - + ][ # # ]: 354 : RESULT_ENSURE_REF(conn);
769 [ - + ][ # # ]: 354 : RESULT_ENSURE_REF(conn->config);
770 : :
771 [ + + ]: 354 : if (conn->config->disable_x509_intent_verification) {
772 : 46 : return S2N_RESULT_OK;
773 : 46 : }
774 : :
775 : 308 : DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
776 [ - + ]: 308 : RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
777 : :
778 : 308 : int cert_count = sk_X509_num(validated_cert_chain.stack);
779 [ # # ][ - + ]: 308 : RESULT_ENSURE_GT(cert_count, 0);
780 : :
781 : : /* The validated cert chain returned from the libcrypto includes the trust anchor. The trust
782 : : * anchor is omitted from intent verification since its TLS intent is implicitly indicated by
783 : : * its presence in the s2n-tls trust store.
784 : : */
785 : 308 : cert_count -= 1;
786 : :
787 [ + + ]: 596 : for (int i = 0; i < cert_count; i++) {
788 : 307 : X509 *cert = sk_X509_value(validated_cert_chain.stack, i);
789 [ - + ][ # # ]: 307 : RESULT_ENSURE_REF(cert);
790 : :
791 : 307 : bool is_leaf = (i == 0);
792 [ + + ]: 307 : RESULT_GUARD(s2n_x509_validator_verify_intent_for_cert(conn, cert, is_leaf));
793 : 307 : }
794 : :
795 : 289 : return S2N_RESULT_OK;
796 : 308 : }
797 : :
798 : : static S2N_RESULT s2n_x509_validator_verify_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn)
799 : 380 : {
800 [ - + ][ # # ]: 380 : RESULT_ENSURE(validator->state == READY_TO_VERIFY, S2N_ERR_INVALID_CERT_STATE);
801 : :
802 : 380 : X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(validator->store_ctx);
803 : 380 : X509_VERIFY_PARAM_set_depth(param, validator->max_chain_depth);
804 : :
805 : 380 : DEFER_CLEANUP(STACK_OF(X509_CRL) *crl_stack = NULL, sk_X509_CRL_free_pointer);
806 : :
807 [ + + ]: 380 : if (conn->config->crl_lookup_cb) {
808 : 16 : X509_STORE_CTX_set_verify_cb(validator->store_ctx, s2n_crl_ossl_verify_callback);
809 : :
810 : 16 : crl_stack = sk_X509_CRL_new_null();
811 [ - + ]: 16 : RESULT_GUARD(s2n_crl_get_crls_from_lookup_list(validator, crl_stack));
812 : :
813 : : /* Set the CRL list that the libcrypto will use to validate certificates with */
814 : 16 : X509_STORE_CTX_set0_crls(validator->store_ctx, crl_stack);
815 : :
816 : : /* Enable CRL validation for certificates in X509_verify_cert */
817 [ - + ][ # # ]: 16 : RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK),
818 : 16 : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
819 : :
820 : : /* Enable CRL validation for all certificates, not just the leaf */
821 [ - + ][ # # ]: 16 : RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK_ALL),
822 : 16 : S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
823 : 16 : }
824 : :
825 : : /* Disabling time validation may set a NO_CHECK_TIME flag on the X509_STORE_CTX. Calling
826 : : * X509_STORE_CTX_set_time will override this flag. To prevent this, X509_STORE_CTX_set_time is
827 : : * only called if time validation is enabled.
828 : : */
829 [ + + ]: 380 : if (conn->config->disable_x509_time_validation) {
830 [ - + ]: 8 : RESULT_GUARD(s2n_x509_validator_disable_time_validation(conn, validator));
831 : 372 : } else {
832 : 372 : uint64_t current_sys_time = 0;
833 [ - + ]: 372 : RESULT_GUARD(s2n_config_wall_clock(conn->config, ¤t_sys_time));
834 : 372 : if (sizeof(time_t) == 4) {
835 : : /* cast value to uint64_t to prevent overflow errors */
836 [ # # ][ # # ]: 0 : RESULT_ENSURE_LTE(current_sys_time, (uint64_t) MAX_32_TIMESTAMP_NANOS);
837 : 0 : }
838 : :
839 : : /* this wants seconds not nanoseconds */
840 : 372 : time_t current_time = (time_t) (current_sys_time / ONE_SEC_IN_NANOS);
841 : 372 : X509_STORE_CTX_set_time(validator->store_ctx, 0, current_time);
842 : 372 : }
843 : :
844 : : /* It's assumed that if a valid certificate chain is received with an issuer that's present in
845 : : * the trust store, the certificate chain should be trusted. This should be the case even if
846 : : * the issuer in the trust store isn't a root certificate. Setting the PARTIAL_CHAIN flag
847 : : * allows the libcrypto to trust certificates in the trust store that aren't root certificates.
848 : : */
849 : 380 : X509_STORE_CTX_set_flags(validator->store_ctx, X509_V_FLAG_PARTIAL_CHAIN);
850 : :
851 [ - + ]: 380 : RESULT_GUARD(s2n_x509_validator_add_custom_extensions(validator, conn));
852 : :
853 : 380 : int verify_ret = X509_verify_cert(validator->store_ctx);
854 [ + + ]: 380 : if (verify_ret <= 0) {
855 : 26 : int ossl_error = X509_STORE_CTX_get_error(validator->store_ctx);
856 : 26 : switch (ossl_error) {
857 [ + + ]: 3 : case X509_V_ERR_CERT_NOT_YET_VALID:
858 [ + - ]: 3 : RESULT_BAIL(S2N_ERR_CERT_NOT_YET_VALID);
859 [ + + ]: 5 : case X509_V_ERR_CERT_HAS_EXPIRED:
860 [ + - ]: 5 : RESULT_BAIL(S2N_ERR_CERT_EXPIRED);
861 [ + + ]: 7 : case X509_V_ERR_CERT_REVOKED:
862 [ + - ]: 7 : RESULT_BAIL(S2N_ERR_CERT_REVOKED);
863 [ + + ]: 1 : case X509_V_ERR_UNABLE_TO_GET_CRL:
864 [ - + ]: 1 : case X509_V_ERR_DIFFERENT_CRL_SCOPE:
865 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_CRL_LOOKUP_FAILED);
866 [ - + ]: 0 : case X509_V_ERR_CRL_SIGNATURE_FAILURE:
867 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CRL_SIGNATURE);
868 [ - + ]: 0 : case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
869 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CRL_ISSUER);
870 [ - + ]: 0 : case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
871 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CRL_UNHANDLED_CRITICAL_EXTENSION);
872 [ - + ]: 0 : case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
873 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_UNHANDLED_CRITICAL_EXTENSION);
874 [ + + ]: 10 : default:
875 [ + - ]: 10 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
876 : 26 : }
877 : 26 : }
878 : :
879 : 354 : validator->state = VALIDATED;
880 : :
881 : 354 : return S2N_RESULT_OK;
882 : 380 : }
883 : :
884 : : static S2N_RESULT s2n_x509_validator_parse_leaf_certificate_extensions(struct s2n_connection *conn,
885 : : uint8_t *cert_chain_in, uint32_t cert_chain_len,
886 : : s2n_parsed_extensions_list *first_certificate_extensions)
887 : 2494 : {
888 : : /* certificate extensions is a field in TLS 1.3 - https://tools.ietf.org/html/rfc8446#section-4.4.2 */
889 [ - + ][ # # ]: 2494 : RESULT_ENSURE_GTE(conn->actual_protocol_version, S2N_TLS13);
890 : :
891 : 2494 : struct s2n_blob cert_chain_blob = { 0 };
892 [ - + ]: 2494 : RESULT_GUARD_POSIX(s2n_blob_init(&cert_chain_blob, cert_chain_in, cert_chain_len));
893 : 2494 : DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = { 0 }, s2n_stuffer_free);
894 : :
895 [ - + ]: 2494 : RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob));
896 [ - + ]: 2494 : RESULT_GUARD_POSIX(s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob));
897 : :
898 : 2494 : struct s2n_blob asn1_cert = { 0 };
899 [ - + ]: 2494 : RESULT_GUARD(s2n_x509_validator_read_asn1_cert(&cert_chain_in_stuffer, &asn1_cert));
900 : :
901 : 2494 : s2n_parsed_extensions_list parsed_extensions_list = { 0 };
902 [ - + ]: 2494 : RESULT_GUARD_POSIX(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list));
903 : 2494 : *first_certificate_extensions = parsed_extensions_list;
904 : :
905 : 2494 : return S2N_RESULT_OK;
906 : 2494 : }
907 : :
908 : : S2N_RESULT s2n_x509_validator_validate_cert_chain_pre_cb(struct s2n_x509_validator *validator, struct s2n_connection *conn,
909 : : uint8_t *cert_chain_in, uint32_t cert_chain_len)
910 : 4977 : {
911 [ - + ][ # # ]: 4977 : RESULT_ENSURE_REF(conn);
912 [ - + ][ # # ]: 4977 : RESULT_ENSURE_REF(conn->config);
913 : :
914 : 4977 : switch (validator->state) {
915 [ + + ]: 4957 : case INIT:
916 : 4957 : break;
917 [ + + ]: 20 : case AWAITING_CRL_CALLBACK:
918 [ + + ]: 20 : RESULT_GUARD(s2n_crl_handle_lookup_callback_result(validator));
919 : 1 : break;
920 [ - + ]: 1 : default:
921 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_INVALID_CERT_STATE);
922 : 4977 : }
923 : :
924 [ + + ]: 4958 : if (validator->state == INIT) {
925 [ + + ]: 4957 : RESULT_GUARD(s2n_x509_validator_process_cert_chain(validator, conn, cert_chain_in, cert_chain_len));
926 : 4957 : }
927 : :
928 [ + + ]: 4926 : if (validator->state == READY_TO_VERIFY) {
929 [ + + ]: 380 : RESULT_GUARD(s2n_x509_validator_verify_cert_chain(validator, conn));
930 [ + + ]: 354 : RESULT_GUARD(s2n_x509_validator_verify_intent(validator, conn));
931 [ + + ]: 335 : RESULT_GUARD(s2n_x509_validator_check_root_cert(validator, conn));
932 : 335 : }
933 : :
934 [ + + ]: 4880 : if (conn->actual_protocol_version >= S2N_TLS13) {
935 : : /* Only process certificate extensions received in the first certificate. Extensions received in all other
936 : : * certificates are ignored.
937 : : *
938 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.4.2
939 : : *# If an extension applies to the entire chain, it SHOULD be included in
940 : : *# the first CertificateEntry.
941 : : */
942 : 2494 : s2n_parsed_extensions_list first_certificate_extensions = { 0 };
943 [ - + ]: 2494 : RESULT_GUARD(s2n_x509_validator_parse_leaf_certificate_extensions(conn, cert_chain_in, cert_chain_len, &first_certificate_extensions));
944 [ - + ]: 2494 : RESULT_GUARD_POSIX(s2n_extension_list_process(S2N_EXTENSION_LIST_CERTIFICATE, conn, &first_certificate_extensions));
945 : 2494 : }
946 : :
947 : 4880 : return S2N_RESULT_OK;
948 : 4880 : }
949 : :
950 : : static S2N_RESULT s2n_x509_validator_handle_cert_validation_callback_result(struct s2n_x509_validator *validator)
951 : 46 : {
952 [ - + ][ # # ]: 46 : RESULT_ENSURE_REF(validator);
953 : :
954 [ + + ]: 46 : if (!validator->cert_validation_info.finished) {
955 [ + - ]: 27 : RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED);
956 : 27 : }
957 : :
958 [ + + ][ + - ]: 19 : RESULT_ENSURE(validator->cert_validation_info.accepted, S2N_ERR_CERT_REJECTED);
959 : 10 : return S2N_RESULT_OK;
960 : 19 : }
961 : :
962 : : S2N_RESULT s2n_x509_validator_validate_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn,
963 : : uint8_t *cert_chain_in, uint32_t cert_chain_len, s2n_pkey_type *pkey_type, struct s2n_pkey *public_key_out)
964 : 5004 : {
965 [ # # ][ - + ]: 5004 : RESULT_ENSURE_REF(validator);
966 : :
967 [ + + ]: 5004 : if (validator->cert_validation_cb_invoked) {
968 [ + + ]: 27 : RESULT_GUARD(s2n_x509_validator_handle_cert_validation_callback_result(validator));
969 : 4977 : } else {
970 [ + + ]: 4977 : RESULT_GUARD(s2n_x509_validator_validate_cert_chain_pre_cb(validator, conn, cert_chain_in, cert_chain_len));
971 : :
972 [ + + ]: 4880 : if (conn->config->cert_validation_cb) {
973 [ + + ][ + - ]: 29 : RESULT_ENSURE(conn->config->cert_validation_cb(conn, &(validator->cert_validation_info), conn->config->cert_validation_ctx) == S2N_SUCCESS,
974 : 19 : S2N_ERR_CANCELLED);
975 : 19 : validator->cert_validation_cb_invoked = true;
976 [ + + ]: 19 : RESULT_GUARD(s2n_x509_validator_handle_cert_validation_callback_result(validator));
977 : 19 : }
978 : 4880 : }
979 : :
980 : : /* retrieve information from leaf cert */
981 [ # # ][ - + ]: 4861 : RESULT_ENSURE_GT(sk_X509_num(validator->cert_chain_from_wire), 0);
982 : 4861 : X509 *leaf_cert = sk_X509_value(validator->cert_chain_from_wire, 0);
983 [ # # ][ - + ]: 4861 : RESULT_ENSURE_REF(leaf_cert);
984 : 4861 : DEFER_CLEANUP(struct s2n_pkey public_key = { 0 }, s2n_pkey_free);
985 [ - + ]: 4861 : RESULT_GUARD(s2n_pkey_from_x509(leaf_cert, &public_key, pkey_type));
986 : :
987 : 4861 : *public_key_out = public_key;
988 : :
989 : : /* Reset the old struct, so we don't clean up public_key_out */
990 : 4861 : ZERO_TO_DISABLE_DEFER_CLEANUP(public_key);
991 : :
992 : 4861 : return S2N_RESULT_OK;
993 : 4861 : }
994 : :
995 : : S2N_RESULT s2n_x509_validator_validate_cert_stapled_ocsp_response(struct s2n_x509_validator *validator,
996 : : struct s2n_connection *conn, const uint8_t *ocsp_response_raw, uint32_t ocsp_response_length)
997 : 36 : {
998 [ + + ][ + + ]: 36 : if (validator->skip_cert_validation || !validator->check_stapled_ocsp) {
999 : 8 : validator->state = OCSP_VALIDATED;
1000 : 8 : return S2N_RESULT_OK;
1001 : 8 : }
1002 : :
1003 [ - + ][ # # ]: 28 : RESULT_ENSURE(validator->state == VALIDATED, S2N_ERR_INVALID_CERT_STATE);
1004 : :
1005 : : #if !S2N_OCSP_STAPLING_SUPPORTED
1006 : : /* Default to safety */
1007 : : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
1008 : : #else
1009 : :
1010 [ - + ][ # # ]: 28 : RESULT_ENSURE_REF(ocsp_response_raw);
1011 : :
1012 : 28 : DEFER_CLEANUP(OCSP_RESPONSE *ocsp_response = d2i_OCSP_RESPONSE(NULL, &ocsp_response_raw, ocsp_response_length),
1013 : 28 : OCSP_RESPONSE_free_pointer);
1014 [ + - ][ + + ]: 28 : RESULT_ENSURE(ocsp_response != NULL, S2N_ERR_INVALID_OCSP_RESPONSE);
1015 : :
1016 : 27 : int ocsp_status = OCSP_response_status(ocsp_response);
1017 [ # # ][ - + ]: 27 : RESULT_ENSURE(ocsp_status == OCSP_RESPONSE_STATUS_SUCCESSFUL, S2N_ERR_CERT_UNTRUSTED);
1018 : :
1019 : 27 : DEFER_CLEANUP(OCSP_BASICRESP *basic_response = OCSP_response_get1_basic(ocsp_response), OCSP_BASICRESP_free_pointer);
1020 [ - + ][ # # ]: 27 : RESULT_ENSURE(basic_response != NULL, S2N_ERR_INVALID_OCSP_RESPONSE);
1021 : :
1022 : 27 : DEFER_CLEANUP(struct s2n_validated_cert_chain validated_cert_chain = { 0 }, s2n_x509_validator_validated_cert_chain_free);
1023 [ - + ]: 27 : RESULT_GUARD(s2n_x509_validator_get_validated_cert_chain(validator, &validated_cert_chain));
1024 : 27 : STACK_OF(X509) *cert_chain = validated_cert_chain.stack;
1025 [ - + ][ # # ]: 27 : RESULT_ENSURE_REF(cert_chain);
1026 : :
1027 : 27 : const int certs_in_chain = sk_X509_num(cert_chain);
1028 [ - + ][ # # ]: 27 : RESULT_ENSURE(certs_in_chain > 0, S2N_ERR_NO_CERT_FOUND);
1029 : :
1030 : : /* leaf is the top: not the bottom. */
1031 : 27 : X509 *subject = sk_X509_value(cert_chain, 0);
1032 : 27 : X509 *issuer = NULL;
1033 : : /* find the issuer in the chain. If it's not there. Fail everything. */
1034 [ + + ]: 54 : for (int i = 0; i < certs_in_chain; ++i) {
1035 : 53 : X509 *issuer_candidate = sk_X509_value(cert_chain, i);
1036 : 53 : const int issuer_value = X509_check_issued(issuer_candidate, subject);
1037 : :
1038 [ + + ]: 53 : if (issuer_value == X509_V_OK) {
1039 : 26 : issuer = issuer_candidate;
1040 : 26 : break;
1041 : 26 : }
1042 : 53 : }
1043 [ + + ][ + - ]: 27 : RESULT_ENSURE(issuer != NULL, S2N_ERR_CERT_UNTRUSTED);
1044 : :
1045 : : /* Important: this checks that the stapled ocsp response CAN be verified, not that it has been verified. */
1046 : 26 : const int ocsp_verify_res = OCSP_basic_verify(basic_response, cert_chain, validator->trust_store->trust_store, 0);
1047 [ + - ][ + + ]: 26 : RESULT_GUARD_OSSL(ocsp_verify_res, S2N_ERR_CERT_UNTRUSTED);
1048 : :
1049 : : /* do the crypto checks on the response.*/
1050 : 24 : int status = 0;
1051 : 24 : int reason = 0;
1052 : :
1053 : : /* SHA-1 is the only supported hash algorithm for the CertID due to its established use in
1054 : : * OCSP responders.
1055 : : */
1056 : 24 : OCSP_CERTID *cert_id = OCSP_cert_to_id(EVP_sha1(), subject, issuer);
1057 [ # # ][ - + ]: 24 : RESULT_ENSURE_REF(cert_id);
1058 : :
1059 : : /**
1060 : : *= https://www.rfc-editor.org/rfc/rfc6960#section-2.4
1061 : : *#
1062 : : *# thisUpdate The most recent time at which the status being
1063 : : *# indicated is known by the responder to have been
1064 : : *# correct.
1065 : : *#
1066 : : *# nextUpdate The time at or before which newer information will be
1067 : : *# available about the status of the certificate.
1068 : : **/
1069 : 24 : ASN1_GENERALIZEDTIME *revtime = NULL, *thisupd = NULL, *nextupd = NULL;
1070 : : /* Actual verification of the response */
1071 : 24 : const int ocsp_resp_find_status_res = OCSP_resp_find_status(basic_response, cert_id, &status, &reason, &revtime, &thisupd, &nextupd);
1072 : 24 : OCSP_CERTID_free(cert_id);
1073 [ + + ][ + - ]: 24 : RESULT_GUARD_OSSL(ocsp_resp_find_status_res, S2N_ERR_CERT_UNTRUSTED);
1074 : :
1075 : 23 : uint64_t current_sys_time_nanoseconds = 0;
1076 [ - + ]: 23 : RESULT_GUARD(s2n_config_wall_clock(conn->config, ¤t_sys_time_nanoseconds));
1077 : 23 : if (sizeof(time_t) == 4) {
1078 : : /* cast value to uint64_t to prevent overflow errors */
1079 [ # # ][ # # ]: 0 : RESULT_ENSURE_LTE(current_sys_time_nanoseconds, (uint64_t) MAX_32_TIMESTAMP_NANOS);
1080 : 0 : }
1081 : : /* convert the current_sys_time (which is in nanoseconds) to seconds */
1082 : 23 : time_t current_sys_time_seconds = (time_t) (current_sys_time_nanoseconds / ONE_SEC_IN_NANOS);
1083 : :
1084 : 23 : DEFER_CLEANUP(ASN1_GENERALIZEDTIME *current_sys_time = ASN1_GENERALIZEDTIME_set(NULL, current_sys_time_seconds), s2n_openssl_asn1_time_free_pointer);
1085 [ - + ][ # # ]: 23 : RESULT_ENSURE_REF(current_sys_time);
1086 : :
1087 : : /**
1088 : : * It is fine to use ASN1_TIME functions with ASN1_GENERALIZEDTIME structures
1089 : : * From openssl documentation:
1090 : : * It is recommended that functions starting with ASN1_TIME be used instead
1091 : : * of those starting with ASN1_UTCTIME or ASN1_GENERALIZEDTIME. The
1092 : : * functions starting with ASN1_UTCTIME and ASN1_GENERALIZEDTIME act only on
1093 : : * that specific time format. The functions starting with ASN1_TIME will
1094 : : * operate on either format.
1095 : : * https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_to_generalizedtime.html
1096 : : *
1097 : : * ASN1_TIME_compare has a much nicer API, but is not available in Openssl
1098 : : * 1.0.1, so we use ASN1_TIME_diff.
1099 : : */
1100 : 23 : int pday = 0;
1101 : 23 : int psec = 0;
1102 [ # # ][ - + ]: 23 : RESULT_GUARD_OSSL(ASN1_TIME_diff(&pday, &psec, thisupd, current_sys_time), S2N_ERR_CERT_UNTRUSTED);
1103 : : /* ensure that current_time is after or the same as "this update" */
1104 [ + - ][ + + ]: 23 : RESULT_ENSURE(pday >= 0 && psec >= 0, S2N_ERR_CERT_INVALID);
[ + + ]
1105 : :
1106 : : /* ensure that current_time is before or the same as "next update" */
1107 [ + + ]: 20 : if (nextupd) {
1108 [ - + ][ # # ]: 19 : RESULT_GUARD_OSSL(ASN1_TIME_diff(&pday, &psec, current_sys_time, nextupd), S2N_ERR_CERT_UNTRUSTED);
1109 [ + - ][ + + ]: 19 : RESULT_ENSURE(pday >= 0 && psec >= 0, S2N_ERR_CERT_EXPIRED);
[ + + ]
1110 : 19 : } else {
1111 : : /**
1112 : : * if nextupd isn't present, assume that nextupd is
1113 : : * DEFAULT_OCSP_NEXT_UPDATE_PERIOD after thisupd. This means that if the
1114 : : * current time is more than DEFAULT_OCSP_NEXT_UPDATE_PERIOD
1115 : : * seconds ahead of thisupd, we consider it invalid. We already compared
1116 : : * current_sys_time to thisupd, so reuse those values
1117 : : */
1118 : 1 : uint64_t seconds_after_thisupd = pday * (3600 * 24) + psec;
1119 [ # # ][ - + ]: 1 : RESULT_ENSURE(seconds_after_thisupd < DEFAULT_OCSP_NEXT_UPDATE_PERIOD, S2N_ERR_CERT_EXPIRED);
1120 : 1 : }
1121 : :
1122 : 16 : switch (status) {
1123 [ + + ]: 15 : case V_OCSP_CERTSTATUS_GOOD:
1124 : 15 : validator->state = OCSP_VALIDATED;
1125 : 15 : return S2N_RESULT_OK;
1126 [ + + ]: 1 : case V_OCSP_CERTSTATUS_REVOKED:
1127 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_CERT_REVOKED);
1128 [ - + ]: 0 : default:
1129 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
1130 : 16 : }
1131 : 16 : #endif /* S2N_OCSP_STAPLING_SUPPORTED */
1132 : 16 : }
1133 : :
1134 : : bool s2n_x509_validator_is_cert_chain_validated(const struct s2n_x509_validator *validator)
1135 : 739 : {
1136 [ + - ][ + + ]: 739 : return validator && (validator->state == VALIDATED || validator->state == OCSP_VALIDATED);
[ + + ]
1137 : 739 : }
1138 : :
1139 : : int s2n_cert_validation_accept(struct s2n_cert_validation_info *info)
1140 : 38 : {
1141 [ + - ][ + + ]: 38 : POSIX_ENSURE_REF(info);
1142 [ + - ][ + + ]: 37 : POSIX_ENSURE(!info->finished, S2N_ERR_INVALID_STATE);
1143 : :
1144 : 17 : info->finished = true;
1145 : 17 : info->accepted = true;
1146 : :
1147 : 17 : return S2N_SUCCESS;
1148 : 37 : }
1149 : :
1150 : : int s2n_cert_validation_reject(struct s2n_cert_validation_info *info)
1151 : 37 : {
1152 [ + + ][ + - ]: 37 : POSIX_ENSURE_REF(info);
1153 [ + + ][ + - ]: 36 : POSIX_ENSURE(!info->finished, S2N_ERR_INVALID_STATE);
1154 : :
1155 : 16 : info->finished = true;
1156 : 16 : info->accepted = false;
1157 : :
1158 : 16 : return S2N_SUCCESS;
1159 : 36 : }
|