Annotation of embedaddon/strongswan/src/libstrongswan/plugins/revocation/revocation_validator.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2015-2018 Tobias Brunner
3: * Copyright (C) 2010 Martin Willi
4: * Copyright (C) 2010 revosec AG
5: * Copyright (C) 2009 Andreas Steffen
6: * HSR Hochschule fuer Technik Rapperswil
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License as published by the
10: * Free Software Foundation; either version 2 of the License, or (at your
11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12: *
13: * This program is distributed in the hope that it will be useful, but
14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16: * for more details.
17: */
18:
19: #include <time.h>
20:
21: #include "revocation_validator.h"
22:
23: #include <utils/debug.h>
24: #include <credentials/certificates/x509.h>
25: #include <credentials/certificates/crl.h>
26: #include <credentials/certificates/ocsp_request.h>
27: #include <credentials/certificates/ocsp_response.h>
28: #include <credentials/sets/ocsp_response_wrapper.h>
29: #include <selectors/traffic_selector.h>
30: #include <threading/spinlock.h>
31:
32: typedef struct private_revocation_validator_t private_revocation_validator_t;
33:
34: /**
35: * Private data of an revocation_validator_t object.
36: */
37: struct private_revocation_validator_t {
38:
39: /**
40: * Public revocation_validator_t interface.
41: */
42: revocation_validator_t public;
43:
44: /**
45: * Enable OCSP validation
46: */
47: bool enable_ocsp;
48:
49: /**
50: * Enable CRL validation
51: */
52: bool enable_crl;
53:
54: /**
55: * Lock to access flags
56: */
57: spinlock_t *lock;
58: };
59:
60: /**
61: * Do an OCSP request
62: */
63: static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
64: certificate_t *issuer)
65: {
66: certificate_t *request, *response;
67: ocsp_request_t *ocsp_request;
68: ocsp_response_t *ocsp_response;
69: chunk_t send, receive = chunk_empty;
70:
71: /* TODO: requestor name, signature */
72: request = lib->creds->create(lib->creds,
73: CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
74: BUILD_CA_CERT, issuer,
75: BUILD_CERT, subject, BUILD_END);
76: if (!request)
77: {
78: DBG1(DBG_CFG, "generating ocsp request failed");
79: return NULL;
80: }
81:
82: if (!request->get_encoding(request, CERT_ASN1_DER, &send))
83: {
84: DBG1(DBG_CFG, "encoding ocsp request failed");
85: request->destroy(request);
86: return NULL;
87: }
88:
89: DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
90: if (lib->fetcher->fetch(lib->fetcher, url, &receive,
91: FETCH_REQUEST_DATA, send,
92: FETCH_REQUEST_TYPE, "application/ocsp-request",
93: FETCH_END) != SUCCESS)
94: {
95: DBG1(DBG_CFG, "ocsp request to %s failed", url);
96: request->destroy(request);
97: chunk_free(&receive);
98: chunk_free(&send);
99: return NULL;
100: }
101: chunk_free(&send);
102:
103: response = lib->creds->create(lib->creds,
104: CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
105: BUILD_BLOB_ASN1_DER, receive, BUILD_END);
106: chunk_free(&receive);
107: if (!response)
108: {
109: DBG1(DBG_CFG, "parsing ocsp response failed");
110: request->destroy(request);
111: return NULL;
112: }
113: ocsp_request = (ocsp_request_t*)request;
114: ocsp_response = (ocsp_response_t*)response;
115: if (!chunk_equals_const(ocsp_request->get_nonce(ocsp_request),
116: ocsp_response->get_nonce(ocsp_response)))
117: {
118: DBG1(DBG_CFG, "nonce in ocsp response doesn't match");
119: request->destroy(request);
120: return NULL;
121: }
122: request->destroy(request);
123: return response;
124: }
125:
126: /**
127: * check the signature of an OCSP response
128: */
129: static bool verify_ocsp(ocsp_response_t *response, certificate_t *ca)
130: {
131: certificate_t *issuer, *subject;
132: identification_t *responder;
133: ocsp_response_wrapper_t *wrapper;
134: enumerator_t *enumerator;
135: x509_t *x509;
136: bool verified = FALSE, found = FALSE;
137:
138: wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
139: lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
140:
141: subject = &response->certificate;
142: responder = subject->get_issuer(subject);
143:
144: /* check OCSP response using CA or directly delegated OCSP signer */
145: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509,
146: KEY_ANY, responder, FALSE);
147: while (enumerator->enumerate(enumerator, &issuer))
148: {
149: x509 = (x509_t*)issuer;
150: if (!issuer->get_validity(issuer, NULL, NULL, NULL))
151: { /* OCSP signer currently invalid */
152: continue;
153: }
154: if (!ca->equals(ca, issuer))
155: { /* delegated OCSP signer? */
156: if (!lib->credmgr->issued_by(lib->credmgr, issuer, ca, NULL))
157: { /* OCSP response not signed by CA, nor delegated OCSP signer */
158: continue;
159: }
160: if (!(x509->get_flags(x509) & X509_OCSP_SIGNER))
161: { /* delegated OCSP signer does not have OCSP signer flag */
162: continue;
163: }
164: }
165: found = TRUE;
166: if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
167: {
168: DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
169: issuer->get_subject(issuer));
170: verified = TRUE;
171: break;
172: }
173: DBG1(DBG_CFG, "ocsp response verification failed, "
174: "invalid signature");
175: }
176: enumerator->destroy(enumerator);
177:
178: if (!verified)
179: {
180: /* as fallback, use any locally installed OCSP signer certificate */
181: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
182: CERT_X509, KEY_ANY, responder, TRUE);
183: while (enumerator->enumerate(enumerator, &issuer))
184: {
185: x509 = (x509_t*)issuer;
186: /* while issued_by() accepts both OCSP signer or CA basic
187: * constraint flags to verify OCSP responses, unrelated but trusted
188: * OCSP signers must explicitly have the OCSP signer flag set. */
189: if ((x509->get_flags(x509) & X509_OCSP_SIGNER) &&
190: issuer->get_validity(issuer, NULL, NULL, NULL))
191: {
192: found = TRUE;
193: if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
194: {
195: DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
196: issuer->get_subject(issuer));
197: verified = TRUE;
198: break;
199: }
200: DBG1(DBG_CFG, "ocsp response verification failed, "
201: "invalid signature");
202: }
203: }
204: enumerator->destroy(enumerator);
205: }
206:
207: lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
208: wrapper->destroy(wrapper);
209:
210: if (!found)
211: {
212: DBG1(DBG_CFG, "ocsp response verification failed, "
213: "no signer certificate '%Y' found", responder);
214: }
215: return verified;
216: }
217:
218: /**
219: * Get the better of two OCSP responses, and check for usable OCSP info
220: */
221: static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
222: x509_t *subject, x509_t *issuer,
223: cert_validation_t *valid, bool cache)
224: {
225: ocsp_response_t *response;
226: time_t revocation, this_update, next_update, valid_until;
227: crl_reason_t reason;
228: bool revoked = FALSE;
229:
230: response = (ocsp_response_t*)cand;
231:
232: /* check ocsp signature */
233: if (!verify_ocsp(response, &issuer->interface))
234: {
235: cand->destroy(cand);
236: return best;
237: }
238: /* check if response contains our certificate */
239: switch (response->get_status(response, subject, issuer, &revocation, &reason,
240: &this_update, &next_update))
241: {
242: case VALIDATION_REVOKED:
243: /* subject has been revoked by a valid OCSP response */
244: DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
245: &revocation, TRUE, crl_reason_names, reason);
246: revoked = TRUE;
247: break;
248: case VALIDATION_GOOD:
249: /* results in either good or stale */
250: break;
251: default:
252: case VALIDATION_FAILED:
253: /* candidate unusable, does not contain our cert */
254: DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
255: cand->destroy(cand);
256: return best;
257: }
258:
259: /* select the better of the two responses */
260: if (best == NULL || certificate_is_newer(cand, best))
261: {
262: DESTROY_IF(best);
263: best = cand;
264: if (best->get_validity(best, NULL, NULL, &valid_until))
265: {
266: DBG1(DBG_CFG, " ocsp response is valid: until %T",
267: &valid_until, FALSE);
268: *valid = VALIDATION_GOOD;
269: if (cache)
270: { /* cache non-stale only, stale certs get refetched */
271: lib->credmgr->cache_cert(lib->credmgr, best);
272: }
273: }
274: else
275: {
276: DBG1(DBG_CFG, " ocsp response is stale: since %T",
277: &valid_until, FALSE);
278: *valid = VALIDATION_STALE;
279: }
280: }
281: else
282: {
283: *valid = VALIDATION_STALE;
284: cand->destroy(cand);
285: }
286: if (revoked)
287: { /* revoked always counts, even if stale */
288: *valid = VALIDATION_REVOKED;
289: }
290: return best;
291: }
292:
293: /**
294: * validate a x509 certificate using OCSP
295: */
296: static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
297: auth_cfg_t *auth)
298: {
299: enumerator_t *enumerator;
300: cert_validation_t valid = VALIDATION_SKIPPED;
301: certificate_t *best = NULL, *current;
302: identification_t *keyid = NULL;
303: public_key_t *public;
304: chunk_t chunk;
305: char *uri = NULL;
306:
307: /** lookup cache for valid OCSP responses */
308: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
309: CERT_X509_OCSP_RESPONSE, KEY_ANY, NULL, FALSE);
310: while (enumerator->enumerate(enumerator, ¤t))
311: {
312: current->get_ref(current);
313: best = get_better_ocsp(current, best, subject, issuer, &valid, FALSE);
314: if (best && valid != VALIDATION_STALE)
315: {
316: DBG1(DBG_CFG, " using cached ocsp response");
317: break;
318: }
319: }
320: enumerator->destroy(enumerator);
321:
322: /* derive the authorityKeyIdentifier from the issuer's public key */
323: current = &issuer->interface;
324: public = current->get_public_key(current);
325: if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
326: {
327: keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
328: }
329: /** fetch from configured OCSP responder URLs */
330: if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
331: {
332: enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
333: CERT_X509_OCSP_RESPONSE, keyid);
334: while (enumerator->enumerate(enumerator, &uri))
335: {
336: current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
337: if (current)
338: {
339: best = get_better_ocsp(current, best, subject, issuer,
340: &valid, TRUE);
341: if (best && valid != VALIDATION_STALE)
342: {
343: break;
344: }
345: }
346: }
347: enumerator->destroy(enumerator);
348: }
349: DESTROY_IF(public);
350: DESTROY_IF(keyid);
351:
352: /* fallback to URL fetching from subject certificate's URIs */
353: if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
354: {
355: enumerator = subject->create_ocsp_uri_enumerator(subject);
356: while (enumerator->enumerate(enumerator, &uri))
357: {
358: current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
359: if (current)
360: {
361: best = get_better_ocsp(current, best, subject, issuer,
362: &valid, TRUE);
363: if (best && valid != VALIDATION_STALE)
364: {
365: break;
366: }
367: }
368: }
369: enumerator->destroy(enumerator);
370: }
371: /* an uri was found, but no result. switch validation state to failed */
372: if (valid == VALIDATION_SKIPPED && uri)
373: {
374: valid = VALIDATION_FAILED;
375: }
376: auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
377: if (valid == VALIDATION_GOOD)
378: { /* successful OCSP check fulfills also CRL constraint */
379: auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
380: }
381: DESTROY_IF(best);
382: return valid;
383: }
384:
385: /**
386: * fetch a CRL from an URL
387: */
388: static certificate_t* fetch_crl(char *url)
389: {
390: certificate_t *crl;
391: chunk_t chunk = chunk_empty;
392:
393: DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
394: if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
395: {
396: DBG1(DBG_CFG, "crl fetching failed");
397: chunk_free(&chunk);
398: return NULL;
399: }
400: crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
401: BUILD_BLOB_PEM, chunk, BUILD_END);
402: chunk_free(&chunk);
403: if (!crl)
404: {
405: DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
406: return NULL;
407: }
408: return crl;
409: }
410:
411: /**
412: * check the signature of an CRL
413: */
414: static bool verify_crl(certificate_t *crl)
415: {
416: certificate_t *issuer;
417: enumerator_t *enumerator;
418: bool verified = FALSE;
419:
420: enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
421: KEY_ANY, crl->get_issuer(crl), FALSE);
422: while (enumerator->enumerate(enumerator, &issuer, NULL))
423: {
424: if (lib->credmgr->issued_by(lib->credmgr, crl, issuer, NULL))
425: {
426: DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
427: issuer->get_subject(issuer));
428: verified = TRUE;
429: break;
430: }
431: }
432: enumerator->destroy(enumerator);
433:
434: return verified;
435: }
436:
437: /**
438: * Report the given CRL's validity and cache it if valid and requested
439: */
440: static bool is_crl_valid(certificate_t *crl, time_t now, bool cache)
441: {
442: time_t valid_until;
443:
444: if (crl->get_validity(crl, &now, NULL, &valid_until))
445: {
446: DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
447: if (cache)
448: {
449: lib->credmgr->cache_cert(lib->credmgr, crl);
450: }
451: return TRUE;
452: }
453: DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
454: return FALSE;
455: }
456:
457: /**
458: * Check if the CRL should be used yet
459: */
460: static bool is_crl_not_valid_yet(certificate_t *crl, time_t now)
461: {
462: time_t this_update;
463:
464: if (!crl->get_validity(crl, &now, &this_update, NULL))
465: {
466: if (this_update > now)
467: {
468: DBG1(DBG_CFG, " crl is not valid: until %T", &this_update, FALSE);
469: return TRUE;
470: }
471: /* we accept stale CRLs */
472: }
473: return FALSE;
474: }
475:
476: /**
477: * Get the better of two CRLs, and check for usable CRL info
478: */
479: static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
480: x509_t *subject, cert_validation_t *valid,
481: bool cache, crl_t *base)
482: {
483: enumerator_t *enumerator;
484: time_t now, revocation;
485: crl_reason_t reason;
486: chunk_t subject_serial, serial;
487: crl_t *crl = (crl_t*)cand;
488:
489: if (base)
490: {
491: if (!crl->is_delta_crl(crl, &serial) ||
492: !chunk_equals(serial, base->get_serial(base)))
493: {
494: cand->destroy(cand);
495: return best;
496: }
497: }
498: else
499: {
500: if (crl->is_delta_crl(crl, NULL))
501: {
502: cand->destroy(cand);
503: return best;
504: }
505: }
506:
507: /* check CRL signature */
508: if (!verify_crl(cand))
509: {
510: DBG1(DBG_CFG, "crl response verification failed");
511: cand->destroy(cand);
512: return best;
513: }
514: now = time(NULL);
515: if (is_crl_not_valid_yet(cand, now))
516: {
517: cand->destroy(cand);
518: return best;
519: }
520:
521: subject_serial = chunk_skip_zero(subject->get_serial(subject));
522: enumerator = crl->create_enumerator(crl);
523: while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
524: {
525: if (chunk_equals(subject_serial, chunk_skip_zero(serial)))
526: {
527: if (reason != CRL_REASON_CERTIFICATE_HOLD)
528: {
529: *valid = VALIDATION_REVOKED;
530: }
531: else
532: {
533: /* if the cert is on hold, a newer CRL might not contain it */
534: *valid = VALIDATION_ON_HOLD;
535: }
536: is_crl_valid(cand, now, cache);
537: DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
538: &revocation, TRUE, crl_reason_names, reason);
539: enumerator->destroy(enumerator);
540: DESTROY_IF(best);
541: return cand;
542: }
543: }
544: enumerator->destroy(enumerator);
545:
546: /* select the better of the two CRLs */
547: if (best == NULL || crl_is_newer(crl, (crl_t*)best))
548: {
549: DESTROY_IF(best);
550: best = cand;
551: if (is_crl_valid(best, now, cache))
552: {
553: *valid = VALIDATION_GOOD;
554: }
555: else
556: {
557: *valid = VALIDATION_STALE;
558: }
559: }
560: else
561: {
562: *valid = VALIDATION_STALE;
563: cand->destroy(cand);
564: }
565: return best;
566: }
567:
568: /**
569: * Find or fetch a certificate for a given crlIssuer
570: */
571: static cert_validation_t find_crl(x509_t *subject, identification_t *issuer,
572: crl_t *base, certificate_t **best,
573: bool *uri_found)
574: {
575: cert_validation_t valid = VALIDATION_SKIPPED;
576: enumerator_t *enumerator;
577: certificate_t *current;
578: char *uri;
579:
580: /* find a cached (delta) crl */
581: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
582: CERT_X509_CRL, KEY_ANY, issuer, FALSE);
583: while (enumerator->enumerate(enumerator, ¤t))
584: {
585: current->get_ref(current);
586: *best = get_better_crl(current, *best, subject, &valid, FALSE, base);
587: if (*best && valid != VALIDATION_STALE)
588: {
589: DBG1(DBG_CFG, " using cached crl");
590: break;
591: }
592: }
593: enumerator->destroy(enumerator);
594:
595: /* fallback to fetching crls from credential sets cdps */
596: if (!base && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
597: {
598: enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
599: CERT_X509_CRL, issuer);
600: while (enumerator->enumerate(enumerator, &uri))
601: {
602: *uri_found = TRUE;
603: current = fetch_crl(uri);
604: if (current)
605: {
606: if (!current->has_issuer(current, issuer))
607: {
608: DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match CRL "
609: "issuer '%Y'", current->get_issuer(current), issuer);
610: current->destroy(current);
611: continue;
612: }
613: *best = get_better_crl(current, *best, subject,
614: &valid, TRUE, base);
615: if (*best && valid != VALIDATION_STALE)
616: {
617: break;
618: }
619: }
620: }
621: enumerator->destroy(enumerator);
622: }
623: return valid;
624: }
625:
626: /**
627: * Check if the issuer of the given CRL matches
628: */
629: static bool check_issuer(certificate_t *crl, x509_t *issuer, x509_cdp_t *cdp)
630: {
631: certificate_t *cissuer = (certificate_t*)issuer;
632: identification_t *id;
633: chunk_t chunk;
634: bool matches = FALSE;
635:
636: if (cdp->issuer)
637: {
638: return crl->has_issuer(crl, cdp->issuer);
639: }
640: /* check SKI/AKI first, but fall back to DN matching */
641: chunk = issuer->get_subjectKeyIdentifier(issuer);
642: if (chunk.len)
643: {
644: id = identification_create_from_encoding(ID_KEY_ID, chunk);
645: matches = crl->has_issuer(crl, id);
646: id->destroy(id);
647: }
648: return matches || crl->has_issuer(crl, cissuer->get_subject(cissuer));
649: }
650:
651: /**
652: * Look for a delta CRL for a given base CRL
653: */
654: static cert_validation_t check_delta_crl(x509_t *subject, x509_t *issuer,
655: crl_t *base, cert_validation_t base_valid)
656: {
657: cert_validation_t valid = VALIDATION_SKIPPED;
658: certificate_t *best = NULL, *current, *cissuer = (certificate_t*)issuer;
659: enumerator_t *enumerator;
660: identification_t *id;
661: x509_cdp_t *cdp;
662: chunk_t chunk;
663: bool uri;
664:
665: /* find cached delta CRL via subjectKeyIdentifier */
666: chunk = issuer->get_subjectKeyIdentifier(issuer);
667: if (chunk.len)
668: {
669: id = identification_create_from_encoding(ID_KEY_ID, chunk);
670: valid = find_crl(subject, id, base, &best, &uri);
671: id->destroy(id);
672: }
673:
674: /* find delta CRL by CRLIssuer */
675: enumerator = subject->create_crl_uri_enumerator(subject);
676: while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
677: enumerator->enumerate(enumerator, &cdp))
678: {
679: if (cdp->issuer)
680: {
681: valid = find_crl(subject, cdp->issuer, base, &best, &uri);
682: }
683: }
684: enumerator->destroy(enumerator);
685:
686: /* fetch from URIs found in Freshest CRL extension */
687: enumerator = base->create_delta_crl_uri_enumerator(base);
688: while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
689: enumerator->enumerate(enumerator, &cdp))
690: {
691: current = fetch_crl(cdp->uri);
692: if (current)
693: {
694: if (!check_issuer(current, issuer, cdp))
695: {
696: DBG1(DBG_CFG, "issuer of fetched delta CRL '%Y' does not match "
697: "certificate's %sissuer '%Y'",
698: current->get_issuer(current), cdp->issuer ? "CRL " : "",
699: cdp->issuer ?: cissuer->get_subject(cissuer));
700: current->destroy(current);
701: continue;
702: }
703: best = get_better_crl(current, best, subject, &valid, TRUE, base);
704: if (best && valid != VALIDATION_STALE)
705: {
706: break;
707: }
708: }
709: }
710: enumerator->destroy(enumerator);
711:
712: if (best)
713: {
714: best->destroy(best);
715: return valid;
716: }
717: return base_valid;
718: }
719:
720: /**
721: * validate a x509 certificate using CRL
722: */
723: static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
724: auth_cfg_t *auth)
725: {
726: cert_validation_t valid = VALIDATION_SKIPPED;
727: certificate_t *best = NULL, *cissuer = (certificate_t*)issuer;
728: identification_t *id;
729: x509_cdp_t *cdp;
730: bool uri_found = FALSE;
731: certificate_t *current;
732: enumerator_t *enumerator;
733: chunk_t chunk;
734:
735: /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
736: chunk = issuer->get_subjectKeyIdentifier(issuer);
737: if (chunk.len)
738: {
739: id = identification_create_from_encoding(ID_KEY_ID, chunk);
740: valid = find_crl(subject, id, NULL, &best, &uri_found);
741: id->destroy(id);
742: }
743:
744: /* find a cached CRL or fetch via configured CDP via CRLIssuer */
745: enumerator = subject->create_crl_uri_enumerator(subject);
746: while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
747: enumerator->enumerate(enumerator, &cdp))
748: {
749: if (cdp->issuer)
750: {
751: valid = find_crl(subject, cdp->issuer, NULL, &best, &uri_found);
752: }
753: }
754: enumerator->destroy(enumerator);
755:
756: /* fallback to fetching CRLs from CDPs found in subjects certificate */
757: if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
758: {
759: enumerator = subject->create_crl_uri_enumerator(subject);
760: while (enumerator->enumerate(enumerator, &cdp))
761: {
762: uri_found = TRUE;
763: current = fetch_crl(cdp->uri);
764: if (current)
765: {
766: if (!check_issuer(current, issuer, cdp))
767: {
768: DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match "
769: "certificate's %sissuer '%Y'",
770: current->get_issuer(current), cdp->issuer ? "CRL " : "",
771: cdp->issuer ?: cissuer->get_subject(cissuer));
772: current->destroy(current);
773: continue;
774: }
775: best = get_better_crl(current, best, subject, &valid,
776: TRUE, NULL);
777: if (best && valid != VALIDATION_STALE)
778: {
779: break;
780: }
781: }
782: }
783: enumerator->destroy(enumerator);
784: }
785:
786: /* look for delta CRLs */
787: if (best && (valid == VALIDATION_GOOD || valid == VALIDATION_STALE))
788: {
789: valid = check_delta_crl(subject, issuer, (crl_t*)best, valid);
790: }
791:
792: /* an uri was found, but no result. switch validation state to failed */
793: if (valid == VALIDATION_SKIPPED && uri_found)
794: {
795: valid = VALIDATION_FAILED;
796: }
797: if (valid == VALIDATION_SKIPPED)
798: { /* if we skipped CRL validation, we use the result of OCSP for
799: * constraint checking */
800: auth->add(auth, AUTH_RULE_CRL_VALIDATION,
801: auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
802: }
803: else
804: {
805: auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
806: }
807: DESTROY_IF(best);
808: return valid;
809: }
810:
811: METHOD(cert_validator_t, validate, bool,
812: private_revocation_validator_t *this, certificate_t *subject,
813: certificate_t *issuer, bool online, u_int pathlen, bool anchor,
814: auth_cfg_t *auth)
815: {
816: bool enable_ocsp, enable_crl;
817:
818: this->lock->lock(this->lock);
819: enable_ocsp = this->enable_ocsp;
820: enable_crl = this->enable_crl;
821: this->lock->unlock(this->lock);
822:
823: if (online && (enable_ocsp || enable_crl) &&
824: subject->get_type(subject) == CERT_X509 &&
825: issuer->get_type(issuer) == CERT_X509)
826: {
827: DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
828: subject->get_subject(subject));
829:
830: if (enable_ocsp)
831: {
832: switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth))
833: {
834: case VALIDATION_GOOD:
835: DBG1(DBG_CFG, "certificate status is good");
836: return TRUE;
837: case VALIDATION_REVOKED:
838: case VALIDATION_ON_HOLD:
839: /* has already been logged */
840: lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
841: subject);
842: return FALSE;
843: case VALIDATION_SKIPPED:
844: DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
845: break;
846: case VALIDATION_STALE:
847: DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
848: break;
849: case VALIDATION_FAILED:
850: DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
851: break;
852: }
853: }
854: else
855: {
856: auth->add(auth, AUTH_RULE_OCSP_VALIDATION, VALIDATION_SKIPPED);
857: }
858:
859: if (enable_crl)
860: {
861: switch (check_crl((x509_t*)subject, (x509_t*)issuer, auth))
862: {
863: case VALIDATION_GOOD:
864: DBG1(DBG_CFG, "certificate status is good");
865: return TRUE;
866: case VALIDATION_REVOKED:
867: case VALIDATION_ON_HOLD:
868: /* has already been logged */
869: lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
870: subject);
871: return FALSE;
872: case VALIDATION_FAILED:
873: case VALIDATION_SKIPPED:
874: DBG1(DBG_CFG, "certificate status is not available");
875: break;
876: case VALIDATION_STALE:
877: DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
878: break;
879: }
880: }
881: else
882: {
883: auth->add(auth, AUTH_RULE_CRL_VALIDATION,
884: auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
885: }
886:
887: lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_VALIDATION_FAILED,
888: subject);
889: }
890: return TRUE;
891: }
892:
893: METHOD(revocation_validator_t, reload, void,
894: private_revocation_validator_t *this)
895: {
896: bool enable_ocsp, enable_crl;
897:
898: enable_ocsp = lib->settings->get_bool(lib->settings,
899: "%s.plugins.revocation.enable_ocsp", TRUE, lib->ns);
900: enable_crl = lib->settings->get_bool(lib->settings,
901: "%s.plugins.revocation.enable_crl", TRUE, lib->ns);
902:
903: this->lock->lock(this->lock);
904: this->enable_ocsp = enable_ocsp;
905: this->enable_crl = enable_crl;
906: this->lock->unlock(this->lock);
907:
908: if (!enable_ocsp)
909: {
910: DBG1(DBG_LIB, "all OCSP validation disabled");
911: }
912: if (!enable_crl)
913: {
914: DBG1(DBG_LIB, "all CRL validation disabled");
915: }
916: }
917:
918: METHOD(revocation_validator_t, destroy, void,
919: private_revocation_validator_t *this)
920: {
921: this->lock->destroy(this->lock);
922: free(this);
923: }
924:
925: /**
926: * See header
927: */
928: revocation_validator_t *revocation_validator_create()
929: {
930: private_revocation_validator_t *this;
931:
932: INIT(this,
933: .public = {
934: .validator.validate = _validate,
935: .reload = _reload,
936: .destroy = _destroy,
937: },
938: .lock = spinlock_create(),
939: );
940:
941: reload(this);
942:
943: return &this->public;
944: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>