![]() ![]() | ![]() |
1.1 misho 1: /*
2: * Copyright (C) 2017 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * Copyright (C) 2010 Martin Willi
6: * Copyright (C) 2010 revosec AG
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: /*
20: * Copyright (C) 2010 secunet Security Networks AG
21: * Copyright (C) 2010 Thomas Egerer
22: *
23: * Permission is hereby granted, free of charge, to any person obtaining a copy
24: * of this software and associated documentation files (the "Software"), to deal
25: * in the Software without restriction, including without limitation the rights
26: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27: * copies of the Software, and to permit persons to whom the Software is
28: * furnished to do so, subject to the following conditions:
29: *
30: * The above copyright notice and this permission notice shall be included in
31: * all copies or substantial portions of the Software.
32: *
33: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39: * THE SOFTWARE.
40: */
41:
42: #include "openssl_crl.h"
43: #include "openssl_util.h"
44:
45: #include <openssl/x509.h>
46: #include <openssl/x509v3.h>
47:
48: #include <utils/debug.h>
49: #include <collections/enumerator.h>
50: #include <credentials/certificates/x509.h>
51:
52: #if OPENSSL_VERSION_NUMBER < 0x10100000L
53: static inline void X509_CRL_get0_signature(const X509_CRL *crl, ASN1_BIT_STRING **psig, X509_ALGOR **palg) {
54: if (psig) { *psig = crl->signature; }
55: if (palg) { *palg = crl->sig_alg; }
56: }
57: #define X509_REVOKED_get0_serialNumber(r) ({ (r)->serialNumber; })
58: #define X509_REVOKED_get0_revocationDate(r) ({ (r)->revocationDate; })
59: #define X509_CRL_get0_extensions(c) ({ (c)->crl->extensions; })
60: #define ASN1_STRING_get0_data(a) ASN1_STRING_data(a)
61: #define X509_CRL_get0_lastUpdate(c) X509_CRL_get_lastUpdate(c)
62: #define X509_CRL_get0_nextUpdate(c) X509_CRL_get_nextUpdate(c)
63: #endif
64:
65: typedef struct private_openssl_crl_t private_openssl_crl_t;
66:
67: /**
68: * Private data of an openssl_crl_t object.
69: */
70: struct private_openssl_crl_t {
71:
72: /**
73: * Public openssl_crl_t interface.
74: */
75: openssl_crl_t public;
76:
77: /**
78: * OpenSSL representation of a CRL
79: */
80: X509_CRL *crl;
81:
82: /**
83: * DER encoding of the CRL
84: */
85: chunk_t encoding;
86:
87: /**
88: * Serial Number (crlNumber) of the CRL)
89: */
90: chunk_t serial;
91:
92: /**
93: * Number of base CRL (deltaCrlIndicator), if a delta CRL
94: */
95: chunk_t base;
96:
97: /**
98: * List of Freshest CRL distribution points
99: */
100: linked_list_t *crl_uris;
101:
102: /**
103: * AuthorityKeyIdentifier of the issuing CA
104: */
105: chunk_t authKeyIdentifier;
106:
107: /**
108: * Date of this CRL
109: */
110: time_t thisUpdate;
111:
112: /**
113: * Date of next CRL expected
114: */
115: time_t nextUpdate;
116:
117: /**
118: * Issuer of this CRL
119: */
120: identification_t *issuer;
121:
122: /**
123: * Signature scheme used in this CRL
124: */
125: signature_params_t *scheme;
126:
127: /**
128: * References to this CRL
129: */
130: refcount_t ref;
131: };
132:
133: /**
134: * Enumerator over revoked certificates
135: */
136: typedef struct {
137: /**
138: * Implements enumerator_t
139: */
140: enumerator_t public;
141:
142: /**
143: * stack of revoked certificates
144: */
145: STACK_OF(X509_REVOKED) *stack;
146:
147: /**
148: * Total number of revoked certificates
149: */
150: int num;
151:
152: /**
153: * Current position of enumerator
154: */
155: int i;
156: } crl_enumerator_t;
157:
158: /**
159: * from openssl_x509
160: */
161: bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext,
162: linked_list_t *list);
163:
164: METHOD(enumerator_t, crl_enumerate, bool,
165: crl_enumerator_t *this, va_list args)
166: {
167: crl_reason_t *reason;
168: chunk_t *serial;
169: time_t *date;
170:
171: VA_ARGS_VGET(args, serial, date, reason);
172:
173: if (this->i < this->num)
174: {
175: X509_REVOKED *revoked;
176: ASN1_ENUMERATED *crlrsn;
177:
178: revoked = sk_X509_REVOKED_value(this->stack, this->i);
179: if (serial)
180: {
181: *serial = openssl_asn1_str2chunk(
182: X509_REVOKED_get0_serialNumber(revoked));
183: }
184: if (date)
185: {
186: *date = openssl_asn1_to_time(
187: X509_REVOKED_get0_revocationDate(revoked));
188: }
189: if (reason)
190: {
191: *reason = CRL_REASON_UNSPECIFIED;
192: crlrsn = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason,
193: NULL, NULL);
194: if (crlrsn)
195: {
196: if (ASN1_STRING_type(crlrsn) == V_ASN1_ENUMERATED &&
197: ASN1_STRING_length(crlrsn) == 1)
198: {
199: *reason = *ASN1_STRING_get0_data(crlrsn);
200: }
201: ASN1_STRING_free(crlrsn);
202: }
203: }
204: this->i++;
205: return TRUE;
206: }
207: return FALSE;
208: }
209:
210: METHOD(crl_t, create_enumerator, enumerator_t*,
211: private_openssl_crl_t *this)
212: {
213: crl_enumerator_t *enumerator;
214:
215: INIT(enumerator,
216: .public = {
217: .enumerate = enumerator_enumerate_default,
218: .venumerate = _crl_enumerate,
219: .destroy = (void*)free,
220: },
221: .stack = X509_CRL_get_REVOKED(this->crl),
222: );
223: if (!enumerator->stack)
224: {
225: free(enumerator);
226: return enumerator_create_empty();
227: }
228: enumerator->num = sk_X509_REVOKED_num(enumerator->stack);
229: return &enumerator->public;
230: }
231:
232: METHOD(crl_t, get_serial, chunk_t,
233: private_openssl_crl_t *this)
234: {
235: return this->serial;
236: }
237:
238: METHOD(crl_t, is_delta_crl, bool,
239: private_openssl_crl_t *this, chunk_t *base_crl)
240: {
241: if (this->base.len)
242: {
243: if (base_crl)
244: {
245: *base_crl = this->base;
246: }
247: return TRUE;
248: }
249: return FALSE;
250: }
251:
252: METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*,
253: private_openssl_crl_t *this)
254: {
255: return this->crl_uris->create_enumerator(this->crl_uris);
256: }
257:
258: METHOD(crl_t, get_authKeyIdentifier, chunk_t,
259: private_openssl_crl_t *this)
260: {
261: return this->authKeyIdentifier;
262: }
263:
264: METHOD(certificate_t, get_type, certificate_type_t,
265: private_openssl_crl_t *this)
266: {
267: return CERT_X509_CRL;
268: }
269:
270: METHOD(certificate_t, get_subject_or_issuer, identification_t*,
271: private_openssl_crl_t *this)
272: {
273: return this->issuer;
274: }
275:
276: METHOD(certificate_t, has_subject_or_issuer, id_match_t,
277: private_openssl_crl_t *this, identification_t *id)
278: {
279: if (id->get_type(id) == ID_KEY_ID &&
280: chunk_equals(this->authKeyIdentifier, id->get_encoding(id)))
281: {
282: return ID_MATCH_PERFECT;
283: }
284: return this->issuer->matches(this->issuer, id);
285: }
286:
287: METHOD(certificate_t, issued_by, bool,
288: private_openssl_crl_t *this, certificate_t *issuer,
289: signature_params_t **scheme)
290: {
291: chunk_t fingerprint, tbs;
292: public_key_t *key;
293: x509_t *x509;
294: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
295: const ASN1_BIT_STRING *sig;
296: #else
297: ASN1_BIT_STRING *sig;
298: #endif
299: bool valid;
300:
301: if (issuer->get_type(issuer) != CERT_X509)
302: {
303: return FALSE;
304: }
305: x509 = (x509_t*)issuer;
1.1.1.2 ! misho 306: if (!(x509->get_flags(x509) & (X509_CA | X509_CRL_SIGN)))
1.1 misho 307: {
308: return FALSE;
309: }
310: key = issuer->get_public_key(issuer);
311: if (!key)
312: {
313: return FALSE;
314: }
315: if (this->authKeyIdentifier.ptr && key)
316: {
317: if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) ||
318: !chunk_equals(fingerprint, this->authKeyIdentifier))
319: {
320: return FALSE;
321: }
322: }
323: else
324: {
325: if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
326: {
327: return FALSE;
328: }
329: }
330: /* i2d_re_X509_CRL_tbs() was added with 1.1.0 when X509_CRL became opaque */
331: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
332: tbs = openssl_i2chunk(re_X509_CRL_tbs, this->crl);
333: #else
334: tbs = openssl_i2chunk(X509_CRL_INFO, this->crl->crl);
335: #endif
336: X509_CRL_get0_signature(this->crl, &sig, NULL);
337: valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs,
338: openssl_asn1_str2chunk(sig));
339: free(tbs.ptr);
340: key->destroy(key);
341: if (valid && scheme)
342: {
343: *scheme = signature_params_clone(this->scheme);
344: }
345: return valid;
346: }
347:
348: METHOD(certificate_t, get_public_key, public_key_t*,
349: private_openssl_crl_t *this)
350: {
351: return NULL;
352: }
353:
354: METHOD(certificate_t, get_validity, bool,
355: private_openssl_crl_t *this,
356: time_t *when, time_t *not_before, time_t *not_after)
357: {
358: time_t t = when ? *when : time(NULL);
359:
360: if (not_before)
361: {
362: *not_before = this->thisUpdate;
363: }
364: if (not_after)
365: {
366: *not_after = this->nextUpdate;
367: }
368: return (t >= this->thisUpdate && t <= this->nextUpdate);
369: }
370:
371: METHOD(certificate_t, get_encoding, bool,
372: private_openssl_crl_t *this, cred_encoding_type_t type, chunk_t *encoding)
373: {
374: if (type == CERT_ASN1_DER)
375: {
376: *encoding = chunk_clone(this->encoding);
377: return TRUE;
378: }
379: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
380: CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END);
381: }
382:
383: METHOD(certificate_t, equals, bool,
384: private_openssl_crl_t *this, certificate_t *other)
385: {
386: chunk_t encoding;
387: bool equal;
388:
389: if (&this->public.crl.certificate == other)
390: {
391: return TRUE;
392: }
393: if (other->equals == (void*)equals)
394: { /* skip allocation if we have the same implementation */
395: return chunk_equals(this->encoding,
396: ((private_openssl_crl_t*)other)->encoding);
397: }
398: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
399: {
400: return FALSE;
401: }
402: equal = chunk_equals(this->encoding, encoding);
403: free(encoding.ptr);
404: return equal;
405: }
406:
407: METHOD(certificate_t, get_ref, certificate_t*,
408: private_openssl_crl_t *this)
409: {
410: ref_get(&this->ref);
411: return &this->public.crl.certificate;
412: }
413:
414: METHOD(certificate_t, destroy, void,
415: private_openssl_crl_t *this)
416: {
417: if (ref_put(&this->ref))
418: {
419: if (this->crl)
420: {
421: X509_CRL_free(this->crl);
422: }
423: signature_params_destroy(this->scheme);
424: this->crl_uris->destroy_function(this->crl_uris,
425: (void*)x509_cdp_destroy);
426: DESTROY_IF(this->issuer);
427: free(this->authKeyIdentifier.ptr);
428: free(this->base.ptr);
429: free(this->serial.ptr);
430: free(this->encoding.ptr);
431: free(this);
432: }
433: }
434:
435: /**
436: * Create an empty CRL.
437: */
438: static private_openssl_crl_t *create_empty()
439: {
440: private_openssl_crl_t *this;
441:
442: INIT(this,
443: .public = {
444: .crl = {
445: .certificate = {
446: .get_type = _get_type,
447: .get_subject = _get_subject_or_issuer,
448: .get_issuer = _get_subject_or_issuer,
449: .has_subject = _has_subject_or_issuer,
450: .has_issuer = _has_subject_or_issuer,
451: .issued_by = _issued_by,
452: .get_public_key = _get_public_key,
453: .get_validity = _get_validity,
454: .get_encoding = _get_encoding,
455: .equals = _equals,
456: .get_ref = _get_ref,
457: .destroy = _destroy,
458: },
459: .get_serial = _get_serial,
460: .get_authKeyIdentifier = _get_authKeyIdentifier,
461: .is_delta_crl = _is_delta_crl,
462: .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator,
463: .create_enumerator = _create_enumerator,
464: },
465: },
466: .crl_uris = linked_list_create(),
467: .ref = 1,
468: );
469: return this;
470: }
471:
472: /**
473: * Parse the authKeyIdentifier extension
474: */
475: static bool parse_authKeyIdentifier_ext(private_openssl_crl_t *this,
476: X509_EXTENSION *ext)
477: {
478: AUTHORITY_KEYID *keyid;
479:
480: keyid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
481: if (keyid)
482: {
483: free(this->authKeyIdentifier.ptr);
484: this->authKeyIdentifier = chunk_clone(
485: openssl_asn1_str2chunk(keyid->keyid));
486: AUTHORITY_KEYID_free(keyid);
487: return TRUE;
488: }
489: return FALSE;
490: }
491:
492: /**
493: * Quick and dirty INTEGER unwrap for crlNumber/deltaCrlIndicator extensions
494: */
495: static bool parse_integer_ext(X509_EXTENSION *ext, chunk_t *out)
496: {
497: chunk_t chunk;
498:
499: chunk = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
500: if (chunk.len > 1 && chunk.ptr[0] == V_ASN1_INTEGER &&
501: chunk.ptr[1] == chunk.len - 2)
502: {
503: chunk = chunk_skip(chunk, 2);
504: free(out->ptr);
505: *out = chunk_clone(chunk);
506: return TRUE;
507: }
508: return FALSE;
509: }
510:
511: /**
512: * Parse X509 CRL extensions
513: */
514: static bool parse_extensions(private_openssl_crl_t *this)
515: {
516: bool ok;
517: int i, num;
518: X509_EXTENSION *ext;
519: const STACK_OF(X509_EXTENSION) *extensions;
520:
521: extensions = X509_CRL_get0_extensions(this->crl);
522: if (extensions)
523: {
524: num = sk_X509_EXTENSION_num(extensions);
525: for (i = 0; i < num; ++i)
526: {
527: ext = sk_X509_EXTENSION_value(extensions, i);
528:
529: switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext)))
530: {
531: case NID_authority_key_identifier:
532: ok = parse_authKeyIdentifier_ext(this, ext);
533: break;
534: case NID_crl_number:
535: ok = parse_integer_ext(ext, &this->serial);
536: break;
537: case NID_delta_crl:
538: ok = parse_integer_ext(ext, &this->base);
539: break;
540: case NID_freshest_crl:
541: ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris);
542: break;
543: case NID_issuing_distribution_point:
544: /* TODO support of IssuingDistributionPoints */
545: ok = TRUE;
546: break;
547: default:
548: ok = X509_EXTENSION_get_critical(ext) == 0 ||
549: !lib->settings->get_bool(lib->settings,
550: "%s.x509.enforce_critical", TRUE, lib->ns);
551: if (!ok)
552: {
553: DBG1(DBG_LIB, "found unsupported critical X.509 "
554: "CRL extension");
555: }
556: break;
557: }
558: if (!ok)
559: {
560: return FALSE;
561: }
562: }
563: }
564: return TRUE;
565: }
566:
567: /**
568: * Parse a X509 CRL
569: */
570: static bool parse_crl(private_openssl_crl_t *this)
571: {
572: const unsigned char *ptr = this->encoding.ptr;
573: chunk_t sig_scheme;
574: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
575: const X509_ALGOR *alg;
576: #else
577: X509_ALGOR *alg;
578: #endif
579:
580: this->crl = d2i_X509_CRL(NULL, &ptr, this->encoding.len);
581: if (!this->crl)
582: {
583: return FALSE;
584: }
585:
586: X509_CRL_get0_signature(this->crl, NULL, &alg);
587: sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
588: INIT(this->scheme);
589: if (!signature_params_parse(sig_scheme, 0, this->scheme))
590: {
591: DBG1(DBG_ASN, "unable to parse signature algorithm");
592: free(sig_scheme.ptr);
593: return FALSE;
594: }
595: free(sig_scheme.ptr);
596:
597: this->issuer = openssl_x509_name2id(X509_CRL_get_issuer(this->crl));
598: if (!this->issuer)
599: {
600: return FALSE;
601: }
602: this->thisUpdate = openssl_asn1_to_time(X509_CRL_get0_lastUpdate(this->crl));
603: this->nextUpdate = openssl_asn1_to_time(X509_CRL_get0_nextUpdate(this->crl));
604:
605: return parse_extensions(this);
606: }
607:
608: /**
609: * Load the CRL.
610: */
611: openssl_crl_t *openssl_crl_load(certificate_type_t type, va_list args)
612: {
613: chunk_t blob = chunk_empty;
614:
615: while (TRUE)
616: {
617: switch (va_arg(args, builder_part_t))
618: {
619: case BUILD_BLOB_ASN1_DER:
620: blob = va_arg(args, chunk_t);
621: continue;
622: case BUILD_END:
623: break;
624: default:
625: return NULL;
626: }
627: break;
628: }
629: if (blob.ptr)
630: {
631: private_openssl_crl_t *this = create_empty();
632:
633: this->encoding = chunk_clone(blob);
634: if (parse_crl(this))
635: {
636: return &this->public;
637: }
638: destroy(this);
639: }
640: return NULL;
641: }