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 "s2n_crl.h"
17 : :
18 : : #include "crypto/s2n_openssl_x509.h"
19 : : #include "tls/s2n_connection.h"
20 : :
21 : : struct s2n_crl *s2n_crl_new(void)
22 : 11 : {
23 : 11 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
24 [ - + ]: 11 : PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_crl)));
25 [ - + ]: 11 : PTR_GUARD_POSIX(s2n_blob_zero(&mem));
26 : :
27 : 11 : struct s2n_crl *crl = (struct s2n_crl *) (void *) mem.data;
28 : :
29 : 11 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
30 : 11 : return crl;
31 : 11 : }
32 : :
33 : : int s2n_crl_load_pem(struct s2n_crl *crl, uint8_t *pem, size_t len)
34 : 10 : {
35 [ - + ][ # # ]: 10 : POSIX_ENSURE_REF(crl);
36 [ - + ][ # # ]: 10 : POSIX_ENSURE(crl->crl == NULL, S2N_ERR_INVALID_ARGUMENT);
37 : :
38 : 10 : struct s2n_blob pem_blob = { 0 };
39 [ - + ]: 10 : POSIX_GUARD(s2n_blob_init(&pem_blob, pem, len));
40 : :
41 : 10 : struct s2n_stuffer pem_stuffer = { 0 };
42 [ - + ]: 10 : POSIX_GUARD(s2n_stuffer_init(&pem_stuffer, &pem_blob));
43 [ - + ]: 10 : POSIX_GUARD(s2n_stuffer_skip_write(&pem_stuffer, pem_blob.size));
44 : :
45 : 10 : DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = { 0 }, s2n_stuffer_free);
46 [ - + ]: 10 : POSIX_GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, len));
47 [ - + ]: 10 : POSIX_GUARD(s2n_stuffer_crl_from_pem(&pem_stuffer, &der_out_stuffer));
48 : :
49 : 10 : uint32_t data_size = s2n_stuffer_data_available(&der_out_stuffer);
50 : 10 : const uint8_t *data = s2n_stuffer_raw_read(&der_out_stuffer, data_size);
51 [ - + ][ # # ]: 10 : POSIX_ENSURE_REF(data);
52 : 10 : crl->crl = d2i_X509_CRL(NULL, &data, data_size);
53 [ + + ][ + - ]: 10 : POSIX_ENSURE(crl->crl != NULL, S2N_ERR_INVALID_PEM);
54 : :
55 : 9 : return S2N_SUCCESS;
56 : 10 : }
57 : :
58 : : int s2n_crl_free(struct s2n_crl **crl)
59 : 21 : {
60 [ - + ]: 21 : if (crl == NULL) {
61 : 0 : return S2N_SUCCESS;
62 : 0 : }
63 [ + + ]: 21 : if (*crl == NULL) {
64 : 10 : return S2N_SUCCESS;
65 : 10 : }
66 : :
67 [ + + ]: 11 : if ((*crl)->crl != NULL) {
68 : 9 : X509_CRL_free((*crl)->crl);
69 : 9 : (*crl)->crl = NULL;
70 : 9 : }
71 : :
72 [ - + ]: 11 : POSIX_GUARD(s2n_free_object((uint8_t **) crl, sizeof(struct s2n_crl)));
73 : :
74 : 11 : *crl = NULL;
75 : :
76 : 11 : return S2N_SUCCESS;
77 : 11 : }
78 : :
79 : : int s2n_crl_get_issuer_hash(struct s2n_crl *crl, uint64_t *hash)
80 : 3 : {
81 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(crl);
82 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(crl->crl);
83 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(hash);
84 : :
85 : 3 : S2N_X509_CONST X509_NAME *crl_name = X509_CRL_get_issuer(crl->crl);
86 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(crl_name);
87 : :
88 : : /* X509_NAME_hash takes a non-const X509_NAME* even on libcryptos (AWS-LC)
89 : : * whose X509_CRL_get_issuer returns const; it only reads the name. */
90 : 3 : unsigned long temp_hash = X509_NAME_hash((X509_NAME *) (uintptr_t) crl_name);
91 [ - + ][ # # ]: 3 : POSIX_ENSURE(temp_hash != 0, S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
92 : :
93 : 3 : *hash = temp_hash;
94 : :
95 : 3 : return S2N_SUCCESS;
96 : 3 : }
97 : :
98 : : int s2n_crl_validate_active(struct s2n_crl *crl)
99 : 3 : {
100 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(crl);
101 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(crl->crl);
102 : :
103 : 3 : ASN1_TIME *this_update = X509_CRL_get_lastUpdate(crl->crl);
104 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(this_update);
105 : :
106 : 3 : int ret = X509_cmp_time(this_update, NULL);
107 [ - + ][ # # ]: 3 : POSIX_ENSURE(ret != 0, S2N_ERR_CRL_INVALID_THIS_UPDATE);
108 [ + + ][ + - ]: 3 : POSIX_ENSURE(ret < 0, S2N_ERR_CRL_NOT_YET_VALID);
109 : :
110 : 2 : return S2N_SUCCESS;
111 : 3 : }
112 : :
113 : : int s2n_crl_validate_not_expired(struct s2n_crl *crl)
114 : 3 : {
115 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(crl);
116 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(crl->crl);
117 : :
118 : 3 : ASN1_TIME *next_update = X509_CRL_get_nextUpdate(crl->crl);
119 [ - + ]: 3 : if (next_update == NULL) {
120 : : /* If the CRL has no nextUpdate field, assume it will never expire */
121 : 0 : return S2N_SUCCESS;
122 : 0 : }
123 : :
124 : 3 : int ret = X509_cmp_time(next_update, NULL);
125 [ - + ][ # # ]: 3 : POSIX_ENSURE(ret != 0, S2N_ERR_CRL_INVALID_NEXT_UPDATE);
126 [ + + ][ + - ]: 3 : POSIX_ENSURE(ret > 0, S2N_ERR_CRL_EXPIRED);
127 : :
128 : 2 : return S2N_SUCCESS;
129 : 3 : }
130 : :
131 : : S2N_RESULT s2n_crl_get_crls_from_lookup_list(struct s2n_x509_validator *validator, STACK_OF(X509_CRL) *crl_stack)
132 : 16 : {
133 [ # # ][ - + ]: 16 : RESULT_ENSURE_REF(validator);
134 [ # # ][ - + ]: 16 : RESULT_ENSURE_REF(validator->crl_lookup_list);
135 [ # # ][ - + ]: 16 : RESULT_ENSURE_REF(crl_stack);
136 : :
137 : 16 : uint32_t num_lookups = 0;
138 [ - + ]: 16 : RESULT_GUARD(s2n_array_num_elements(validator->crl_lookup_list, &num_lookups));
139 [ + + ]: 49 : for (uint32_t i = 0; i < num_lookups; i++) {
140 : 33 : struct s2n_crl_lookup *lookup = NULL;
141 [ - + ]: 33 : RESULT_GUARD(s2n_array_get(validator->crl_lookup_list, i, (void **) &lookup));
142 [ - + ][ # # ]: 33 : RESULT_ENSURE_REF(lookup);
143 : :
144 [ + + ]: 33 : if (lookup->crl == NULL) {
145 : : /* A CRL was intentionally not returned from the callback. Don't add anything to the stack*/
146 : 3 : continue;
147 : 3 : }
148 : :
149 [ - + ][ # # ]: 30 : RESULT_ENSURE_REF(lookup->crl->crl);
150 [ - + ]: 30 : if (!sk_X509_CRL_push(crl_stack, lookup->crl->crl)) {
151 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
152 : 0 : }
153 : 30 : }
154 : :
155 : 16 : return S2N_RESULT_OK;
156 : 16 : }
157 : :
158 : : static S2N_RESULT s2n_crl_get_lookup_callback_status(struct s2n_x509_validator *validator, crl_lookup_callback_status *status)
159 : 36 : {
160 [ # # ][ - + ]: 36 : RESULT_ENSURE_REF(validator);
161 [ - + ][ # # ]: 36 : RESULT_ENSURE_REF(validator->crl_lookup_list);
162 : :
163 : 36 : uint32_t num_lookups = 0;
164 [ - + ]: 36 : RESULT_GUARD(s2n_array_num_elements(validator->crl_lookup_list, &num_lookups));
165 [ + + ]: 79 : for (uint32_t i = 0; i < num_lookups; i++) {
166 : 63 : struct s2n_crl_lookup *lookup = NULL;
167 [ - + ]: 63 : RESULT_GUARD(s2n_array_get(validator->crl_lookup_list, i, (void **) &lookup));
168 [ # # ][ - + ]: 63 : RESULT_ENSURE_REF(lookup);
169 : :
170 [ + + ]: 63 : if (lookup->status == AWAITING_RESPONSE) {
171 : 20 : *status = AWAITING_RESPONSE;
172 : 20 : return S2N_RESULT_OK;
173 : 20 : }
174 : 63 : }
175 : :
176 : 16 : *status = FINISHED;
177 : 16 : return S2N_RESULT_OK;
178 : 36 : }
179 : :
180 : : S2N_RESULT s2n_crl_handle_lookup_callback_result(struct s2n_x509_validator *validator)
181 : 36 : {
182 [ # # ][ - + ]: 36 : RESULT_ENSURE_REF(validator);
183 : :
184 : 36 : crl_lookup_callback_status status = 0;
185 [ - + ]: 36 : RESULT_GUARD(s2n_crl_get_lookup_callback_status(validator, &status));
186 : :
187 : 36 : switch (status) {
188 [ + + ]: 16 : case FINISHED:
189 : 16 : validator->state = READY_TO_VERIFY;
190 : 16 : return S2N_RESULT_OK;
191 [ + + ]: 20 : case AWAITING_RESPONSE:
192 : 20 : validator->state = AWAITING_CRL_CALLBACK;
193 [ + - ]: 20 : RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED);
194 [ - + ]: 0 : default:
195 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_INVALID_CERT_STATE);
196 : 36 : }
197 : 36 : }
198 : :
199 : : S2N_RESULT s2n_crl_invoke_lookup_callbacks(struct s2n_connection *conn, struct s2n_x509_validator *validator)
200 : 17 : {
201 [ - + ][ # # ]: 17 : RESULT_ENSURE_REF(validator);
202 [ - + ][ # # ]: 17 : RESULT_ENSURE_REF(validator->cert_chain_from_wire);
203 : :
204 : 17 : int cert_count = sk_X509_num(validator->cert_chain_from_wire);
205 : 17 : DEFER_CLEANUP(struct s2n_array *crl_lookup_list = s2n_array_new_with_capacity(sizeof(struct s2n_crl_lookup), cert_count),
206 : 17 : s2n_array_free_p);
207 [ - + ][ # # ]: 17 : RESULT_ENSURE_REF(crl_lookup_list);
208 : :
209 [ + + ]: 52 : for (int i = 0; i < cert_count; ++i) {
210 : 35 : struct s2n_crl_lookup *lookup = NULL;
211 [ - + ]: 35 : RESULT_GUARD(s2n_array_pushback(crl_lookup_list, (void **) &lookup));
212 : :
213 : 35 : X509 *cert = sk_X509_value(validator->cert_chain_from_wire, i);
214 [ - + ][ # # ]: 35 : RESULT_ENSURE_REF(cert);
215 : 35 : lookup->cert = cert;
216 : 35 : lookup->cert_idx = i;
217 : 35 : }
218 : :
219 : 17 : validator->crl_lookup_list = crl_lookup_list;
220 : 17 : ZERO_TO_DISABLE_DEFER_CLEANUP(crl_lookup_list);
221 : :
222 : : /* Invoke the crl lookup callbacks after the crl_lookup_list is stored on the validator. This ensures that if a
223 : : * callback fails, the memory for all other callbacks that may still be running remains allocated */
224 : 17 : uint32_t num_lookups = 0;
225 [ - + ]: 17 : RESULT_GUARD(s2n_array_num_elements(validator->crl_lookup_list, &num_lookups));
226 [ + + ]: 50 : for (uint32_t i = 0; i < num_lookups; i++) {
227 : 34 : struct s2n_crl_lookup *lookup = NULL;
228 [ - + ]: 34 : RESULT_GUARD(s2n_array_get(validator->crl_lookup_list, i, (void **) &lookup));
229 [ - + ][ # # ]: 34 : RESULT_ENSURE_REF(lookup);
230 : :
231 : 34 : int result = conn->config->crl_lookup_cb(lookup, conn->config->crl_lookup_ctx);
232 [ + - ][ + + ]: 34 : RESULT_ENSURE(result == S2N_SUCCESS, S2N_ERR_CANCELLED);
233 : 34 : }
234 : :
235 : 16 : return S2N_RESULT_OK;
236 : 17 : }
237 : :
238 : : int s2n_crl_ossl_verify_callback(int default_ossl_ret, X509_STORE_CTX *ctx)
239 : 36 : {
240 : 36 : int err = X509_STORE_CTX_get_error(ctx);
241 : 36 : switch (err) {
242 [ + + ]: 5 : case X509_V_ERR_CRL_NOT_YET_VALID:
243 [ + + ]: 10 : case X509_V_ERR_CRL_HAS_EXPIRED:
244 [ - + ]: 10 : case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
245 [ - + ]: 10 : case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
246 : 10 : return 1;
247 [ + + ]: 26 : default:
248 : 26 : return default_ossl_ret;
249 : 36 : }
250 : 36 : }
251 : :
252 : : int s2n_crl_lookup_get_cert_issuer_hash(struct s2n_crl_lookup *lookup, uint64_t *hash)
253 : 3 : {
254 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(lookup);
255 [ - + ][ # # ]: 3 : POSIX_ENSURE_REF(lookup->cert);
256 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(hash);
257 : :
258 : 3 : unsigned long temp_hash = X509_issuer_name_hash(lookup->cert);
259 [ - + ][ # # ]: 3 : POSIX_ENSURE(temp_hash != 0, S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
260 : :
261 : 3 : *hash = temp_hash;
262 : :
263 : 3 : return S2N_SUCCESS;
264 : 3 : }
265 : :
266 : : int s2n_crl_lookup_set(struct s2n_crl_lookup *lookup, struct s2n_crl *crl)
267 : 31 : {
268 [ # # ][ - + ]: 31 : POSIX_ENSURE_REF(lookup);
269 [ - + ][ # # ]: 31 : POSIX_ENSURE_REF(crl);
270 : 31 : lookup->crl = crl;
271 : 31 : lookup->status = FINISHED;
272 : 31 : return S2N_SUCCESS;
273 : 31 : }
274 : :
275 : : int s2n_crl_lookup_ignore(struct s2n_crl_lookup *lookup)
276 : 4 : {
277 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(lookup);
278 : 4 : lookup->crl = NULL;
279 : 4 : lookup->status = FINISHED;
280 : 4 : return S2N_SUCCESS;
281 : 4 : }
|