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