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