redesigned format of print function
[strongswan.git] / src / libstrongswan / crypto / crl.c
1 /**
2 * @file crl.c
3 *
4 * @brief Implementation of crl_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Andreas Steffen
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <printf.h>
27
28 #include <types.h>
29 #include <library.h>
30 #include <definitions.h>
31 #include <asn1/oid.h>
32 #include <asn1/asn1.h>
33 #include <asn1/pem.h>
34 #include <utils/linked_list.h>
35 #include <utils/identification.h>
36
37 #include "certinfo.h"
38 #include "x509.h"
39 #include "crl.h"
40
41 #define CRL_WARNING_INTERVAL 7 /* days */
42
43 extern char* check_expiry(time_t expiration_date, int warning_interval, bool strict);
44 extern time_t parse_time(chunk_t blob, int level0);
45 extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
46
47 /* access structure for a revoked certificate */
48
49 typedef struct revokedCert_t revokedCert_t;
50
51 struct revokedCert_t {
52 chunk_t userCertificate;
53 time_t revocationDate;
54 crl_reason_t revocationReason;
55 };
56
57 typedef struct private_crl_t private_crl_t;
58
59 /**
60 * Private data of a crl_t object.
61 */
62 struct private_crl_t {
63 /**
64 * Public interface for this crl.
65 */
66 crl_t public;
67
68 /**
69 * Time when crl was installed
70 */
71 time_t installed;
72
73 /**
74 * List of crlDistributionPoints
75 */
76 linked_list_t *crlDistributionPoints;
77
78 /**
79 * X.509 crl in DER format
80 */
81 chunk_t certificateList;
82
83 /**
84 * X.509 crl body over which signature is computed
85 */
86 chunk_t tbsCertList;
87
88 /**
89 * Version of the X.509 crl
90 */
91 u_int version;
92
93 /**
94 * Signature algorithm
95 */
96 int sigAlg;
97
98 /**
99 * ID representing the crl issuer
100 */
101 identification_t *issuer;
102
103 /**
104 * Time when the crl was generated
105 */
106 time_t thisUpdate;
107
108 /**
109 * Time when an update crl will be available
110 */
111 time_t nextUpdate;
112
113 /**
114 * List of identification_t's representing subjectAltNames
115 */
116 linked_list_t *revokedCertificates;
117
118 /**
119 * Authority Key Identifier
120 */
121 chunk_t authKeyID;
122
123 /**
124 * Authority Key Serial Number
125 */
126 chunk_t authKeySerialNumber;
127
128 /**
129 * Signature algorithm (must be identical to sigAlg)
130 */
131 int algorithm;
132
133 /**
134 * Signature
135 */
136 chunk_t signature;
137 };
138
139 /**
140 * ASN.1 definition of an X.509 certificate revocation list
141 */
142 static const asn1Object_t crlObjects[] = {
143 { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
144 { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
145 { 2, "version", ASN1_INTEGER, ASN1_OPT |
146 ASN1_BODY }, /* 2 */
147 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
148 { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
149 { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
150 { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
151 { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
152 { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
153 ASN1_LOOP }, /* 8 */
154 { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
155 { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
156 { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
157 { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
158 ASN1_LOOP }, /* 12 */
159 { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
160 { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
161 { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
162 ASN1_BODY }, /* 15 */
163 { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
164 { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
165 { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
166 { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
167 { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
168 { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
169 { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
170 { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
171 ASN1_BODY }, /* 23 */
172 { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
173 { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
174 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
175 { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
176 { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
177 };
178
179 #define CRL_OBJ_CERTIFICATE_LIST 0
180 #define CRL_OBJ_TBS_CERT_LIST 1
181 #define CRL_OBJ_VERSION 2
182 #define CRL_OBJ_SIG_ALG 4
183 #define CRL_OBJ_ISSUER 5
184 #define CRL_OBJ_THIS_UPDATE 6
185 #define CRL_OBJ_NEXT_UPDATE 7
186 #define CRL_OBJ_USER_CERTIFICATE 10
187 #define CRL_OBJ_REVOCATION_DATE 11
188 #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
189 #define CRL_OBJ_CRL_ENTRY_CRITICAL 15
190 #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
191 #define CRL_OBJ_EXTN_ID 22
192 #define CRL_OBJ_CRITICAL 23
193 #define CRL_OBJ_EXTN_VALUE 24
194 #define CRL_OBJ_ALGORITHM 27
195 #define CRL_OBJ_SIGNATURE 28
196 #define CRL_OBJ_ROOF 29
197
198 /**
199 * Parses a CRL revocation reason code
200 */
201 static crl_reason_t parse_crl_reasonCode(chunk_t object)
202 {
203 crl_reason_t reason = REASON_UNSPECIFIED;
204
205 if (*object.ptr == ASN1_ENUMERATED && asn1_length(&object) == 1)
206 {
207 reason = *object.ptr;
208 }
209 DBG2(" '%N'", crl_reason_names, reason);
210
211 return reason;
212 }
213
214 /**
215 * Parses an X.509 Certificate Revocation List (CRL)
216 */
217 bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl)
218 {
219 asn1_ctx_t ctx;
220 bool critical;
221 chunk_t extnID;
222 chunk_t userCertificate = CHUNK_INITIALIZER;
223 revokedCert_t *revokedCert = NULL;
224 chunk_t object;
225 u_int level;
226 int objectID = 0;
227
228 asn1_init(&ctx, blob, level0, FALSE, FALSE);
229
230 while (objectID < CRL_OBJ_ROOF)
231 {
232 if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
233 return FALSE;
234
235 /* those objects which will parsed further need the next higher level */
236 level++;
237
238 switch (objectID)
239 {
240 case CRL_OBJ_CERTIFICATE_LIST:
241 crl->certificateList = object;
242 break;
243 case CRL_OBJ_TBS_CERT_LIST:
244 crl->tbsCertList = object;
245 break;
246 case CRL_OBJ_VERSION:
247 crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
248 DBG2(" v%d", crl->version);
249 break;
250 case CRL_OBJ_SIG_ALG:
251 crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
252 break;
253 case CRL_OBJ_ISSUER:
254 crl->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
255 DBG2(" '%D'", crl->issuer);
256 break;
257 case CRL_OBJ_THIS_UPDATE:
258 crl->thisUpdate = parse_time(object, level);
259 break;
260 case CRL_OBJ_NEXT_UPDATE:
261 crl->nextUpdate = parse_time(object, level);
262 break;
263 case CRL_OBJ_USER_CERTIFICATE:
264 userCertificate = object;
265 break;
266 case CRL_OBJ_REVOCATION_DATE:
267 revokedCert = malloc_thing(revokedCert_t);
268 revokedCert->userCertificate = userCertificate;
269 revokedCert->revocationDate = parse_time(object, level);
270 revokedCert->revocationReason = REASON_UNSPECIFIED;
271 crl->revokedCertificates->insert_last(crl->revokedCertificates, (void *)revokedCert);
272 break;
273 case CRL_OBJ_CRL_ENTRY_EXTN_ID:
274 case CRL_OBJ_EXTN_ID:
275 extnID = object;
276 break;
277 case CRL_OBJ_CRL_ENTRY_CRITICAL:
278 case CRL_OBJ_CRITICAL:
279 critical = object.len && *object.ptr;
280 DBG2(" %s",(critical)?"TRUE":"FALSE");
281 break;
282 case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
283 case CRL_OBJ_EXTN_VALUE:
284 {
285 int extn_oid = known_oid(extnID);
286
287 if (revokedCert && extn_oid == OID_CRL_REASON_CODE)
288 {
289 revokedCert->revocationReason = parse_crl_reasonCode(object);
290 }
291 else if (extn_oid == OID_AUTHORITY_KEY_ID)
292 {
293 parse_authorityKeyIdentifier(object, level, &crl->authKeyID, &crl->authKeySerialNumber);
294 }
295 }
296 break;
297 case CRL_OBJ_ALGORITHM:
298 crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
299 break;
300 case CRL_OBJ_SIGNATURE:
301 crl->signature = object;
302 break;
303 default:
304 break;
305 }
306 objectID++;
307 }
308 time(&crl->installed);
309 return TRUE;
310 }
311
312 /**
313 * Implements crl_t.is_valid
314 */
315 static err_t is_valid(const private_crl_t *this, time_t *until, bool strict)
316 {
317 time_t current_time = time(NULL);
318
319 DBG2(" this update : %T", this->thisUpdate);
320 DBG2(" current time: %T", current_time);
321 DBG2(" next update: %T", this->nextUpdate);
322
323 if (strict && until != NULL &&
324 (*until == UNDEFINED_TIME || this->nextUpdate < *until))
325 {
326 *until = this->nextUpdate;
327 }
328 if (current_time > this->nextUpdate)
329 {
330 return "has expired";
331 }
332 DBG2(" crl is valid");
333 return NULL;
334 }
335
336 /**
337 * Implements crl_t.get_issuer
338 */
339 static identification_t *get_issuer(const private_crl_t *this)
340 {
341 return this->issuer;
342 }
343
344 /**
345 * Implements crl_t.equals_issuer
346 */
347 static bool equals_issuer(const private_crl_t *this, const private_crl_t *other)
348 {
349 return (this->authKeyID.ptr)
350 ? chunk_equals(this->authKeyID, other->authKeyID)
351 : (this->issuer->equals(this->issuer, other->issuer)
352 && chunk_equals_or_null(this->authKeySerialNumber, other->authKeySerialNumber));
353 }
354
355 /**
356 * Implements crl_t.is_issuer
357 */
358 static bool is_issuer(const private_crl_t *this, const x509_t *issuer)
359 {
360 return (this->authKeyID.ptr)
361 ? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer))
362 : (this->issuer->equals(this->issuer, issuer->get_subject(issuer))
363 && chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer)));
364 }
365
366 /**
367 * Implements crl_t.is_newer
368 */
369 static bool is_newer(const private_crl_t *this, const private_crl_t *other)
370 {
371 return (this->nextUpdate > other->nextUpdate);
372 }
373
374 /**
375 * Implements crl_t.verify
376 */
377 static bool verify(const private_crl_t *this, const rsa_public_key_t *signer)
378 {
379 return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature) == SUCCESS;
380 }
381
382 /**
383 * Implements crl_t.get_status
384 */
385 static void get_status(const private_crl_t *this, certinfo_t *certinfo)
386 {
387 chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
388 iterator_t *iterator;
389 revokedCert_t *revokedCert;
390
391 certinfo->set_nextUpdate(certinfo, this->nextUpdate);
392 certinfo->set_status(certinfo, CERT_GOOD);
393
394 iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE);
395 while (iterator->iterate(iterator, (void**)&revokedCert))
396 {
397 if (chunk_equals(serialNumber, revokedCert->userCertificate))
398 {
399 certinfo->set_status(certinfo, CERT_REVOKED);
400 certinfo->set_revocationTime(certinfo, revokedCert->revocationDate);
401 certinfo->set_revocationReason(certinfo, revokedCert->revocationReason);
402 break;
403 }
404 }
405 iterator->destroy(iterator);
406 }
407
408 /**
409 * Implements crl_t.destroy
410 */
411 static void destroy(private_crl_t *this)
412 {
413 this->revokedCertificates->destroy_function(this->revokedCertificates, free);
414 this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints,
415 offsetof(identification_t, destroy));
416 DESTROY_IF(this->issuer);
417 free(this->certificateList.ptr);
418 free(this);
419 }
420
421 /**
422 * output handler in printf()
423 */
424 static int print(FILE *stream, const struct printf_info *info,
425 const void *const *args)
426 {
427 private_crl_t *this = *((private_crl_t**)(args[0]));
428 bool utc = TRUE;
429 int written = 0;
430 time_t now;
431
432 if (info->alt)
433 {
434 utc = *((bool*)args[1]);
435 }
436
437 if (this == NULL)
438 {
439 return fprintf(stream, "(null)");
440 }
441
442 now = time(NULL);
443
444 written += fprintf(stream, "%#T, revoked certs: %d\n", this->installed, utc,
445 this->revokedCertificates->get_count(this->revokedCertificates));
446 written += fprintf(stream, " issuer: '%D'\n", this->issuer);
447 written += fprintf(stream, " updates: this %#T\n", this->thisUpdate, utc);
448 written += fprintf(stream, " next %#T ", this->nextUpdate, utc);
449 if (this->nextUpdate == UNDEFINED_TIME)
450 {
451 written += fprintf(stream, "ok (expires never)");
452 }
453 else if (now > this->nextUpdate)
454 {
455 written += fprintf(stream, "expired (since %V)", now, this->nextUpdate);
456 }
457 else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
458 {
459 written += fprintf(stream, "ok (expires in %V)", now, this->nextUpdate);
460 }
461 else
462 {
463 written += fprintf(stream, "ok");
464 }
465 if (this->authKeyID.ptr)
466 {
467 written += fprintf(stream, "\n authkey: %#B", &this->authKeyID);
468 }
469 if (this->authKeySerialNumber.ptr)
470 {
471 written += fprintf(stream, "\n aserial: %#B", &this->authKeySerialNumber);
472 }
473 return written;
474 }
475
476 /**
477 * arginfo handler in printf()
478 */
479 static int print_arginfo(const struct printf_info *info, size_t n, int *argtypes)
480 {
481 if (info->alt)
482 {
483 if (n > 1)
484 {
485 argtypes[0] = PA_POINTER;
486 argtypes[1] = PA_INT;
487 }
488 return 2;
489 }
490
491 if (n > 0)
492 {
493 argtypes[0] = PA_POINTER;
494 }
495 return 1;
496 }
497
498 /**
499 * register printf() handlers
500 */
501 static void __attribute__ ((constructor))print_register()
502 {
503 register_printf_function(CRL_PRINTF_SPEC, print, print_arginfo);
504 }
505
506 /*
507 * Described in header.
508 */
509 crl_t *crl_create_from_chunk(chunk_t chunk)
510 {
511 private_crl_t *this = malloc_thing(private_crl_t);
512
513 /* initialize */
514 this->crlDistributionPoints = linked_list_create();
515 this->tbsCertList = CHUNK_INITIALIZER;
516 this->issuer = NULL;
517 this->revokedCertificates = linked_list_create();
518 this->authKeyID = CHUNK_INITIALIZER;
519 this->authKeySerialNumber = CHUNK_INITIALIZER;
520
521 /* public functions */
522 this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer;
523 this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer;
524 this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer;
525 this->public.is_valid = (err_t (*) (const crl_t*,time_t*,bool))is_valid;
526 this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer;
527 this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
528 this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
529 this->public.destroy = (void (*) (crl_t*))destroy;
530
531 if (!parse_x509crl(chunk, 0, this))
532 {
533 destroy(this);
534 return NULL;
535 }
536
537 return &this->public;
538 }
539
540 /*
541 * Described in header.
542 */
543 crl_t *crl_create_from_file(const char *filename)
544 {
545 bool pgp = FALSE;
546 chunk_t chunk = CHUNK_INITIALIZER;
547 crl_t *crl = NULL;
548
549 if (!pem_asn1_load_file(filename, NULL, "crl", &chunk, &pgp))
550 return NULL;
551
552 crl = crl_create_from_chunk(chunk);
553
554 if (crl == NULL)
555 free(chunk.ptr);
556 return crl;
557 }