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