6e7d338132e84003af6acded7ce1c6e4c88e4640
[strongswan.git] / src / charon / config / credentials / credential_store.c
1 /**
2 * @file credential_store.c
3 *
4 * @brief Implementation of credential_store_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
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 <dirent.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include "credential_store.h"
29
30 #include <utils/lexparser.h>
31 #include <utils/linked_list.h>
32 #include <utils/logger_manager.h>
33 #include <crypto/x509.h>
34 #include <crypto/crl.h>
35
36 #define PATH_BUF 256
37
38 typedef struct private_credential_store_t private_credential_store_t;
39
40 /**
41 * Private data of an credential_store_t object
42 */
43 struct private_credential_store_t {
44
45 /**
46 * Public part
47 */
48 credential_store_t public;
49
50 /**
51 * list of key_entry_t's with private keys
52 */
53 linked_list_t *private_keys;
54
55 /**
56 * list of X.509 certificates with public keys
57 */
58 linked_list_t *certs;
59
60 /**
61 * list of X.509 CA certificates with public keys
62 */
63 linked_list_t *ca_certs;
64
65 /**
66 * list of X.509 CRLs
67 */
68 linked_list_t *crls;
69
70 /**
71 * mutex controlling the access to the crls linked list
72 */
73 pthread_mutex_t crls_mutex;
74
75 /**
76 * enforce strict crl policy
77 */
78 bool strict;
79
80 /**
81 * Assigned logger
82 */
83 logger_t *logger;
84 };
85
86
87 /**
88 * Implementation of credential_store_t.get_shared_secret.
89 */
90 static status_t get_shared_secret(private_credential_store_t *this, identification_t *id, chunk_t *secret)
91 {
92 return FAILED;
93 }
94
95 /**
96 * Implementation of credential_store_t.get_rsa_public_key.
97 */
98 static rsa_public_key_t * get_rsa_public_key(private_credential_store_t *this, identification_t *id)
99 {
100 rsa_public_key_t *found = NULL;
101
102 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
103
104 while (iterator->has_next(iterator))
105 {
106 x509_t *cert;
107
108 iterator->current(iterator, (void**)&cert);
109
110 if (id->equals(id, cert->get_subject(cert)) || cert->equals_subjectAltName(cert, id))
111 {
112 found = cert->get_public_key(cert);
113 break;
114 }
115 }
116 iterator->destroy(iterator);
117 return found;
118 }
119
120 /**
121 * Implementation of credential_store_t.get_rsa_private_key.
122 */
123 static rsa_private_key_t* get_rsa_private_key(private_credential_store_t *this, rsa_public_key_t *pubkey)
124 {
125 rsa_private_key_t *found = NULL;
126 rsa_private_key_t *current;
127
128 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
129
130 while (iterator->has_next(iterator))
131 {
132 iterator->current(iterator, (void**)&current);
133
134 if (current->belongs_to(current, pubkey))
135 {
136 found = current->clone(current);
137 break;
138 }
139 }
140 iterator->destroy(iterator);
141 return found;
142 }
143
144 /**
145 * Implementation of credential_store_t.has_rsa_private_key.
146 */
147 static bool has_rsa_private_key(private_credential_store_t *this, rsa_public_key_t *pubkey)
148 {
149 bool found = FALSE;
150 rsa_private_key_t *current;
151
152 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
153
154 while (iterator->has_next(iterator))
155 {
156 iterator->current(iterator, (void**)&current);
157
158 if (current->belongs_to(current, pubkey))
159 {
160 found = TRUE;
161 break;
162 }
163 }
164 iterator->destroy(iterator);
165 return found;
166 }
167
168 /**
169 * Add a unique certificate to a linked list
170 */
171 static x509_t* add_certificate(linked_list_t *certs, x509_t *cert)
172 {
173 bool found = FALSE;
174
175 iterator_t *iterator = certs->create_iterator(certs, TRUE);
176
177 while (iterator->has_next(iterator))
178 {
179 x509_t *current_cert;
180
181 iterator->current(iterator, (void**)&current_cert);
182 if (cert->equals(cert, current_cert))
183 {
184 found = TRUE;
185 cert->destroy(cert);
186 cert = current_cert;
187 break;
188 }
189 }
190 iterator->destroy(iterator);
191
192 if (!found)
193 {
194 certs->insert_last(certs, (void*)cert);
195 }
196 return cert;
197 }
198
199 /**
200 * Implements credential_store_t.add_end_certificate
201 */
202 static x509_t* add_end_certificate(private_credential_store_t *this, x509_t *cert)
203 {
204 return add_certificate(this->certs, cert);
205 }
206
207 /**
208 * Implements credential_store_t.add_ca_certificate
209 */
210 static x509_t* add_ca_certificate(private_credential_store_t *this, x509_t *cert)
211 {
212 return add_certificate(this->ca_certs, cert);
213 }
214
215 /**
216 * Implements credential_store_t.log_certificates
217 */
218 static void log_certificates(private_credential_store_t *this, logger_t *logger, bool utc)
219 {
220 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
221
222 if (iterator->get_count(iterator))
223 {
224 logger->log(logger, CONTROL, "");
225 logger->log(logger, CONTROL, "List of X.509 End Entity Certificates:");
226 logger->log(logger, CONTROL, "");
227 }
228
229 while (iterator->has_next(iterator))
230 {
231 x509_t *cert;
232 bool has_key;
233
234 iterator->current(iterator, (void**)&cert);
235 has_key = has_rsa_private_key(this, cert->get_public_key(cert));
236 cert->log_certificate(cert, logger, utc, has_key);
237 }
238 iterator->destroy(iterator);
239 }
240
241 /**
242 * Implements credential_store_t.log_ca_certificates
243 */
244 static void log_ca_certificates(private_credential_store_t *this, logger_t *logger, bool utc)
245 {
246 iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
247
248 if (iterator->get_count(iterator))
249 {
250 logger->log(logger, CONTROL, "");
251 logger->log(logger, CONTROL, "List of X.509 CA Certificates:");
252 logger->log(logger, CONTROL, "");
253 }
254
255 while (iterator->has_next(iterator))
256 {
257 x509_t *cert;
258
259 iterator->current(iterator, (void**)&cert);
260 cert->log_certificate(cert, logger, utc, FALSE);
261 }
262 iterator->destroy(iterator);
263 }
264
265 /**
266 * Implements credential_store_t.log_crls
267 */
268 static void log_crls(private_credential_store_t *this, logger_t *logger, bool utc)
269 {
270 iterator_t *iterator = this->crls->create_iterator(this->crls, TRUE);
271
272 pthread_mutex_lock(&(this->crls_mutex));
273 if (iterator->get_count(iterator))
274 {
275 logger->log(logger, CONTROL, "");
276 logger->log(logger, CONTROL, "List of X.509 CRLs:");
277 logger->log(logger, CONTROL, "");
278 }
279
280 while (iterator->has_next(iterator))
281 {
282 crl_t *crl;
283
284 iterator->current(iterator, (void**)&crl);
285 crl->log_crl(crl, logger, utc, this->strict);
286 }
287 pthread_mutex_unlock(&(this->crls_mutex));
288
289 iterator->destroy(iterator);
290 }
291
292 /**
293 * Implements credential_store_t.load_ca_certificates
294 */
295 static void load_ca_certificates(private_credential_store_t *this, const char *path)
296 {
297 struct dirent* entry;
298 struct stat stb;
299 DIR* dir;
300 x509_t *cert;
301
302 this->logger->log(this->logger, CONTROL, "loading ca certificates from '%s/'", path);
303
304 dir = opendir(path);
305 if (dir == NULL)
306 {
307 this->logger->log(this->logger, ERROR, "error opening ca certs directory %s'", path);
308 return;
309 }
310
311 while ((entry = readdir(dir)) != NULL)
312 {
313 char file[PATH_BUF];
314
315 snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
316
317 if (stat(file, &stb) == -1)
318 {
319 continue;
320 }
321 /* try to parse all regular files */
322 if (stb.st_mode & S_IFREG)
323 {
324 cert = x509_create_from_file(file, "ca certificate");
325 if (cert)
326 {
327 err_t ugh = cert->is_valid(cert, NULL);
328
329 if (ugh != NULL)
330 {
331 this->logger->log(this->logger, ERROR, "warning: ca certificate %s", ugh);
332 }
333 if (cert->is_ca(cert))
334 {
335 cert = add_certificate(this->ca_certs, cert);
336 }
337 else
338 {
339 this->logger->log(this->logger, ERROR,
340 " CA basic constraints flag not set, cert discarded");
341 cert->destroy(cert);
342 }
343 }
344 }
345 }
346 closedir(dir);
347 }
348
349 /**
350 * Add the latest crl to a linked list
351 */
352 static crl_t* add_crl(linked_list_t *crls, crl_t *crl, logger_t *logger)
353 {
354 bool found = FALSE;
355
356 iterator_t *iterator = crls->create_iterator(crls, TRUE);
357
358 while (iterator->has_next(iterator))
359 {
360 crl_t *current_crl;
361
362 iterator->current(iterator, (void**)&current_crl);
363 if (crl->equals_issuer(crl, current_crl))
364 {
365 found = TRUE;
366 if (crl->is_newer(crl, current_crl))
367 {
368 crl_t *old_crl = NULL;
369
370 iterator->replace(iterator, (void**)&old_crl, (void*)crl);
371 if (old_crl != NULL)
372 {
373 old_crl->destroy(old_crl);
374 }
375 logger->log(logger, CONTROL|LEVEL1, " thisUpdate is newer - existing crl replaced");
376 }
377 else
378 {
379 crl->destroy(crl);
380 crl = current_crl;
381 logger->log(logger, CONTROL|LEVEL1, " thisUpdate is not newer - existing crl retained");
382 }
383 break;
384 }
385 }
386 iterator->destroy(iterator);
387
388 if (!found)
389 {
390 crls->insert_last(crls, (void*)crl);
391 logger->log(logger, CONTROL|LEVEL1, " crl added");
392 }
393 return crl;
394 }
395
396 /**
397 * Implements credential_store_t.load_crls
398 */
399 static void load_crls(private_credential_store_t *this, const char *path)
400 {
401 struct dirent* entry;
402 struct stat stb;
403 DIR* dir;
404 crl_t *crl;
405
406 this->logger->log(this->logger, CONTROL, "loading crls from '%s/'", path);
407
408 dir = opendir(path);
409 if (dir == NULL)
410 {
411 this->logger->log(this->logger, ERROR, "error opening crl directory %s'", path);
412 return;
413 }
414
415 while ((entry = readdir(dir)) != NULL)
416 {
417 char file[PATH_BUF];
418
419 snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
420
421 if (stat(file, &stb) == -1)
422 {
423 continue;
424 }
425 /* try to parse all regular files */
426 if (stb.st_mode & S_IFREG)
427 {
428 crl = crl_create_from_file(file);
429 if (crl)
430 {
431 err_t ugh = crl->is_valid(crl, NULL, this->strict);
432
433 if (ugh != NULL)
434 {
435 this->logger->log(this->logger, ERROR, "warning: crl %s", ugh);
436 }
437 pthread_mutex_lock(&(this->crls_mutex));
438 crl = add_crl(this->crls, crl, this->logger);
439 pthread_mutex_unlock(&(this->crls_mutex));
440 }
441 }
442 }
443 closedir(dir);
444 }
445
446 /**
447 * Implements credential_store_t.load_private_keys
448 */
449 static void load_private_keys(private_credential_store_t *this, const char *secretsfile, const char *defaultpath)
450 {
451 FILE *fd = fopen(secretsfile, "r");
452
453 if (fd)
454 {
455 int bytes;
456 int line_nr = 0;
457 chunk_t chunk, src, line;
458
459 this->logger->log(this->logger, CONTROL, "loading secrets from \"%s\"", secretsfile);
460
461 fseek(fd, 0, SEEK_END);
462 chunk.len = ftell(fd);
463 rewind(fd);
464 chunk.ptr = malloc(chunk.len);
465 bytes = fread(chunk.ptr, 1, chunk.len, fd);
466 fclose(fd);
467
468 src = chunk;
469
470 while (fetchline(&src, &line))
471 {
472 chunk_t ids, token;
473
474 line_nr++;
475
476 if (!eat_whitespace(&line))
477 {
478 continue;
479 }
480 if (!extract_token(&ids, ':', &line))
481 {
482 this->logger->log(this->logger, ERROR, "line %d: missing ':' separator", line_nr);
483 goto error;
484 }
485 if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
486 {
487 this->logger->log(this->logger, ERROR, "line %d: missing token", line_nr);
488 goto error;
489 }
490 if (match("RSA", &token))
491 {
492 char path[PATH_BUF];
493 chunk_t filename;
494
495 err_t ugh = extract_value(&filename, &line);
496
497 if (ugh != NULL)
498 {
499 this->logger->log(this->logger, ERROR, "line %d: %s", line_nr, ugh);
500 goto error;
501 }
502 if (filename.len == 0)
503 {
504 this->logger->log(this->logger, ERROR,
505 "line %d: empty filename", line_nr);
506 goto error;
507 }
508 if (*filename.ptr == '/')
509 {
510 /* absolute path name */
511 snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
512 }
513 else
514 {
515 /* relative path name */
516 snprintf(path, sizeof(path), "%s/%.*s", defaultpath, filename.len, filename.ptr);
517 }
518
519 rsa_private_key_t *key = rsa_private_key_create_from_file(path, NULL);
520 if (key)
521 {
522 this->private_keys->insert_last(this->private_keys, (void*)key);
523 }
524 }
525 else if (match("PSK", &token))
526 {
527
528 }
529 else if (match("PIN", &token))
530 {
531
532 }
533 else
534 {
535 this->logger->log(this->logger, ERROR,
536 "line %d: token must be either RSA, PSK, or PIN",
537 line_nr, token.len);
538 goto error;
539 }
540 }
541 error:
542 free(chunk.ptr);
543 }
544 else
545 {
546 this->logger->log(this->logger, ERROR, "could not open file '%s'", secretsfile);
547 }
548 }
549
550 /**
551 * Implementation of credential_store_t.destroy.
552 */
553 static void destroy(private_credential_store_t *this)
554 {
555 x509_t *cert;
556 crl_t *crl;
557 rsa_private_key_t *key;
558
559 /* destroy cert list */
560 while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
561 {
562 cert->destroy(cert);
563 }
564 this->certs->destroy(this->certs);
565
566 /* destroy ca cert list */
567 while (this->ca_certs->remove_last(this->ca_certs, (void**)&cert) == SUCCESS)
568 {
569 cert->destroy(cert);
570 }
571 this->ca_certs->destroy(this->ca_certs);
572
573 /* destroy crl list */
574 pthread_mutex_lock(&(this->crls_mutex));
575 while (this->crls->remove_last(this->crls, (void**)&crl) == SUCCESS)
576 {
577 crl->destroy(crl);
578 }
579 this->crls->destroy(this->crls);
580 pthread_mutex_unlock(&(this->crls_mutex));
581
582 /* destroy private key list */
583 while (this->private_keys->remove_last(this->private_keys, (void**)&key) == SUCCESS)
584 {
585 key->destroy(key);
586 }
587 this->private_keys->destroy(this->private_keys);
588
589 free(this);
590 }
591
592 /**
593 * Described in header.
594 */
595 credential_store_t * credential_store_create(bool strict)
596 {
597 private_credential_store_t *this = malloc_thing(private_credential_store_t);
598
599 this->public.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret;
600 this->public.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,rsa_public_key_t*))get_rsa_private_key;
601 this->public.has_rsa_private_key = (bool(*)(credential_store_t*,rsa_public_key_t*))has_rsa_private_key;
602 this->public.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
603 this->public.add_end_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_end_certificate;
604 this->public.add_ca_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_ca_certificate;
605 this->public.log_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_certificates;
606 this->public.log_ca_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_ca_certificates;
607 this->public.log_crls = (void(*)(credential_store_t*,logger_t*,bool))log_crls;
608 this->public.load_ca_certificates = (void(*)(credential_store_t*,const char*))load_ca_certificates;
609 this->public.load_crls = (void(*)(credential_store_t*,const char*))load_crls;
610 this->public.load_private_keys = (void(*)(credential_store_t*,const char*, const char*))load_private_keys;
611 this->public.destroy = (void(*)(credential_store_t*))destroy;
612
613 /* initialize mutexes */
614 pthread_mutex_init(&(this->crls_mutex), NULL);
615
616 /* private variables */
617 this->private_keys = linked_list_create();
618 this->certs = linked_list_create();
619 this->ca_certs = linked_list_create();
620 this->crls = linked_list_create();
621 this->strict = strict;
622 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
623
624 return (&this->public);
625 }