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