/src/strongswan/src/libstrongswan/plugins/x509/x509_crl.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2014-2017 Tobias Brunner |
3 | | * Copyright (C) 2008-2009 Martin Willi |
4 | | * Copyright (C) 2017-2022 Andreas Steffen |
5 | | * |
6 | | * Copyright (C) secunet Security Networks 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 | | #include "x509_crl.h" |
20 | | |
21 | | typedef struct private_x509_crl_t private_x509_crl_t; |
22 | | |
23 | | #include <time.h> |
24 | | |
25 | | #include <utils/debug.h> |
26 | | #include <library.h> |
27 | | #include <asn1/oid.h> |
28 | | #include <asn1/asn1.h> |
29 | | #include <asn1/asn1_parser.h> |
30 | | #include <credentials/certificates/x509.h> |
31 | | #include <credentials/keys/private_key.h> |
32 | | #include <collections/linked_list.h> |
33 | | |
34 | | /** |
35 | | * private data of x509_crl |
36 | | */ |
37 | | struct private_x509_crl_t { |
38 | | |
39 | | /** |
40 | | * public functions |
41 | | */ |
42 | | x509_crl_t public; |
43 | | |
44 | | /** |
45 | | * X.509 crl encoding in ASN.1 DER format |
46 | | */ |
47 | | chunk_t encoding; |
48 | | |
49 | | /** |
50 | | * X.509 crl body over which signature is computed |
51 | | */ |
52 | | chunk_t tbsCertList; |
53 | | |
54 | | /** |
55 | | * Version of the X.509 crl |
56 | | */ |
57 | | u_int version; |
58 | | |
59 | | /** |
60 | | * ID representing the crl issuer |
61 | | */ |
62 | | identification_t *issuer; |
63 | | |
64 | | /** |
65 | | * CRL number |
66 | | */ |
67 | | chunk_t crlNumber; |
68 | | |
69 | | /** |
70 | | * Time when the crl was generated |
71 | | */ |
72 | | time_t thisUpdate; |
73 | | |
74 | | /** |
75 | | * Time when an update crl will be available |
76 | | */ |
77 | | time_t nextUpdate; |
78 | | |
79 | | /** |
80 | | * list of revoked certificates as crl_revoked_t |
81 | | */ |
82 | | linked_list_t *revoked; |
83 | | |
84 | | /** |
85 | | * List of Freshest CRL distribution points |
86 | | */ |
87 | | linked_list_t *crl_uris; |
88 | | |
89 | | /** |
90 | | * Authority Key Identifier |
91 | | */ |
92 | | chunk_t authKeyIdentifier; |
93 | | |
94 | | /** |
95 | | * Authority Key Serial Number |
96 | | */ |
97 | | chunk_t authKeySerialNumber; |
98 | | |
99 | | /** |
100 | | * Optional OID of an [unsupported] critical extension |
101 | | */ |
102 | | chunk_t critical_extension_oid; |
103 | | |
104 | | /** |
105 | | * Number of BaseCRL, if a delta CRL |
106 | | */ |
107 | | chunk_t baseCrlNumber; |
108 | | |
109 | | /** |
110 | | * Signature scheme |
111 | | */ |
112 | | signature_params_t *scheme; |
113 | | |
114 | | /** |
115 | | * Signature |
116 | | */ |
117 | | chunk_t signature; |
118 | | |
119 | | /** |
120 | | * has this CRL been generated |
121 | | */ |
122 | | bool generated; |
123 | | |
124 | | /** |
125 | | * reference counter |
126 | | */ |
127 | | refcount_t ref; |
128 | | }; |
129 | | |
130 | | /** |
131 | | * from x509_cert |
132 | | */ |
133 | | extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, |
134 | | chunk_t *authKeySerialNumber); |
135 | | |
136 | | /** |
137 | | * from x509_cert |
138 | | */ |
139 | | extern bool x509_parse_crlDistributionPoints(chunk_t blob, int level0, |
140 | | linked_list_t *list); |
141 | | |
142 | | /** |
143 | | * from x509_cert |
144 | | */ |
145 | | extern chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn); |
146 | | |
147 | | /** |
148 | | * ASN.1 definition of an X.509 certificate revocation list |
149 | | */ |
150 | | static const asn1Object_t crlObjects[] = { |
151 | | { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ |
152 | | { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ |
153 | | { 2, "version", ASN1_INTEGER, ASN1_OPT | |
154 | | ASN1_BODY }, /* 2 */ |
155 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ |
156 | | { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ |
157 | | { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ |
158 | | { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ |
159 | | { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ |
160 | | { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | |
161 | | ASN1_LOOP }, /* 8 */ |
162 | | { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ |
163 | | { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ |
164 | | { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ |
165 | | { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | |
166 | | ASN1_LOOP }, /* 12 */ |
167 | | { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ |
168 | | { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ |
169 | | { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | |
170 | | ASN1_BODY }, /* 15 */ |
171 | | { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ |
172 | | { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ |
173 | | { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ |
174 | | { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ |
175 | | { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ |
176 | | { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ |
177 | | { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ |
178 | | { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | |
179 | | ASN1_BODY }, /* 23 */ |
180 | | { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ |
181 | | { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ |
182 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ |
183 | | { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ |
184 | | { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */ |
185 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
186 | | }; |
187 | 1.51k | #define CRL_OBJ_TBS_CERT_LIST 1 |
188 | 941 | #define CRL_OBJ_VERSION 2 |
189 | 1.48k | #define CRL_OBJ_SIG_ALG 4 |
190 | 741 | #define CRL_OBJ_ISSUER 5 |
191 | 740 | #define CRL_OBJ_THIS_UPDATE 6 |
192 | 669 | #define CRL_OBJ_NEXT_UPDATE 7 |
193 | 22.8k | #define CRL_OBJ_USER_CERTIFICATE 10 |
194 | 22.8k | #define CRL_OBJ_REVOCATION_DATE 11 |
195 | 3.45k | #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14 |
196 | 3.45k | #define CRL_OBJ_CRL_ENTRY_CRITICAL 15 |
197 | 3.44k | #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 |
198 | 5.23k | #define CRL_OBJ_EXTN_ID 22 |
199 | 5.23k | #define CRL_OBJ_CRITICAL 23 |
200 | 5.20k | #define CRL_OBJ_EXTN_VALUE 24 |
201 | 231 | #define CRL_OBJ_ALGORITHM 27 |
202 | 26 | #define CRL_OBJ_SIGNATURE 28 |
203 | | |
204 | | /** |
205 | | * Parses an X.509 Certificate Revocation List (CRL) |
206 | | */ |
207 | | static bool parse(private_x509_crl_t *this) |
208 | 1.75k | { |
209 | 1.75k | asn1_parser_t *parser; |
210 | 1.75k | chunk_t object; |
211 | 1.75k | chunk_t extnID = chunk_empty; |
212 | 1.75k | chunk_t userCertificate = chunk_empty; |
213 | 1.75k | int objectID; |
214 | 1.75k | signature_params_t sig_alg = {}; |
215 | 1.75k | bool success = FALSE; |
216 | 1.75k | bool critical = FALSE; |
217 | 1.75k | crl_revoked_t *revoked = NULL; |
218 | | |
219 | 1.75k | parser = asn1_parser_create(crlObjects, this->encoding); |
220 | | |
221 | 127k | while (parser->iterate(parser, &objectID, &object)) |
222 | 126k | { |
223 | 126k | u_int level = parser->get_level(parser)+1; |
224 | | |
225 | 126k | switch (objectID) |
226 | 126k | { |
227 | 1.51k | case CRL_OBJ_TBS_CERT_LIST: |
228 | 1.51k | this->tbsCertList = object; |
229 | 1.51k | break; |
230 | 941 | case CRL_OBJ_VERSION: |
231 | 941 | this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; |
232 | 941 | DBG2(DBG_ASN, " v%d", this->version); |
233 | 941 | break; |
234 | 1.48k | case CRL_OBJ_SIG_ALG: |
235 | 1.48k | if (!signature_params_parse(object, level, &sig_alg)) |
236 | 664 | { |
237 | 664 | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
238 | 664 | goto end; |
239 | 664 | } |
240 | 821 | break; |
241 | 821 | case CRL_OBJ_ISSUER: |
242 | 741 | this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); |
243 | 741 | DBG2(DBG_ASN, " '%Y'", this->issuer); |
244 | 741 | break; |
245 | 740 | case CRL_OBJ_THIS_UPDATE: |
246 | 740 | this->thisUpdate = asn1_parse_time(object, level); |
247 | 740 | break; |
248 | 669 | case CRL_OBJ_NEXT_UPDATE: |
249 | 669 | this->nextUpdate = asn1_parse_time(object, level); |
250 | 669 | break; |
251 | 22.8k | case CRL_OBJ_USER_CERTIFICATE: |
252 | 22.8k | userCertificate = object; |
253 | 22.8k | break; |
254 | 22.8k | case CRL_OBJ_REVOCATION_DATE: |
255 | 22.8k | revoked = malloc_thing(crl_revoked_t); |
256 | 22.8k | revoked->serial = chunk_clone(userCertificate); |
257 | 22.8k | revoked->date = asn1_parse_time(object, level); |
258 | 22.8k | revoked->reason = CRL_REASON_UNSPECIFIED; |
259 | 22.8k | this->revoked->insert_last(this->revoked, (void *)revoked); |
260 | 22.8k | break; |
261 | 3.45k | case CRL_OBJ_CRL_ENTRY_EXTN_ID: |
262 | 5.23k | case CRL_OBJ_EXTN_ID: |
263 | 5.23k | extnID = object; |
264 | 5.23k | break; |
265 | 3.45k | case CRL_OBJ_CRL_ENTRY_CRITICAL: |
266 | 5.23k | case CRL_OBJ_CRITICAL: |
267 | 5.23k | critical = object.len && *object.ptr; |
268 | 5.23k | DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); |
269 | 5.23k | break; |
270 | 3.44k | case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: |
271 | 5.20k | case CRL_OBJ_EXTN_VALUE: |
272 | 5.20k | { |
273 | 5.20k | int extn_oid = asn1_known_oid(extnID); |
274 | | |
275 | 5.20k | switch (extn_oid) |
276 | 5.20k | { |
277 | 2.95k | case OID_CRL_REASON_CODE: |
278 | 2.95k | if (revoked) |
279 | 2.91k | { |
280 | 2.91k | if (object.len && *object.ptr == ASN1_ENUMERATED && |
281 | 2.91k | asn1_length(&object) == 1) |
282 | 2.30k | { |
283 | 2.30k | revoked->reason = *object.ptr; |
284 | 2.30k | } |
285 | 2.91k | DBG2(DBG_ASN, " '%N'", crl_reason_names, |
286 | 2.91k | revoked->reason); |
287 | 2.91k | } |
288 | 2.95k | break; |
289 | 504 | case OID_AUTHORITY_KEY_ID: |
290 | 504 | chunk_free(&this->authKeyIdentifier); |
291 | 504 | this->authKeyIdentifier = |
292 | 504 | x509_parse_authorityKeyIdentifier( |
293 | 504 | object, level, &this->authKeySerialNumber); |
294 | 504 | break; |
295 | 49 | case OID_CRL_NUMBER: |
296 | 49 | if (!asn1_parse_simple_object(&object, ASN1_INTEGER, |
297 | 49 | level, "crlNumber")) |
298 | 5 | { |
299 | 5 | goto end; |
300 | 5 | } |
301 | 44 | this->crlNumber = object; |
302 | 44 | break; |
303 | 179 | case OID_FRESHEST_CRL: |
304 | 179 | if (!x509_parse_crlDistributionPoints(object, level, |
305 | 179 | this->crl_uris)) |
306 | 62 | { |
307 | 62 | goto end; |
308 | 62 | } |
309 | 117 | break; |
310 | 117 | case OID_DELTA_CRL_INDICATOR: |
311 | 30 | if (!asn1_parse_simple_object(&object, ASN1_INTEGER, |
312 | 30 | level, "deltaCrlIndicator")) |
313 | 6 | { |
314 | 6 | goto end; |
315 | 6 | } |
316 | 24 | this->baseCrlNumber = object; |
317 | 24 | break; |
318 | 146 | case OID_ISSUING_DIST_POINT: |
319 | | /* TODO support of IssuingDistributionPoints */ |
320 | 146 | break; |
321 | 1.34k | default: |
322 | 1.34k | if (critical && lib->settings->get_bool(lib->settings, |
323 | 12 | "%s.x509.enforce_critical", TRUE, lib->ns)) |
324 | 12 | { |
325 | 12 | DBG1(DBG_ASN, "critical '%s' extension not supported", |
326 | 12 | (extn_oid == OID_UNKNOWN) ? "unknown" : |
327 | 12 | (char*)oid_names[extn_oid].name); |
328 | 12 | goto end; |
329 | 12 | } |
330 | 1.32k | break; |
331 | 5.20k | } |
332 | 5.11k | break; |
333 | 5.20k | } |
334 | 5.11k | case CRL_OBJ_ALGORITHM: |
335 | 231 | { |
336 | 231 | INIT(this->scheme); |
337 | 231 | if (!signature_params_parse(object, level, this->scheme)) |
338 | 56 | { |
339 | 56 | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
340 | 56 | goto end; |
341 | 56 | } |
342 | 175 | if (!signature_params_equal(this->scheme, &sig_alg)) |
343 | 118 | { |
344 | 118 | DBG1(DBG_ASN, " signature algorithms do not agree"); |
345 | 118 | goto end; |
346 | 118 | } |
347 | 57 | break; |
348 | 175 | } |
349 | 57 | case CRL_OBJ_SIGNATURE: |
350 | 26 | this->signature = chunk_skip(object, 1); |
351 | 26 | break; |
352 | 59.1k | default: |
353 | 59.1k | break; |
354 | 126k | } |
355 | 126k | } |
356 | 830 | success = parser->success(parser); |
357 | | |
358 | 1.75k | end: |
359 | 1.75k | parser->destroy(parser); |
360 | 1.75k | signature_params_clear(&sig_alg); |
361 | 1.75k | return success; |
362 | 830 | } |
363 | | |
364 | | CALLBACK(filter, bool, |
365 | | void *data, enumerator_t *orig, va_list args) |
366 | 0 | { |
367 | 0 | crl_revoked_t *revoked; |
368 | 0 | crl_reason_t *reason; |
369 | 0 | chunk_t *serial; |
370 | 0 | time_t *date; |
371 | |
|
372 | 0 | VA_ARGS_VGET(args, serial, date, reason); |
373 | |
|
374 | 0 | if (orig->enumerate(orig, &revoked)) |
375 | 0 | { |
376 | 0 | if (serial) |
377 | 0 | { |
378 | 0 | *serial = chunk_skip_zero(revoked->serial); |
379 | 0 | } |
380 | 0 | if (date) |
381 | 0 | { |
382 | 0 | *date = revoked->date; |
383 | 0 | } |
384 | 0 | if (reason) |
385 | 0 | { |
386 | 0 | *reason = revoked->reason; |
387 | 0 | } |
388 | 0 | return TRUE; |
389 | 0 | } |
390 | 0 | return FALSE; |
391 | 0 | } |
392 | | |
393 | | METHOD(crl_t, get_serial, chunk_t, |
394 | | private_x509_crl_t *this) |
395 | 0 | { |
396 | 0 | return chunk_skip_zero(this->crlNumber); |
397 | 0 | } |
398 | | |
399 | | METHOD(crl_t, get_authKeyIdentifier, chunk_t, |
400 | | private_x509_crl_t *this) |
401 | 0 | { |
402 | 0 | return this->authKeyIdentifier; |
403 | 0 | } |
404 | | |
405 | | METHOD(crl_t, is_delta_crl, bool, |
406 | | private_x509_crl_t *this, chunk_t *base_crl) |
407 | 0 | { |
408 | 0 | if (this->baseCrlNumber.len) |
409 | 0 | { |
410 | 0 | if (base_crl) |
411 | 0 | { |
412 | 0 | *base_crl = chunk_skip_zero(this->baseCrlNumber); |
413 | 0 | } |
414 | 0 | return TRUE; |
415 | 0 | } |
416 | 0 | return FALSE; |
417 | 0 | } |
418 | | |
419 | | METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*, |
420 | | private_x509_crl_t *this) |
421 | 0 | { |
422 | 0 | return this->crl_uris->create_enumerator(this->crl_uris); |
423 | 0 | } |
424 | | |
425 | | METHOD(crl_t, create_enumerator, enumerator_t*, |
426 | | private_x509_crl_t *this) |
427 | 0 | { |
428 | 0 | return enumerator_create_filter( |
429 | 0 | this->revoked->create_enumerator(this->revoked), |
430 | 0 | filter, NULL, NULL); |
431 | 0 | } |
432 | | |
433 | | METHOD(certificate_t, get_type, certificate_type_t, |
434 | | private_x509_crl_t *this) |
435 | 0 | { |
436 | 0 | return CERT_X509_CRL; |
437 | 0 | } |
438 | | |
439 | | METHOD(certificate_t, get_issuer, identification_t*, |
440 | | private_x509_crl_t *this) |
441 | 0 | { |
442 | 0 | return this->issuer; |
443 | 0 | } |
444 | | |
445 | | METHOD(certificate_t, has_issuer, id_match_t, |
446 | | private_x509_crl_t *this, identification_t *issuer) |
447 | 0 | { |
448 | 0 | if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr && |
449 | 0 | chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer))) |
450 | 0 | { |
451 | 0 | return ID_MATCH_PERFECT; |
452 | 0 | } |
453 | 0 | return this->issuer->matches(this->issuer, issuer); |
454 | 0 | } |
455 | | |
456 | | METHOD(certificate_t, issued_by, bool, |
457 | | private_x509_crl_t *this, certificate_t *issuer, |
458 | | signature_params_t **scheme) |
459 | 0 | { |
460 | 0 | public_key_t *key; |
461 | 0 | bool valid; |
462 | 0 | x509_t *x509 = (x509_t*)issuer; |
463 | 0 | chunk_t keyid = chunk_empty; |
464 | | |
465 | | /* check if issuer is an X.509 certificate with cRLSign keyUsage bit set */ |
466 | 0 | if (issuer->get_type(issuer) != CERT_X509) |
467 | 0 | { |
468 | 0 | return FALSE; |
469 | 0 | } |
470 | 0 | if (!(x509->get_flags(x509) & X509_CRL_SIGN)) |
471 | 0 | { |
472 | 0 | return FALSE; |
473 | 0 | } |
474 | | |
475 | | /* compare keyIdentifiers if available, otherwise use DNs */ |
476 | 0 | if (this->authKeyIdentifier.ptr) |
477 | 0 | { |
478 | 0 | keyid = x509->get_subjectKeyIdentifier(x509); |
479 | 0 | if (keyid.len && !chunk_equals(keyid, this->authKeyIdentifier)) |
480 | 0 | { |
481 | 0 | return FALSE; |
482 | 0 | } |
483 | 0 | } |
484 | 0 | if (!keyid.len) |
485 | 0 | { |
486 | 0 | if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) |
487 | 0 | { |
488 | 0 | return FALSE; |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | 0 | key = issuer->get_public_key(issuer); |
493 | 0 | if (!key) |
494 | 0 | { |
495 | 0 | return FALSE; |
496 | 0 | } |
497 | 0 | valid = key->verify(key, this->scheme->scheme, this->scheme->params, |
498 | 0 | this->tbsCertList, this->signature); |
499 | 0 | key->destroy(key); |
500 | 0 | if (valid && scheme) |
501 | 0 | { |
502 | 0 | *scheme = signature_params_clone(this->scheme); |
503 | 0 | } |
504 | 0 | return valid; |
505 | 0 | } |
506 | | |
507 | | METHOD(certificate_t, get_public_key, public_key_t*, |
508 | | private_x509_crl_t *this) |
509 | 0 | { |
510 | 0 | return NULL; |
511 | 0 | } |
512 | | |
513 | | METHOD(certificate_t, get_ref, certificate_t*, |
514 | | private_x509_crl_t *this) |
515 | 0 | { |
516 | 0 | ref_get(&this->ref); |
517 | 0 | return &this->public.crl.certificate; |
518 | 0 | } |
519 | | |
520 | | METHOD(certificate_t, get_validity, bool, |
521 | | private_x509_crl_t *this, time_t *when, |
522 | | time_t *not_before, time_t *not_after) |
523 | 0 | { |
524 | 0 | time_t t = when ? *when : time(NULL); |
525 | |
|
526 | 0 | if (not_before) |
527 | 0 | { |
528 | 0 | *not_before = this->thisUpdate; |
529 | 0 | } |
530 | 0 | if (not_after) |
531 | 0 | { |
532 | 0 | *not_after = this->nextUpdate; |
533 | 0 | } |
534 | 0 | return (t >= this->thisUpdate && t <= this->nextUpdate); |
535 | 0 | } |
536 | | |
537 | | METHOD(certificate_t, get_encoding, bool, |
538 | | private_x509_crl_t *this, cred_encoding_type_t type, chunk_t *encoding) |
539 | 0 | { |
540 | 0 | if (type == CERT_ASN1_DER) |
541 | 0 | { |
542 | 0 | *encoding = chunk_clone(this->encoding); |
543 | 0 | return TRUE; |
544 | 0 | } |
545 | 0 | return lib->encoding->encode(lib->encoding, type, NULL, encoding, |
546 | 0 | CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END); |
547 | 0 | } |
548 | | |
549 | | METHOD(certificate_t, equals, bool, |
550 | | private_x509_crl_t *this, certificate_t *other) |
551 | 0 | { |
552 | 0 | chunk_t encoding; |
553 | 0 | bool equal; |
554 | |
|
555 | 0 | if ((certificate_t*)this == other) |
556 | 0 | { |
557 | 0 | return TRUE; |
558 | 0 | } |
559 | 0 | if (other->equals == (void*)equals) |
560 | 0 | { /* skip allocation if we have the same implementation */ |
561 | 0 | return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding); |
562 | 0 | } |
563 | 0 | if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) |
564 | 0 | { |
565 | 0 | return FALSE; |
566 | 0 | } |
567 | 0 | equal = chunk_equals(this->encoding, encoding); |
568 | 0 | free(encoding.ptr); |
569 | 0 | return equal; |
570 | 0 | } |
571 | | |
572 | | /** |
573 | | * Destroy a revoked_t entry |
574 | | */ |
575 | | static void revoked_destroy(crl_revoked_t *revoked) |
576 | 22.8k | { |
577 | 22.8k | free(revoked->serial.ptr); |
578 | 22.8k | free(revoked); |
579 | 22.8k | } |
580 | | |
581 | | METHOD(certificate_t, destroy, void, |
582 | | private_x509_crl_t *this) |
583 | 6.66k | { |
584 | 6.66k | if (ref_put(&this->ref)) |
585 | 6.66k | { |
586 | 6.66k | this->revoked->destroy_function(this->revoked, (void*)revoked_destroy); |
587 | 6.66k | this->crl_uris->destroy_function(this->crl_uris, |
588 | 6.66k | (void*)x509_cdp_destroy); |
589 | 6.66k | signature_params_destroy(this->scheme); |
590 | 6.66k | DESTROY_IF(this->issuer); |
591 | 6.66k | free(this->authKeyIdentifier.ptr); |
592 | 6.66k | free(this->encoding.ptr); |
593 | 6.66k | free(this->critical_extension_oid.ptr); |
594 | 6.66k | if (this->generated) |
595 | 4.91k | { |
596 | 4.91k | free(this->crlNumber.ptr); |
597 | 4.91k | free(this->baseCrlNumber.ptr); |
598 | 4.91k | free(this->signature.ptr); |
599 | 4.91k | free(this->tbsCertList.ptr); |
600 | 4.91k | } |
601 | 6.66k | free(this); |
602 | 6.66k | } |
603 | 6.66k | } |
604 | | |
605 | | /** |
606 | | * create an empty but initialized X.509 crl |
607 | | */ |
608 | | static private_x509_crl_t* create_empty(void) |
609 | 6.66k | { |
610 | 6.66k | private_x509_crl_t *this; |
611 | | |
612 | 6.66k | INIT(this, |
613 | 6.66k | .public = { |
614 | 6.66k | .crl = { |
615 | 6.66k | .certificate = { |
616 | 6.66k | .get_type = _get_type, |
617 | 6.66k | .get_subject = _get_issuer, |
618 | 6.66k | .get_issuer = _get_issuer, |
619 | 6.66k | .has_subject = _has_issuer, |
620 | 6.66k | .has_issuer = _has_issuer, |
621 | 6.66k | .issued_by = _issued_by, |
622 | 6.66k | .get_public_key = _get_public_key, |
623 | 6.66k | .get_validity = _get_validity, |
624 | 6.66k | .get_encoding = _get_encoding, |
625 | 6.66k | .equals = _equals, |
626 | 6.66k | .get_ref = _get_ref, |
627 | 6.66k | .destroy = _destroy, |
628 | 6.66k | }, |
629 | 6.66k | .get_serial = _get_serial, |
630 | 6.66k | .get_authKeyIdentifier = _get_authKeyIdentifier, |
631 | 6.66k | .is_delta_crl = _is_delta_crl, |
632 | 6.66k | .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator, |
633 | 6.66k | .create_enumerator = _create_enumerator, |
634 | 6.66k | }, |
635 | 6.66k | }, |
636 | 6.66k | .revoked = linked_list_create(), |
637 | 6.66k | .crl_uris = linked_list_create(), |
638 | 6.66k | .ref = 1, |
639 | 6.66k | ); |
640 | 6.66k | return this; |
641 | 6.66k | } |
642 | | |
643 | | /** |
644 | | * See header. |
645 | | */ |
646 | | x509_crl_t *x509_crl_load(certificate_type_t type, va_list args) |
647 | 4.91k | { |
648 | 4.91k | chunk_t blob = chunk_empty; |
649 | | |
650 | 4.91k | while (TRUE) |
651 | 6.66k | { |
652 | 6.66k | switch (va_arg(args, builder_part_t)) |
653 | 6.66k | { |
654 | 1.75k | case BUILD_BLOB_ASN1_DER: |
655 | 1.75k | blob = va_arg(args, chunk_t); |
656 | 1.75k | continue; |
657 | 1.75k | case BUILD_END: |
658 | 1.75k | break; |
659 | 3.15k | default: |
660 | 3.15k | return NULL; |
661 | 6.66k | } |
662 | 1.75k | break; |
663 | 6.66k | } |
664 | 1.75k | if (blob.ptr) |
665 | 1.75k | { |
666 | 1.75k | private_x509_crl_t *crl = create_empty(); |
667 | | |
668 | 1.75k | crl->encoding = chunk_clone(blob); |
669 | 1.75k | if (parse(crl)) |
670 | 26 | { |
671 | 26 | return &crl->public; |
672 | 26 | } |
673 | 1.72k | destroy(crl); |
674 | 1.72k | } |
675 | 1.72k | return NULL; |
676 | 1.75k | }; |
677 | | |
678 | | /** |
679 | | * Read certificate status from enumerator, copy to crl |
680 | | */ |
681 | | static void read_revoked(private_x509_crl_t *crl, enumerator_t *enumerator) |
682 | 0 | { |
683 | 0 | crl_revoked_t *revoked; |
684 | 0 | chunk_t serial; |
685 | 0 | time_t date; |
686 | 0 | crl_reason_t reason; |
687 | |
|
688 | 0 | while (enumerator->enumerate(enumerator, &serial, &date, &reason)) |
689 | 0 | { |
690 | 0 | INIT(revoked, |
691 | 0 | .serial = chunk_clone(serial), |
692 | 0 | .date = date, |
693 | 0 | .reason = reason, |
694 | 0 | ); |
695 | 0 | crl->revoked->insert_last(crl->revoked, revoked); |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | | /** |
700 | | * Generate CRL encoding, sign CRL |
701 | | */ |
702 | | static bool generate(private_x509_crl_t *this, certificate_t *cert, |
703 | | private_key_t *key, hash_algorithm_t digest_alg) |
704 | 0 | { |
705 | 0 | chunk_t extensions = chunk_empty, certList = chunk_empty, serial; |
706 | 0 | chunk_t crlDistributionPoints = chunk_empty, baseCrlNumber = chunk_empty; |
707 | 0 | chunk_t sig_scheme = chunk_empty, criticalExtension = chunk_empty; |
708 | 0 | enumerator_t *enumerator; |
709 | 0 | crl_reason_t reason; |
710 | 0 | time_t date; |
711 | 0 | x509_t *x509; |
712 | |
|
713 | 0 | x509 = (x509_t*)cert; |
714 | |
|
715 | 0 | this->issuer = cert->get_subject(cert); |
716 | 0 | this->issuer = this->issuer->clone(this->issuer); |
717 | |
|
718 | 0 | this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509)); |
719 | | |
720 | | /* select signature scheme, if not already specified */ |
721 | 0 | if (!this->scheme) |
722 | 0 | { |
723 | 0 | INIT(this->scheme, |
724 | 0 | .scheme = signature_scheme_from_oid( |
725 | 0 | hasher_signature_algorithm_to_oid(digest_alg, |
726 | 0 | key->get_type(key))), |
727 | 0 | ); |
728 | 0 | } |
729 | 0 | if (this->scheme->scheme == SIGN_UNKNOWN) |
730 | 0 | { |
731 | 0 | return FALSE; |
732 | 0 | } |
733 | 0 | if (!signature_params_build(this->scheme, &sig_scheme)) |
734 | 0 | { |
735 | 0 | return FALSE; |
736 | 0 | } |
737 | | |
738 | 0 | enumerator = create_enumerator(this); |
739 | 0 | while (enumerator->enumerate(enumerator, &serial, &date, &reason)) |
740 | 0 | { |
741 | 0 | chunk_t revoked, entry_ext = chunk_empty; |
742 | |
|
743 | 0 | if (reason != CRL_REASON_UNSPECIFIED) |
744 | 0 | { |
745 | 0 | entry_ext = asn1_wrap(ASN1_SEQUENCE, "m", |
746 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
747 | 0 | asn1_build_known_oid(OID_CRL_REASON_CODE), |
748 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
749 | 0 | asn1_wrap(ASN1_ENUMERATED, "c", |
750 | 0 | chunk_from_chars(reason))))); |
751 | 0 | } |
752 | 0 | revoked = asn1_wrap(ASN1_SEQUENCE, "mmm", |
753 | 0 | asn1_integer("c", serial), |
754 | 0 | asn1_from_time(&date, ASN1_UTCTIME), |
755 | 0 | entry_ext); |
756 | 0 | certList = chunk_cat("mm", certList, revoked); |
757 | 0 | } |
758 | 0 | enumerator->destroy(enumerator); |
759 | |
|
760 | 0 | crlDistributionPoints = x509_build_crlDistributionPoints(this->crl_uris, |
761 | 0 | OID_FRESHEST_CRL); |
762 | |
|
763 | 0 | if (this->baseCrlNumber.len) |
764 | 0 | { |
765 | 0 | baseCrlNumber = asn1_wrap(ASN1_SEQUENCE, "mmm", |
766 | 0 | asn1_build_known_oid(OID_DELTA_CRL_INDICATOR), |
767 | 0 | asn1_wrap(ASN1_BOOLEAN, "c", |
768 | 0 | chunk_from_chars(0xFF)), |
769 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
770 | 0 | asn1_integer("c", this->baseCrlNumber))); |
771 | 0 | } |
772 | |
|
773 | 0 | if (this->critical_extension_oid.len > 0) |
774 | 0 | { |
775 | 0 | criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm", |
776 | 0 | asn1_simple_object(ASN1_OID, this->critical_extension_oid), |
777 | 0 | asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)), |
778 | 0 | asn1_simple_object(ASN1_OCTET_STRING, chunk_empty)); |
779 | 0 | } |
780 | |
|
781 | 0 | extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m", |
782 | 0 | asn1_wrap(ASN1_SEQUENCE, "mmmmm", |
783 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
784 | 0 | asn1_build_known_oid(OID_AUTHORITY_KEY_ID), |
785 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
786 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", |
787 | 0 | asn1_wrap(ASN1_CONTEXT_S_0, "c", |
788 | 0 | this->authKeyIdentifier)))), |
789 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
790 | 0 | asn1_build_known_oid(OID_CRL_NUMBER), |
791 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
792 | 0 | asn1_integer("c", this->crlNumber))), |
793 | 0 | crlDistributionPoints, baseCrlNumber, |
794 | 0 | criticalExtension)); |
795 | |
|
796 | 0 | this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cccmmmm", |
797 | 0 | ASN1_INTEGER_1, |
798 | 0 | sig_scheme, |
799 | 0 | this->issuer->get_encoding(this->issuer), |
800 | 0 | asn1_from_time(&this->thisUpdate, ASN1_UTCTIME), |
801 | 0 | asn1_from_time(&this->nextUpdate, ASN1_UTCTIME), |
802 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", certList), |
803 | 0 | extensions); |
804 | |
|
805 | 0 | if (!key->sign(key, this->scheme->scheme, this->scheme->params, |
806 | 0 | this->tbsCertList, &this->signature)) |
807 | 0 | { |
808 | 0 | chunk_free(&sig_scheme); |
809 | 0 | return FALSE; |
810 | 0 | } |
811 | 0 | this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", |
812 | 0 | this->tbsCertList, |
813 | 0 | sig_scheme, |
814 | 0 | asn1_bitstring("c", this->signature)); |
815 | 0 | return TRUE; |
816 | 0 | } |
817 | | |
818 | | /** |
819 | | * See header. |
820 | | */ |
821 | | x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args) |
822 | 4.91k | { |
823 | 4.91k | hash_algorithm_t digest_alg = HASH_SHA256; |
824 | 4.91k | private_x509_crl_t *crl; |
825 | 4.91k | certificate_t *cert = NULL; |
826 | 4.91k | private_key_t *key = NULL; |
827 | | |
828 | 4.91k | crl = create_empty(); |
829 | 4.91k | crl->generated = TRUE; |
830 | 4.91k | while (TRUE) |
831 | 4.91k | { |
832 | 4.91k | builder_part_t part = va_arg(args, builder_part_t); |
833 | | |
834 | 4.91k | switch (part) |
835 | 4.91k | { |
836 | 0 | case BUILD_SIGNING_KEY: |
837 | 0 | key = va_arg(args, private_key_t*); |
838 | 0 | continue; |
839 | 0 | case BUILD_SIGNING_CERT: |
840 | 0 | cert = va_arg(args, certificate_t*); |
841 | 0 | continue; |
842 | 0 | case BUILD_NOT_BEFORE_TIME: |
843 | 0 | crl->thisUpdate = va_arg(args, time_t); |
844 | 0 | continue; |
845 | 0 | case BUILD_NOT_AFTER_TIME: |
846 | 0 | crl->nextUpdate = va_arg(args, time_t); |
847 | 0 | continue; |
848 | 0 | case BUILD_SERIAL: |
849 | 0 | crl->crlNumber = va_arg(args, chunk_t); |
850 | 0 | crl->crlNumber = chunk_clone(crl->crlNumber); |
851 | 0 | continue; |
852 | 0 | case BUILD_SIGNATURE_SCHEME: |
853 | 0 | crl->scheme = va_arg(args, signature_params_t*); |
854 | 0 | crl->scheme = signature_params_clone(crl->scheme); |
855 | 0 | continue; |
856 | 0 | case BUILD_DIGEST_ALG: |
857 | 0 | digest_alg = va_arg(args, int); |
858 | 0 | continue; |
859 | 0 | case BUILD_REVOKED_ENUMERATOR: |
860 | 0 | read_revoked(crl, va_arg(args, enumerator_t*)); |
861 | 0 | continue; |
862 | 0 | case BUILD_BASE_CRL: |
863 | 0 | crl->baseCrlNumber = va_arg(args, chunk_t); |
864 | 0 | crl->baseCrlNumber = chunk_clone(crl->baseCrlNumber); |
865 | 0 | continue; |
866 | 0 | case BUILD_CRL_DISTRIBUTION_POINTS: |
867 | 0 | { |
868 | 0 | enumerator_t *enumerator; |
869 | 0 | linked_list_t *list; |
870 | 0 | x509_cdp_t *in, *cdp; |
871 | |
|
872 | 0 | list = va_arg(args, linked_list_t*); |
873 | 0 | enumerator = list->create_enumerator(list); |
874 | 0 | while (enumerator->enumerate(enumerator, &in)) |
875 | 0 | { |
876 | 0 | INIT(cdp, |
877 | 0 | .uri = strdup(in->uri), |
878 | 0 | .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL, |
879 | 0 | ); |
880 | 0 | crl->crl_uris->insert_last(crl->crl_uris, cdp); |
881 | 0 | } |
882 | 0 | enumerator->destroy(enumerator); |
883 | 0 | continue; |
884 | 0 | } |
885 | 0 | case BUILD_CRITICAL_EXTENSION: |
886 | 0 | crl->critical_extension_oid = chunk_clone(va_arg(args, chunk_t)); |
887 | 0 | continue; |
888 | 0 | case BUILD_END: |
889 | 0 | break; |
890 | 4.91k | default: |
891 | 4.91k | destroy(crl); |
892 | 4.91k | return NULL; |
893 | 4.91k | } |
894 | 0 | break; |
895 | 4.91k | } |
896 | | |
897 | 0 | if (key && cert && cert->get_type(cert) == CERT_X509 && |
898 | 0 | generate(crl, cert, key, digest_alg)) |
899 | 0 | { |
900 | 0 | return &crl->public; |
901 | 0 | } |
902 | 0 | destroy(crl); |
903 | 0 | return NULL; |
904 | 0 | } |