2 * @file credential_store.c
4 * @brief Implementation of credential_store_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
28 #include "credential_store.h"
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>
38 typedef struct private_credential_store_t private_credential_store_t
;
41 * Private data of an credential_store_t object
43 struct private_credential_store_t
{
48 credential_store_t
public;
51 * list of key_entry_t's with private keys
53 linked_list_t
*private_keys
;
56 * list of X.509 certificates with public keys
61 * list of X.509 CA certificates with public keys
63 linked_list_t
*ca_certs
;
71 * mutex controlling the access to the crls linked list
73 pthread_mutex_t crls_mutex
;
76 * enforce strict crl policy
88 * Implementation of credential_store_t.get_shared_secret.
90 static status_t
get_shared_secret(private_credential_store_t
*this, identification_t
*id
, chunk_t
*secret
)
96 * Implementation of credential_store_t.get_rsa_public_key.
98 static rsa_public_key_t
* get_rsa_public_key(private_credential_store_t
*this, identification_t
*id
)
100 rsa_public_key_t
*found
= NULL
;
102 iterator_t
*iterator
= this->certs
->create_iterator(this->certs
, TRUE
);
104 while (iterator
->has_next(iterator
))
108 iterator
->current(iterator
, (void**)&cert
);
110 if (id
->equals(id
, cert
->get_subject(cert
)) || cert
->equals_subjectAltName(cert
, id
))
112 found
= cert
->get_public_key(cert
);
116 iterator
->destroy(iterator
);
121 * Implementation of credential_store_t.get_rsa_private_key.
123 static rsa_private_key_t
* get_rsa_private_key(private_credential_store_t
*this, rsa_public_key_t
*pubkey
)
125 rsa_private_key_t
*found
= NULL
;
126 rsa_private_key_t
*current
;
128 iterator_t
*iterator
= this->private_keys
->create_iterator(this->private_keys
, TRUE
);
130 while (iterator
->has_next(iterator
))
132 iterator
->current(iterator
, (void**)¤t
);
134 if (current
->belongs_to(current
, pubkey
))
136 found
= current
->clone(current
);
140 iterator
->destroy(iterator
);
145 * Implementation of credential_store_t.has_rsa_private_key.
147 static bool has_rsa_private_key(private_credential_store_t
*this, rsa_public_key_t
*pubkey
)
150 rsa_private_key_t
*current
;
152 iterator_t
*iterator
= this->private_keys
->create_iterator(this->private_keys
, TRUE
);
154 while (iterator
->has_next(iterator
))
156 iterator
->current(iterator
, (void**)¤t
);
158 if (current
->belongs_to(current
, pubkey
))
164 iterator
->destroy(iterator
);
169 * Add a unique certificate to a linked list
171 static x509_t
* add_certificate(linked_list_t
*certs
, x509_t
*cert
)
175 iterator_t
*iterator
= certs
->create_iterator(certs
, TRUE
);
177 while (iterator
->has_next(iterator
))
179 x509_t
*current_cert
;
181 iterator
->current(iterator
, (void**)¤t_cert
);
182 if (cert
->equals(cert
, current_cert
))
190 iterator
->destroy(iterator
);
194 certs
->insert_last(certs
, (void*)cert
);
200 * Implements credential_store_t.add_end_certificate
202 static x509_t
* add_end_certificate(private_credential_store_t
*this, x509_t
*cert
)
204 return add_certificate(this->certs
, cert
);
208 * Implements credential_store_t.add_ca_certificate
210 static x509_t
* add_ca_certificate(private_credential_store_t
*this, x509_t
*cert
)
212 return add_certificate(this->ca_certs
, cert
);
216 * Implements credential_store_t.log_certificates
218 static void log_certificates(private_credential_store_t
*this, logger_t
*logger
, bool utc
)
220 iterator_t
*iterator
= this->certs
->create_iterator(this->certs
, TRUE
);
222 if (iterator
->get_count(iterator
))
224 logger
->log(logger
, CONTROL
, "");
225 logger
->log(logger
, CONTROL
, "List of X.509 End Entity Certificates:");
226 logger
->log(logger
, CONTROL
, "");
229 while (iterator
->has_next(iterator
))
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
);
238 iterator
->destroy(iterator
);
242 * Implements credential_store_t.log_ca_certificates
244 static void log_ca_certificates(private_credential_store_t
*this, logger_t
*logger
, bool utc
)
246 iterator_t
*iterator
= this->ca_certs
->create_iterator(this->ca_certs
, TRUE
);
248 if (iterator
->get_count(iterator
))
250 logger
->log(logger
, CONTROL
, "");
251 logger
->log(logger
, CONTROL
, "List of X.509 CA Certificates:");
252 logger
->log(logger
, CONTROL
, "");
255 while (iterator
->has_next(iterator
))
259 iterator
->current(iterator
, (void**)&cert
);
260 cert
->log_certificate(cert
, logger
, utc
, FALSE
);
262 iterator
->destroy(iterator
);
266 * Implements credential_store_t.log_crls
268 static void log_crls(private_credential_store_t
*this, logger_t
*logger
, bool utc
)
270 iterator_t
*iterator
= this->crls
->create_iterator(this->crls
, TRUE
);
272 pthread_mutex_lock(&(this->crls_mutex
));
273 if (iterator
->get_count(iterator
))
275 logger
->log(logger
, CONTROL
, "");
276 logger
->log(logger
, CONTROL
, "List of X.509 CRLs:");
277 logger
->log(logger
, CONTROL
, "");
280 while (iterator
->has_next(iterator
))
284 iterator
->current(iterator
, (void**)&crl
);
285 crl
->log_crl(crl
, logger
, utc
, this->strict
);
287 pthread_mutex_unlock(&(this->crls_mutex
));
289 iterator
->destroy(iterator
);
293 * Implements credential_store_t.load_ca_certificates
295 static void load_ca_certificates(private_credential_store_t
*this, const char *path
)
297 struct dirent
* entry
;
302 this->logger
->log(this->logger
, CONTROL
, "loading ca certificates from '%s/'", path
);
307 this->logger
->log(this->logger
, ERROR
, "error opening ca certs directory %s'", path
);
311 while ((entry
= readdir(dir
)) != NULL
)
315 snprintf(file
, sizeof(file
), "%s/%s", path
, entry
->d_name
);
317 if (stat(file
, &stb
) == -1)
321 /* try to parse all regular files */
322 if (stb
.st_mode
& S_IFREG
)
324 cert
= x509_create_from_file(file
, "ca certificate");
327 err_t ugh
= cert
->is_valid(cert
, NULL
);
331 this->logger
->log(this->logger
, ERROR
, "warning: ca certificate %s", ugh
);
333 if (cert
->is_ca(cert
))
335 cert
= add_certificate(this->ca_certs
, cert
);
339 this->logger
->log(this->logger
, ERROR
,
340 " CA basic constraints flag not set, cert discarded");
350 * Add the latest crl to a linked list
352 static crl_t
* add_crl(linked_list_t
*crls
, crl_t
*crl
, logger_t
*logger
)
356 iterator_t
*iterator
= crls
->create_iterator(crls
, TRUE
);
358 while (iterator
->has_next(iterator
))
362 iterator
->current(iterator
, (void**)¤t_crl
);
363 if (crl
->equals_issuer(crl
, current_crl
))
366 if (crl
->is_newer(crl
, current_crl
))
368 crl_t
*old_crl
= NULL
;
370 iterator
->replace(iterator
, (void**)&old_crl
, (void*)crl
);
373 old_crl
->destroy(old_crl
);
375 logger
->log(logger
, CONTROL
|LEVEL1
, " thisUpdate is newer - existing crl replaced");
381 logger
->log(logger
, CONTROL
|LEVEL1
, " thisUpdate is not newer - existing crl retained");
386 iterator
->destroy(iterator
);
390 crls
->insert_last(crls
, (void*)crl
);
391 logger
->log(logger
, CONTROL
|LEVEL1
, " crl added");
397 * Implements credential_store_t.load_crls
399 static void load_crls(private_credential_store_t
*this, const char *path
)
401 struct dirent
* entry
;
406 this->logger
->log(this->logger
, CONTROL
, "loading crls from '%s/'", path
);
411 this->logger
->log(this->logger
, ERROR
, "error opening crl directory %s'", path
);
415 while ((entry
= readdir(dir
)) != NULL
)
419 snprintf(file
, sizeof(file
), "%s/%s", path
, entry
->d_name
);
421 if (stat(file
, &stb
) == -1)
425 /* try to parse all regular files */
426 if (stb
.st_mode
& S_IFREG
)
428 crl
= crl_create_from_file(file
);
431 err_t ugh
= crl
->is_valid(crl
, NULL
, this->strict
);
435 this->logger
->log(this->logger
, ERROR
, "warning: crl %s", ugh
);
437 pthread_mutex_lock(&(this->crls_mutex
));
438 crl
= add_crl(this->crls
, crl
, this->logger
);
439 pthread_mutex_unlock(&(this->crls_mutex
));
447 * Implements credential_store_t.load_private_keys
449 static void load_private_keys(private_credential_store_t
*this, const char *secretsfile
, const char *defaultpath
)
451 FILE *fd
= fopen(secretsfile
, "r");
457 chunk_t chunk
, src
, line
;
459 this->logger
->log(this->logger
, CONTROL
, "loading secrets from \"%s\"", secretsfile
);
461 fseek(fd
, 0, SEEK_END
);
462 chunk
.len
= ftell(fd
);
464 chunk
.ptr
= malloc(chunk
.len
);
465 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
470 while (fetchline(&src
, &line
))
476 if (!eat_whitespace(&line
))
480 if (!extract_token(&ids
, ':', &line
))
482 this->logger
->log(this->logger
, ERROR
, "line %d: missing ':' separator", line_nr
);
485 if (!eat_whitespace(&line
) || !extract_token(&token
, ' ', &line
))
487 this->logger
->log(this->logger
, ERROR
, "line %d: missing token", line_nr
);
490 if (match("RSA", &token
))
495 err_t ugh
= extract_value(&filename
, &line
);
499 this->logger
->log(this->logger
, ERROR
, "line %d: %s", line_nr
, ugh
);
502 if (filename
.len
== 0)
504 this->logger
->log(this->logger
, ERROR
,
505 "line %d: empty filename", line_nr
);
508 if (*filename
.ptr
== '/')
510 /* absolute path name */
511 snprintf(path
, sizeof(path
), "%.*s", filename
.len
, filename
.ptr
);
515 /* relative path name */
516 snprintf(path
, sizeof(path
), "%s/%.*s", defaultpath
, filename
.len
, filename
.ptr
);
519 rsa_private_key_t
*key
= rsa_private_key_create_from_file(path
, NULL
);
522 this->private_keys
->insert_last(this->private_keys
, (void*)key
);
525 else if (match("PSK", &token
))
529 else if (match("PIN", &token
))
535 this->logger
->log(this->logger
, ERROR
,
536 "line %d: token must be either RSA, PSK, or PIN",
546 this->logger
->log(this->logger
, ERROR
, "could not open file '%s'", secretsfile
);
551 * Implementation of credential_store_t.destroy.
553 static void destroy(private_credential_store_t
*this)
557 rsa_private_key_t
*key
;
559 /* destroy cert list */
560 while (this->certs
->remove_last(this->certs
, (void**)&cert
) == SUCCESS
)
564 this->certs
->destroy(this->certs
);
566 /* destroy ca cert list */
567 while (this->ca_certs
->remove_last(this->ca_certs
, (void**)&cert
) == SUCCESS
)
571 this->ca_certs
->destroy(this->ca_certs
);
573 /* destroy crl list */
574 pthread_mutex_lock(&(this->crls_mutex
));
575 while (this->crls
->remove_last(this->crls
, (void**)&crl
) == SUCCESS
)
579 this->crls
->destroy(this->crls
);
580 pthread_mutex_unlock(&(this->crls_mutex
));
582 /* destroy private key list */
583 while (this->private_keys
->remove_last(this->private_keys
, (void**)&key
) == SUCCESS
)
587 this->private_keys
->destroy(this->private_keys
);
593 * Described in header.
595 credential_store_t
* credential_store_create(bool strict
)
597 private_credential_store_t
*this = malloc_thing(private_credential_store_t
);
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
;
613 /* initialize mutexes */
614 pthread_mutex_init(&(this->crls_mutex
), NULL
);
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
);
624 return (&this->public);