fixed compilation warnings and errors when not using curl
[strongswan.git] / src / libstrongswan / crypto / ca.c
1 /**
2 * @file ca.c
3 *
4 * @brief Implementation of ca_info_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 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 #include <pthread.h>
28
29 #include "x509.h"
30 #include "crl.h"
31 #include "ca.h"
32 #include "certinfo.h"
33 #include "ocsp.h"
34
35 #include <library.h>
36 #include <debug.h>
37 #include <utils/linked_list.h>
38 #include <utils/identification.h>
39
40 typedef struct private_ca_info_t private_ca_info_t;
41
42 /**
43 * Private data of a ca_info_t object.
44 */
45 struct private_ca_info_t {
46 /**
47 * Public interface for this ca info record
48 */
49 ca_info_t public;
50
51 /**
52 * Name of the ca info record
53 */
54 char *name;
55
56 /**
57 * Time when ca info record was installed
58 */
59 time_t installed;
60
61 /**
62 * Distinguished Name of the CA
63 */
64 x509_t *cacert;
65
66 /**
67 * List of crl URIs
68 */
69 linked_list_t *crluris;
70
71 /**
72 * List of ocsp URIs
73 */
74 linked_list_t *ocspuris;
75
76 /**
77 * CRL issued by this ca
78 */
79 crl_t *crl;
80
81 /**
82 * List of certificate info records
83 */
84 linked_list_t *certinfos;
85
86 /**
87 * mutex controls access to the elements:
88 * name, crluris, ocspuris, crl, and certinfos
89 */
90 pthread_mutex_t mutex;
91 };
92
93 /**
94 * Implements ca_info_t.equals
95 */
96 static bool equals(const private_ca_info_t *this, const private_ca_info_t *that)
97 {
98 return chunk_equals(this->cacert->get_keyid(this->cacert),
99 that->cacert->get_keyid(that->cacert));
100 }
101
102 /**
103 * Implements ca_info_t.equals_name_release_info
104 */
105 static bool equals_name_release_info(private_ca_info_t *this, const char *name)
106 {
107 bool found;
108
109 pthread_mutex_lock(&(this->mutex));
110 found = this->name != NULL && streq(this->name, name);
111
112 if (found)
113 {
114 this->crluris->destroy_offset(this->crluris,
115 offsetof(identification_t, destroy));
116 this->crluris = linked_list_create();
117
118 this->ocspuris->destroy_offset(this->ocspuris,
119 offsetof(identification_t, destroy));
120 this->ocspuris = linked_list_create();
121
122 free(this->name);
123 this->name = NULL;
124 }
125
126 pthread_mutex_unlock(&(this->mutex));
127 return found;
128 }
129
130 /**
131 * Implements ca_info_t.is_crl_issuer
132 */
133 static bool is_cert_issuer(private_ca_info_t *this, const x509_t *cert)
134 {
135 return cert->is_issuer(cert, this->cacert);
136 }
137
138 /**
139 * Implements ca_info_t.is_crl_issuer
140 */
141 static bool is_crl_issuer(private_ca_info_t *this, const crl_t *crl)
142 {
143 return crl->is_issuer(crl, this->cacert);
144 }
145
146 /**
147 * Implements ca_info_t.has_crl
148 */
149 static bool has_crl(private_ca_info_t *this)
150 {
151 bool found;
152
153 pthread_mutex_lock(&(this->mutex));
154 found = this->crl != NULL;
155 pthread_mutex_unlock(&(this->mutex));
156
157 return found;
158 }
159
160 /**
161 * Implements ca_info_t.add_crl
162 */
163 static void add_crl(private_ca_info_t *this, crl_t *crl)
164 {
165 pthread_mutex_lock(&(this->mutex));
166
167 if (this->crl)
168 {
169 if (crl->is_newer(crl, this->crl))
170 {
171 this->crl->destroy(this->crl);
172 this->crl = crl;
173 DBG1(" thisUpdate is newer - existing crl replaced");
174 }
175 else
176 {
177 crl->destroy(crl);
178 DBG1(" thisUpdate is not newer - existing crl retained");
179 }
180 }
181 else
182 {
183 this->crl = crl;
184 DBG2(" crl added");
185 }
186
187 pthread_mutex_unlock(&(this->mutex));
188 }
189
190 /**
191 * Implements ca_info_t.list_crl
192 */
193 static void list_crl(private_ca_info_t *this, FILE *out, bool utc)
194 {
195 pthread_mutex_lock(&(this->mutex));
196
197 fprintf(out, "%#U\n", this->crl, utc);
198
199 pthread_mutex_unlock(&(this->mutex));
200 }
201
202 /**
203 * Implements ca_info_t.list_certinfos
204 */
205 static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc)
206 {
207 pthread_mutex_lock(&(this->mutex));
208
209 /* fprintf(out, "%#X\n", this->certifnos, utc); */
210
211 pthread_mutex_unlock(&(this->mutex));
212 }
213
214 /**
215 * Find an exact copy of an identification in a linked list
216 */
217 static identification_t* find_identification(linked_list_t *list, identification_t *id)
218 {
219 identification_t *found_id = NULL, *current_id;
220
221 iterator_t *iterator = list->create_iterator(list, TRUE);
222
223 while (iterator->iterate(iterator, (void**)&current_id))
224 {
225 if (id->equals(id, current_id))
226 {
227 found_id = current_id;
228 break;
229 }
230 }
231 iterator->destroy(iterator);
232
233 return found_id;
234 }
235
236 /**
237 * Add a unique identification to a linked list
238 */
239 static identification_t *add_identification(linked_list_t *list, identification_t *id)
240 {
241 identification_t *found_id = find_identification(list, id);
242
243 if (found_id)
244 {
245 id->destroy(id);
246 return found_id;
247 }
248 else
249 {
250 list->insert_last(list, (void*)id);
251 return id;
252 }
253 }
254
255 /**
256 * Implements ca_info_t.add_crluri
257 */
258 static void add_crluri(private_ca_info_t *this, chunk_t uri)
259 {
260 if (uri.len < 6 ||
261 (strncasecmp(uri.ptr, "http", 4) != 0 &&
262 strncasecmp(uri.ptr, "ldap", 4) != 0 &&
263 strncasecmp(uri.ptr, "file", 4) != 0 &&
264 strncasecmp(uri.ptr, "ftp", 3) != 0))
265 {
266 DBG1(" invalid crl uri '%#B'", uri);
267 return;
268 }
269 else
270 {
271 identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
272
273 pthread_mutex_lock(&(this->mutex));
274 add_identification(this->crluris, crluri);
275 pthread_mutex_unlock(&(this->mutex));
276 }
277 }
278
279 /**
280 * Implements ca_info_t.add_ocspuri
281 */
282 static void add_ocspuri(private_ca_info_t *this, chunk_t uri)
283 {
284 if (uri.len < 7 || strncasecmp(uri.ptr, "http", 4) != 0)
285 {
286 DBG1(" invalid ocsp uri '%.*s'", uri.len, uri.ptr);
287 return;
288 }
289 else
290 {
291 identification_t *ocspuri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
292
293 pthread_mutex_lock(&(this->mutex));
294 add_identification(this->ocspuris, ocspuri);
295 pthread_mutex_unlock(&(this->mutex));
296 }
297 }
298
299 /**
300 * Implements ca_info_t.add_info.
301 */
302 void add_info (private_ca_info_t *this, const private_ca_info_t *that)
303 {
304 pthread_mutex_lock(&(this->mutex));
305
306 if (this->name == NULL && that->name != NULL)
307 {
308 this->name = strdup(that->name);
309 }
310
311 pthread_mutex_unlock(&(this->mutex));
312
313 {
314 identification_t *uri;
315
316 iterator_t *iterator = that->crluris->create_iterator(that->crluris, TRUE);
317
318 while (iterator->iterate(iterator, (void**)&uri))
319 {
320 add_crluri(this, uri->get_encoding(uri));
321 }
322 iterator->destroy(iterator);
323 }
324
325 {
326 identification_t *uri;
327
328 iterator_t *iterator = that->ocspuris->create_iterator(that->ocspuris, TRUE);
329
330 while (iterator->iterate(iterator, (void**)&uri))
331 {
332 add_ocspuri(this, uri->get_encoding(uri));
333 }
334 iterator->destroy(iterator);
335 }
336 }
337
338 /**
339 * Implements ca_info_t.get_certificate.
340 */
341 static x509_t* get_certificate(private_ca_info_t* this)
342 {
343 return this->cacert;
344 }
345
346 /**
347 * Implements ca_info_t.verify_by_crl.
348 */
349 static cert_status_t verify_by_crl(private_ca_info_t* this, const x509_t *cert,
350 certinfo_t *certinfo)
351 {
352 bool valid_signature;
353 rsa_public_key_t *issuer_public_key;
354
355
356 pthread_mutex_lock(&(this->mutex));
357
358 if (this->crl == NULL)
359 {
360 DBG1("crl not found");
361 goto err;
362 }
363 DBG2("crl found");
364
365 issuer_public_key = this->cacert->get_public_key(this->cacert);
366 valid_signature = this->crl->verify(this->crl, issuer_public_key);
367
368 if (!valid_signature)
369 {
370 DBG1("crl signature is invalid");
371 goto err;
372 }
373 DBG2("crl signature is valid");
374
375 this->crl->get_status(this->crl, certinfo);
376
377 err:
378 pthread_mutex_unlock(&(this->mutex));
379 return certinfo->get_status(certinfo);
380 }
381
382 /**
383 * Implements ca_info_t.verify_by_ocsp.
384 */
385 static cert_status_t verify_by_ocsp(private_ca_info_t* this,
386 const x509_t *cert,
387 certinfo_t *certinfo,
388 credential_store_t *credentials)
389 {
390 bool found = FALSE;
391
392 pthread_mutex_lock(&(this->mutex));
393
394 /* do we support OCSP at all? */
395 if (this->ocspuris->get_count(this->ocspuris) == 0)
396 {
397 goto ret;
398 }
399
400 /* do we have a valid certinfo record for this serial number in our cache? */
401 {
402 iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
403 certinfo_t *current_certinfo;
404
405 while(iterator->iterate(iterator, (void**)&current_certinfo))
406 {
407 if (certinfo->equals_serialNumber(certinfo, current_certinfo))
408 {
409 found = TRUE;
410 DBG2("ocsp status found");
411 break;
412 }
413 }
414 iterator->destroy(iterator);
415 }
416
417 if (!found)
418 {
419 ocsp_t *ocsp;
420
421 DBG2("ocsp status is not in cache");
422
423 ocsp = ocsp_create(this->cacert, this->ocspuris);
424 ocsp->fetch(ocsp, certinfo, credentials);
425 ocsp->destroy(ocsp);
426 }
427
428 ret:
429 pthread_mutex_unlock(&(this->mutex));
430 return certinfo->get_status(certinfo);
431 }
432
433 /**
434 * Implements ca_info_t.destroy
435 */
436 static void destroy(private_ca_info_t *this)
437 {
438 this->crluris->destroy_offset(this->crluris,
439 offsetof(identification_t, destroy));
440 this->ocspuris->destroy_offset(this->ocspuris,
441 offsetof(identification_t, destroy));
442 this->certinfos->destroy_offset(this->certinfos,
443 offsetof(certinfo_t, destroy));
444 DESTROY_IF(this->crl);
445 free(this->name);
446 free(this);
447 }
448
449 /**
450 * output handler in printf()
451 */
452 static int print(FILE *stream, const struct printf_info *info,
453 const void *const *args)
454 {
455 private_ca_info_t *this = *((private_ca_info_t**)(args[0]));
456 bool utc = TRUE;
457 int written = 0;
458 const x509_t *cacert;
459
460 if (info->alt)
461 {
462 utc = *((bool*)args[1]);
463 }
464 if (this == NULL)
465 {
466 return fprintf(stream, "(null)");
467 }
468
469 pthread_mutex_lock(&(this->mutex));
470 written += fprintf(stream, "%#T", &this->installed, utc);
471
472 if (this->name)
473 {
474 written += fprintf(stream, ", \"%s\"\n", this->name);
475 }
476 else
477 {
478 written += fprintf(stream, "\n");
479 }
480
481 cacert = this->cacert;
482 written += fprintf(stream, " authname: '%D'\n", cacert->get_subject(cacert));
483
484 {
485 chunk_t keyid = cacert->get_keyid(cacert);
486
487 written += fprintf(stream, " keyid: %#B\n", &keyid);
488 }
489 {
490 identification_t *crluri;
491 iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE);
492 bool first = TRUE;
493
494 while (iterator->iterate(iterator, (void**)&crluri))
495 {
496 written += fprintf(stream, " %s '%D'\n",
497 first? "crluris:":" ", crluri);
498 first = FALSE;
499 }
500 iterator->destroy(iterator);
501 }
502 {
503 identification_t *ocspuri;
504 iterator_t *iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE);
505 bool first = TRUE;
506
507 while (iterator->iterate(iterator, (void**)&ocspuri))
508 {
509 written += fprintf(stream, " %s '%D'\n",
510 first? "ocspuris:":" ", ocspuri);
511 first = FALSE;
512 }
513 iterator->destroy(iterator);
514 }
515 pthread_mutex_unlock(&(this->mutex));
516 return written;
517 }
518
519 /**
520 * register printf() handlers
521 */
522 static void __attribute__ ((constructor))print_register()
523 {
524 register_printf_function(PRINTF_CAINFO, print, arginfo_ptr_alt_ptr_int);
525 }
526
527 /*
528 * Described in header.
529 */
530 ca_info_t *ca_info_create(const char *name, x509_t *cacert)
531 {
532 private_ca_info_t *this = malloc_thing(private_ca_info_t);
533
534 /* initialize */
535 this->installed = time(NULL);
536 this->name = (name == NULL)? NULL:strdup(name);
537 this->cacert = cacert;
538 this->crluris = linked_list_create();
539 this->ocspuris = linked_list_create();
540 this->certinfos = linked_list_create();
541 this->crl = NULL;
542
543 /* initialize the mutex */
544 pthread_mutex_init(&(this->mutex), NULL);
545
546 /* public functions */
547 this->public.equals = (bool (*) (const ca_info_t*,const ca_info_t*))equals;
548 this->public.equals_name_release_info = (bool (*) (ca_info_t*,const char*))equals_name_release_info;
549 this->public.is_cert_issuer = (bool (*) (ca_info_t*,const x509_t*))is_cert_issuer;
550 this->public.is_crl_issuer = (bool (*) (ca_info_t*,const crl_t*))is_crl_issuer;
551 this->public.add_info = (void (*) (ca_info_t*,const ca_info_t*))add_info;
552 this->public.add_crl = (void (*) (ca_info_t*,crl_t*))add_crl;
553 this->public.has_crl = (bool (*) (ca_info_t*))has_crl;
554 this->public.list_crl = (void (*) (ca_info_t*,FILE*,bool))list_crl;
555 this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri;
556 this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri;
557 this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate;
558 this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,const x509_t*,certinfo_t*))verify_by_crl;
559 this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,const x509_t*,certinfo_t*,credential_store_t*))verify_by_ocsp;
560 this->public.destroy = (void (*) (ca_info_t*))destroy;
561
562 return &this->public;
563 }