removed %Q, %Y, %W, %U printf handlers
[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 <stdio.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 bool is_valid(const private_crl_t *this)
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 return current_time < this->nextUpdate;
323 }
324
325 /**
326 * Implements crl_t.get_issuer
327 */
328 static identification_t *get_issuer(const private_crl_t *this)
329 {
330 return this->issuer;
331 }
332
333 /**
334 * Implements crl_t.equals_issuer
335 */
336 static bool equals_issuer(const private_crl_t *this, const private_crl_t *other)
337 {
338 return (this->authKeyID.ptr)
339 ? chunk_equals(this->authKeyID, other->authKeyID)
340 : (this->issuer->equals(this->issuer, other->issuer)
341 && chunk_equals_or_null(this->authKeySerialNumber, other->authKeySerialNumber));
342 }
343
344 /**
345 * Implements crl_t.is_issuer
346 */
347 static bool is_issuer(const private_crl_t *this, const x509_t *issuer)
348 {
349 return (this->authKeyID.ptr)
350 ? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer))
351 : (this->issuer->equals(this->issuer, issuer->get_subject(issuer))
352 && chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer)));
353 }
354
355 /**
356 * Implements crl_t.is_newer
357 */
358 static bool is_newer(const private_crl_t *this, const private_crl_t *other)
359 {
360 return (this->nextUpdate > other->nextUpdate);
361 }
362
363 /**
364 * Implements crl_t.verify
365 */
366 static bool verify(const private_crl_t *this, const rsa_public_key_t *signer)
367 {
368 return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature) == SUCCESS;
369 }
370
371 /**
372 * Implements crl_t.get_status
373 */
374 static void get_status(const private_crl_t *this, certinfo_t *certinfo)
375 {
376 chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
377 iterator_t *iterator;
378 revokedCert_t *revokedCert;
379
380 certinfo->set_nextUpdate(certinfo, this->nextUpdate);
381 certinfo->set_status(certinfo, CERT_GOOD);
382
383 iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE);
384 while (iterator->iterate(iterator, (void**)&revokedCert))
385 {
386 if (chunk_equals(serialNumber, revokedCert->userCertificate))
387 {
388 certinfo->set_status(certinfo, CERT_REVOKED);
389 certinfo->set_revocationTime(certinfo, revokedCert->revocationDate);
390 certinfo->set_revocationReason(certinfo, revokedCert->revocationReason);
391 break;
392 }
393 }
394 iterator->destroy(iterator);
395 }
396
397 /**
398 * Implements crl_t.write_to_file.
399 */
400 static bool write_to_file(private_crl_t *this, const char *path, mode_t mask, bool force)
401 {
402 return chunk_write(this->certificateList, path, "crl", mask, force);
403 }
404
405 /**
406 * Implements crl_t.destroy
407 */
408 static void destroy(private_crl_t *this)
409 {
410 this->revokedCertificates->destroy_function(this->revokedCertificates, free);
411 this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints,
412 offsetof(identification_t, destroy));
413 DESTROY_IF(this->issuer);
414 free(this->certificateList.ptr);
415 free(this);
416 }
417
418 /**
419 * Implementation of crl_t.list.
420 */
421 static void list(private_crl_t *this, FILE* out, bool utc)
422 {
423 time_t now;
424
425 now = time(NULL);
426
427 fprintf(out, "%#T, revoked certs: %d\n", &this->installed, utc,
428 this->revokedCertificates->get_count(this->revokedCertificates));
429 fprintf(out, " issuer: '%D'\n", this->issuer);
430 fprintf(out, " updates: this %#T\n", &this->thisUpdate, utc);
431 fprintf(out, " next %#T ", &this->nextUpdate, utc);
432 if (this->nextUpdate == UNDEFINED_TIME)
433 {
434 fprintf(out, "ok (expires never)");
435 }
436 else if (now > this->nextUpdate)
437 {
438 fprintf(out, "expired (%V ago)", &now, &this->nextUpdate);
439 }
440 else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
441 {
442 fprintf(out, "ok (expires in %V)", &now, &this->nextUpdate);
443 }
444 else
445 {
446 fprintf(out, "ok");
447 }
448 if (this->authKeyID.ptr)
449 {
450 fprintf(out, "\n authkey: %#B", &this->authKeyID);
451 }
452 if (this->authKeySerialNumber.ptr)
453 {
454 fprintf(out, "\n aserial: %#B", &this->authKeySerialNumber);
455 }
456 }
457
458 /*
459 * Described in header.
460 */
461 crl_t *crl_create_from_chunk(chunk_t chunk)
462 {
463 private_crl_t *this = malloc_thing(private_crl_t);
464
465 /* initialize */
466 this->crlDistributionPoints = linked_list_create();
467 this->tbsCertList = chunk_empty;
468 this->issuer = NULL;
469 this->revokedCertificates = linked_list_create();
470 this->authKeyID = chunk_empty;
471 this->authKeySerialNumber = chunk_empty;
472
473 /* public functions */
474 this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer;
475 this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer;
476 this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer;
477 this->public.is_valid = (bool (*) (const crl_t*))is_valid;
478 this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer;
479 this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
480 this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
481 this->public.write_to_file = (bool (*) (const crl_t*,const char*,mode_t,bool))write_to_file;
482 this->public.list = (void(*)(crl_t*, FILE* out, bool utc))list;
483 this->public.destroy = (void (*) (crl_t*))destroy;
484
485 if (!parse_x509crl(chunk, 0, this))
486 {
487 destroy(this);
488 return NULL;
489 }
490
491 return &this->public;
492 }
493
494 /*
495 * Described in header.
496 */
497 crl_t *crl_create_from_file(const char *filename)
498 {
499 bool pgp = FALSE;
500 chunk_t chunk = chunk_empty;
501 crl_t *crl = NULL;
502
503 if (!pem_asn1_load_file(filename, NULL, "crl", &chunk, &pgp))
504 return NULL;
505
506 crl = crl_create_from_chunk(chunk);
507
508 if (crl == NULL)
509 free(chunk.ptr);
510 return crl;
511 }