Use certificate CRLIssuer information to look up cacched CRLs or CDPs
[strongswan.git] / src / libstrongswan / plugins / revocation / revocation_validator.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2009 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "revocation_validator.h"
19
20 #include <debug.h>
21 #include <credentials/certificates/x509.h>
22 #include <credentials/certificates/crl.h>
23 #include <credentials/certificates/ocsp_request.h>
24 #include <credentials/certificates/ocsp_response.h>
25 #include <credentials/sets/ocsp_response_wrapper.h>
26 #include <selectors/traffic_selector.h>
27
28 typedef struct private_revocation_validator_t private_revocation_validator_t;
29
30 /**
31 * Private data of an revocation_validator_t object.
32 */
33 struct private_revocation_validator_t {
34
35 /**
36 * Public revocation_validator_t interface.
37 */
38 revocation_validator_t public;
39 };
40
41 /**
42 * Do an OCSP request
43 */
44 static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
45 certificate_t *issuer)
46 {
47 certificate_t *request, *response;
48 chunk_t send, receive;
49
50 /* TODO: requestor name, signature */
51 request = lib->creds->create(lib->creds,
52 CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
53 BUILD_CA_CERT, issuer,
54 BUILD_CERT, subject, BUILD_END);
55 if (!request)
56 {
57 DBG1(DBG_CFG, "generating ocsp request failed");
58 return NULL;
59 }
60
61 if (!request->get_encoding(request, CERT_ASN1_DER, &send))
62 {
63 DBG1(DBG_CFG, "encoding ocsp request failed");
64 request->destroy(request);
65 return NULL;
66 }
67 request->destroy(request);
68
69 DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
70 if (lib->fetcher->fetch(lib->fetcher, url, &receive,
71 FETCH_REQUEST_DATA, send,
72 FETCH_REQUEST_TYPE, "application/ocsp-request",
73 FETCH_END) != SUCCESS)
74 {
75 DBG1(DBG_CFG, "ocsp request to %s failed", url);
76 chunk_free(&send);
77 return NULL;
78 }
79 chunk_free(&send);
80
81 response = lib->creds->create(lib->creds,
82 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
83 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
84 chunk_free(&receive);
85 if (!response)
86 {
87 DBG1(DBG_CFG, "parsing ocsp response failed");
88 return NULL;
89 }
90 return response;
91 }
92
93 /**
94 * check the signature of an OCSP response
95 */
96 static bool verify_ocsp(ocsp_response_t *response)
97 {
98 certificate_t *issuer, *subject;
99 identification_t *responder;
100 ocsp_response_wrapper_t *wrapper;
101 enumerator_t *enumerator;
102 bool verified = FALSE;
103
104 wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
105 lib->credmgr->add_local_set(lib->credmgr, &wrapper->set);
106
107 subject = &response->certificate;
108 responder = subject->get_issuer(subject);
109 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
110 KEY_ANY, responder, FALSE);
111 while (enumerator->enumerate(enumerator, &issuer, NULL))
112 {
113 if (lib->credmgr->issued_by(lib->credmgr, subject, issuer))
114 {
115 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
116 issuer->get_subject(issuer));
117 verified = TRUE;
118 break;
119 }
120 }
121 enumerator->destroy(enumerator);
122
123 lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
124 wrapper->destroy(wrapper);
125 return verified;
126 }
127
128 /**
129 * Get the better of two OCSP responses, and check for usable OCSP info
130 */
131 static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
132 x509_t *subject, x509_t *issuer, cert_validation_t *valid, bool cache)
133 {
134 ocsp_response_t *response;
135 time_t revocation, this_update, next_update, valid_until;
136 crl_reason_t reason;
137 bool revoked = FALSE;
138
139 response = (ocsp_response_t*)cand;
140
141 /* check ocsp signature */
142 if (!verify_ocsp(response))
143 {
144 DBG1(DBG_CFG, "ocsp response verification failed");
145 cand->destroy(cand);
146 return best;
147 }
148 /* check if response contains our certificate */
149 switch (response->get_status(response, subject, issuer, &revocation, &reason,
150 &this_update, &next_update))
151 {
152 case VALIDATION_REVOKED:
153 /* subject has been revoked by a valid OCSP response */
154 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
155 &revocation, TRUE, crl_reason_names, reason);
156 revoked = TRUE;
157 break;
158 case VALIDATION_GOOD:
159 /* results in either good or stale */
160 break;
161 default:
162 case VALIDATION_FAILED:
163 /* candidate unusable, does not contain our cert */
164 DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
165 cand->destroy(cand);
166 return best;
167 }
168
169 /* select the better of the two responses */
170 if (best == NULL || certificate_is_newer(cand, best))
171 {
172 DESTROY_IF(best);
173 best = cand;
174 if (best->get_validity(best, NULL, NULL, &valid_until))
175 {
176 DBG1(DBG_CFG, " ocsp response is valid: until %T",
177 &valid_until, FALSE);
178 *valid = VALIDATION_GOOD;
179 if (cache)
180 { /* cache non-stale only, stale certs get refetched */
181 lib->credmgr->cache_cert(lib->credmgr, best);
182 }
183 }
184 else
185 {
186 DBG1(DBG_CFG, " ocsp response is stale: since %T",
187 &valid_until, FALSE);
188 *valid = VALIDATION_STALE;
189 }
190 }
191 else
192 {
193 *valid = VALIDATION_STALE;
194 cand->destroy(cand);
195 }
196 if (revoked)
197 { /* revoked always counts, even if stale */
198 *valid = VALIDATION_REVOKED;
199 }
200 return best;
201 }
202
203 /**
204 * validate a x509 certificate using OCSP
205 */
206 static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
207 auth_cfg_t *auth)
208 {
209 enumerator_t *enumerator;
210 cert_validation_t valid = VALIDATION_SKIPPED;
211 certificate_t *best = NULL, *current;
212 identification_t *keyid = NULL;
213 public_key_t *public;
214 chunk_t chunk;
215 char *uri = NULL;
216
217 /** lookup cache for valid OCSP responses */
218 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
219 CERT_X509_OCSP_RESPONSE, KEY_ANY, NULL, FALSE);
220 while (enumerator->enumerate(enumerator, &current))
221 {
222 current->get_ref(current);
223 best = get_better_ocsp(current, best, subject, issuer, &valid, FALSE);
224 if (best && valid != VALIDATION_STALE)
225 {
226 DBG1(DBG_CFG, " using cached ocsp response");
227 break;
228 }
229 }
230 enumerator->destroy(enumerator);
231
232 /* derive the authorityKeyIdentifier from the issuer's public key */
233 current = &issuer->interface;
234 public = current->get_public_key(current);
235 if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
236 {
237 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
238 }
239 /** fetch from configured OCSP responder URLs */
240 if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
241 {
242 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
243 CERT_X509_OCSP_RESPONSE, keyid);
244 while (enumerator->enumerate(enumerator, &uri))
245 {
246 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
247 if (current)
248 {
249 best = get_better_ocsp(current, best, subject, issuer,
250 &valid, TRUE);
251 if (best && valid != VALIDATION_STALE)
252 {
253 break;
254 }
255 }
256 }
257 enumerator->destroy(enumerator);
258 }
259 DESTROY_IF(public);
260 DESTROY_IF(keyid);
261
262 /* fallback to URL fetching from subject certificate's URIs */
263 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
264 {
265 enumerator = subject->create_ocsp_uri_enumerator(subject);
266 while (enumerator->enumerate(enumerator, &uri))
267 {
268 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
269 if (current)
270 {
271 best = get_better_ocsp(current, best, subject, issuer,
272 &valid, TRUE);
273 if (best && valid != VALIDATION_STALE)
274 {
275 break;
276 }
277 }
278 }
279 enumerator->destroy(enumerator);
280 }
281 /* an uri was found, but no result. switch validation state to failed */
282 if (valid == VALIDATION_SKIPPED && uri)
283 {
284 valid = VALIDATION_FAILED;
285 }
286 if (auth)
287 {
288 auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
289 if (valid == VALIDATION_GOOD)
290 { /* successful OCSP check fulfills also CRL constraint */
291 auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
292 }
293 }
294 DESTROY_IF(best);
295 return valid;
296 }
297
298 /**
299 * fetch a CRL from an URL
300 */
301 static certificate_t* fetch_crl(char *url)
302 {
303 certificate_t *crl;
304 chunk_t chunk;
305
306 DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
307 if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
308 {
309 DBG1(DBG_CFG, "crl fetching failed");
310 return NULL;
311 }
312 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
313 BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
314 chunk_free(&chunk);
315 if (!crl)
316 {
317 DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
318 return NULL;
319 }
320 return crl;
321 }
322
323 /**
324 * check the signature of an CRL
325 */
326 static bool verify_crl(certificate_t *crl)
327 {
328 certificate_t *issuer;
329 enumerator_t *enumerator;
330 bool verified = FALSE;
331
332 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
333 KEY_ANY, crl->get_issuer(crl), FALSE);
334 while (enumerator->enumerate(enumerator, &issuer, NULL))
335 {
336 if (lib->credmgr->issued_by(lib->credmgr, crl, issuer))
337 {
338 DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
339 issuer->get_subject(issuer));
340 verified = TRUE;
341 break;
342 }
343 }
344 enumerator->destroy(enumerator);
345
346 return verified;
347 }
348
349 /**
350 * Get the better of two CRLs, and check for usable CRL info
351 */
352 static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
353 x509_t *subject, cert_validation_t *valid, bool cache)
354 {
355 enumerator_t *enumerator;
356 time_t revocation, valid_until;
357 crl_reason_t reason;
358 chunk_t serial;
359 crl_t *crl;
360
361 /* check CRL signature */
362 if (!verify_crl(cand))
363 {
364 DBG1(DBG_CFG, "crl response verification failed");
365 cand->destroy(cand);
366 return best;
367 }
368
369 crl = (crl_t*)cand;
370 enumerator = crl->create_enumerator(crl);
371 while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
372 {
373 if (chunk_equals(serial, subject->get_serial(subject)))
374 {
375 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
376 &revocation, TRUE, crl_reason_names, reason);
377 *valid = VALIDATION_REVOKED;
378 enumerator->destroy(enumerator);
379 DESTROY_IF(best);
380 return cand;
381 }
382 }
383 enumerator->destroy(enumerator);
384
385 /* select the better of the two CRLs */
386 if (best == NULL || crl_is_newer(crl, (crl_t*)best))
387 {
388 DESTROY_IF(best);
389 best = cand;
390 if (best->get_validity(best, NULL, NULL, &valid_until))
391 {
392 DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
393 *valid = VALIDATION_GOOD;
394 if (cache)
395 { /* we cache non-stale crls only, as a stale crls are refetched */
396 lib->credmgr->cache_cert(lib->credmgr, best);
397 }
398 }
399 else
400 {
401 DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
402 *valid = VALIDATION_STALE;
403 }
404 }
405 else
406 {
407 *valid = VALIDATION_STALE;
408 cand->destroy(cand);
409 }
410 return best;
411 }
412
413 /**
414 * Find or fetch a certificate for a given crlIssuer
415 */
416 static cert_validation_t find_crl(x509_t *subject, identification_t *issuer,
417 certificate_t **best, bool *uri_found)
418 {
419 cert_validation_t valid = VALIDATION_SKIPPED;
420 enumerator_t *enumerator;
421 certificate_t *current;
422 char *uri;
423
424 /* find a cached crl */
425 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
426 CERT_X509_CRL, KEY_ANY, issuer, FALSE);
427 while (enumerator->enumerate(enumerator, &current))
428 {
429 current->get_ref(current);
430 *best = get_better_crl(current, *best, subject, &valid, FALSE);
431 if (*best && valid != VALIDATION_STALE)
432 {
433 DBG1(DBG_CFG, " using cached crl");
434 break;
435 }
436 }
437 enumerator->destroy(enumerator);
438
439 /* fallback to fetching crls from credential sets cdps */
440 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
441 {
442 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
443 CERT_X509_CRL, issuer);
444 while (enumerator->enumerate(enumerator, &uri))
445 {
446 *uri_found = TRUE;
447 current = fetch_crl(uri);
448 if (!current->has_issuer(current, issuer))
449 {
450 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match CRL "
451 "issuer '%Y'", current->get_issuer(current), issuer);
452 current->destroy(current);
453 continue;
454 }
455 if (current)
456 {
457 *best = get_better_crl(current, *best, subject, &valid, TRUE);
458 if (*best && valid != VALIDATION_STALE)
459 {
460 break;
461 }
462 }
463 }
464 enumerator->destroy(enumerator);
465 }
466 return valid;
467 }
468
469 /**
470 * validate a x509 certificate using CRL
471 */
472 static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
473 auth_cfg_t *auth)
474 {
475 cert_validation_t valid = VALIDATION_SKIPPED;
476 identification_t *id;
477 certificate_t *best = NULL;
478 bool uri_found = FALSE;
479 certificate_t *current;
480 enumerator_t *enumerator;
481 chunk_t chunk;
482 char *uri;
483
484 /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
485 chunk = issuer->get_subjectKeyIdentifier(issuer);
486 if (chunk.len)
487 {
488 id = identification_create_from_encoding(ID_KEY_ID, chunk);
489 valid = find_crl(subject, id, &best, &uri_found);
490 id->destroy(id);
491 }
492
493 /* find a cached CRL or fetch via configured CDP via CRLIssuer */
494 enumerator = subject->create_crl_uri_enumerator(subject);
495 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
496 enumerator->enumerate(enumerator, &uri, &id))
497 {
498 if (id)
499 {
500 valid = find_crl(subject, id, &best, &uri_found);
501 }
502 }
503 enumerator->destroy(enumerator);
504
505 /* fallback to fetching CRLs from CDPs found in subjects certificate */
506 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
507 {
508 enumerator = subject->create_crl_uri_enumerator(subject);
509 while (enumerator->enumerate(enumerator, &uri, &id))
510 {
511 uri_found = TRUE;
512 current = fetch_crl(uri);
513 if (current)
514 {
515 if (id && !current->has_issuer(current, id))
516 {
517 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match "
518 "certificates CRL issuer '%Y'",
519 current->get_issuer(current), id);
520 current->destroy(current);
521 continue;
522 }
523 best = get_better_crl(current, best, subject, &valid, TRUE);
524 if (best && valid != VALIDATION_STALE)
525 {
526 break;
527 }
528 }
529 }
530 enumerator->destroy(enumerator);
531 }
532
533 /* an uri was found, but no result. switch validation state to failed */
534 if (valid == VALIDATION_SKIPPED && uri_found)
535 {
536 valid = VALIDATION_FAILED;
537 }
538 if (auth)
539 {
540 if (valid == VALIDATION_SKIPPED)
541 { /* if we skipped CRL validation, we use the result of OCSP for
542 * constraint checking */
543 auth->add(auth, AUTH_RULE_CRL_VALIDATION,
544 auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
545 }
546 else
547 {
548 auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
549 }
550 }
551 DESTROY_IF(best);
552 return valid;
553 }
554
555 METHOD(cert_validator_t, validate, bool,
556 private_revocation_validator_t *this, certificate_t *subject,
557 certificate_t *issuer, bool online, int pathlen, auth_cfg_t *auth)
558 {
559 if (subject->get_type(subject) == CERT_X509 &&
560 issuer->get_type(issuer) == CERT_X509 &&
561 online)
562 {
563 DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
564 subject->get_subject(subject));
565 switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth))
566 {
567 case VALIDATION_GOOD:
568 DBG1(DBG_CFG, "certificate status is good");
569 return TRUE;
570 case VALIDATION_REVOKED:
571 /* has already been logged */
572 return FALSE;
573 case VALIDATION_SKIPPED:
574 DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
575 break;
576 case VALIDATION_STALE:
577 DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
578 break;
579 case VALIDATION_FAILED:
580 DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
581 break;
582 }
583 switch (check_crl((x509_t*)subject, (x509_t*)issuer, auth))
584 {
585 case VALIDATION_GOOD:
586 DBG1(DBG_CFG, "certificate status is good");
587 return TRUE;
588 case VALIDATION_REVOKED:
589 /* has already been logged */
590 return FALSE;
591 case VALIDATION_FAILED:
592 case VALIDATION_SKIPPED:
593 DBG1(DBG_CFG, "certificate status is not available");
594 break;
595 case VALIDATION_STALE:
596 DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
597 break;
598 }
599 }
600 return TRUE;
601 }
602
603 METHOD(revocation_validator_t, destroy, void,
604 private_revocation_validator_t *this)
605 {
606 free(this);
607 }
608
609 /**
610 * See header
611 */
612 revocation_validator_t *revocation_validator_create()
613 {
614 private_revocation_validator_t *this;
615
616 INIT(this,
617 .public = {
618 .validator.validate = _validate,
619 .destroy = _destroy,
620 },
621 );
622
623 return &this->public;
624 }