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