diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2006-06-20 06:05:01 +0000 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2006-06-20 06:05:01 +0000 |
commit | 21b433c64181a9ba25a558745a5850fe0ff32eb0 (patch) | |
tree | fdd7f3f4b4cc6902415b14dea6aa154a65227abf /src | |
parent | db959e6ea364122140f5531958f59b096356d764 (diff) | |
download | strongswan-21b433c64181a9ba25a558745a5850fe0ff32eb0.tar.bz2 strongswan-21b433c64181a9ba25a558745a5850fe0ff32eb0.tar.xz |
implemented rereadcrls rereadcacerts
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/credentials/credential_store.c | 625 | ||||
-rwxr-xr-x | src/charon/config/credentials/credential_store.h | 44 | ||||
-rw-r--r-- | src/charon/daemon.c | 16 | ||||
-rwxr-xr-x | src/charon/threads/stroke_interface.c | 27 |
4 files changed, 702 insertions, 10 deletions
diff --git a/src/charon/config/credentials/credential_store.c b/src/charon/config/credentials/credential_store.c new file mode 100644 index 000000000..6e7d33813 --- /dev/null +++ b/src/charon/config/credentials/credential_store.c @@ -0,0 +1,625 @@ +/** + * @file credential_store.c + * + * @brief Implementation of credential_store_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <sys/stat.h> +#include <dirent.h> +#include <string.h> +#include <pthread.h> + +#include "credential_store.h" + +#include <utils/lexparser.h> +#include <utils/linked_list.h> +#include <utils/logger_manager.h> +#include <crypto/x509.h> +#include <crypto/crl.h> + +#define PATH_BUF 256 + +typedef struct private_credential_store_t private_credential_store_t; + +/** + * Private data of an credential_store_t object + */ +struct private_credential_store_t { + + /** + * Public part + */ + credential_store_t public; + + /** + * list of key_entry_t's with private keys + */ + linked_list_t *private_keys; + + /** + * list of X.509 certificates with public keys + */ + linked_list_t *certs; + + /** + * list of X.509 CA certificates with public keys + */ + linked_list_t *ca_certs; + + /** + * list of X.509 CRLs + */ + linked_list_t *crls; + + /** + * mutex controlling the access to the crls linked list + */ + pthread_mutex_t crls_mutex; + + /** + * enforce strict crl policy + */ + bool strict; + + /** + * Assigned logger + */ + logger_t *logger; +}; + + +/** + * Implementation of credential_store_t.get_shared_secret. + */ +static status_t get_shared_secret(private_credential_store_t *this, identification_t *id, chunk_t *secret) +{ + return FAILED; +} + +/** + * Implementation of credential_store_t.get_rsa_public_key. + */ +static rsa_public_key_t * get_rsa_public_key(private_credential_store_t *this, identification_t *id) +{ + rsa_public_key_t *found = NULL; + + iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE); + + while (iterator->has_next(iterator)) + { + x509_t *cert; + + iterator->current(iterator, (void**)&cert); + + if (id->equals(id, cert->get_subject(cert)) || cert->equals_subjectAltName(cert, id)) + { + found = cert->get_public_key(cert); + break; + } + } + iterator->destroy(iterator); + return found; +} + +/** + * Implementation of credential_store_t.get_rsa_private_key. + */ +static rsa_private_key_t* get_rsa_private_key(private_credential_store_t *this, rsa_public_key_t *pubkey) +{ + rsa_private_key_t *found = NULL; + rsa_private_key_t *current; + + iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE); + + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)¤t); + + if (current->belongs_to(current, pubkey)) + { + found = current->clone(current); + break; + } + } + iterator->destroy(iterator); + return found; +} + +/** + * Implementation of credential_store_t.has_rsa_private_key. + */ +static bool has_rsa_private_key(private_credential_store_t *this, rsa_public_key_t *pubkey) +{ + bool found = FALSE; + rsa_private_key_t *current; + + iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE); + + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)¤t); + + if (current->belongs_to(current, pubkey)) + { + found = TRUE; + break; + } + } + iterator->destroy(iterator); + return found; +} + +/** + * Add a unique certificate to a linked list + */ +static x509_t* add_certificate(linked_list_t *certs, x509_t *cert) +{ + bool found = FALSE; + + iterator_t *iterator = certs->create_iterator(certs, TRUE); + + while (iterator->has_next(iterator)) + { + x509_t *current_cert; + + iterator->current(iterator, (void**)¤t_cert); + if (cert->equals(cert, current_cert)) + { + found = TRUE; + cert->destroy(cert); + cert = current_cert; + break; + } + } + iterator->destroy(iterator); + + if (!found) + { + certs->insert_last(certs, (void*)cert); + } + return cert; +} + +/** + * Implements credential_store_t.add_end_certificate + */ +static x509_t* add_end_certificate(private_credential_store_t *this, x509_t *cert) +{ + return add_certificate(this->certs, cert); +} + +/** + * Implements credential_store_t.add_ca_certificate + */ +static x509_t* add_ca_certificate(private_credential_store_t *this, x509_t *cert) +{ + return add_certificate(this->ca_certs, cert); +} + +/** + * Implements credential_store_t.log_certificates + */ +static void log_certificates(private_credential_store_t *this, logger_t *logger, bool utc) +{ + iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE); + + if (iterator->get_count(iterator)) + { + logger->log(logger, CONTROL, ""); + logger->log(logger, CONTROL, "List of X.509 End Entity Certificates:"); + logger->log(logger, CONTROL, ""); + } + + while (iterator->has_next(iterator)) + { + x509_t *cert; + bool has_key; + + iterator->current(iterator, (void**)&cert); + has_key = has_rsa_private_key(this, cert->get_public_key(cert)); + cert->log_certificate(cert, logger, utc, has_key); + } + iterator->destroy(iterator); +} + +/** + * Implements credential_store_t.log_ca_certificates + */ +static void log_ca_certificates(private_credential_store_t *this, logger_t *logger, bool utc) +{ + iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE); + + if (iterator->get_count(iterator)) + { + logger->log(logger, CONTROL, ""); + logger->log(logger, CONTROL, "List of X.509 CA Certificates:"); + logger->log(logger, CONTROL, ""); + } + + while (iterator->has_next(iterator)) + { + x509_t *cert; + + iterator->current(iterator, (void**)&cert); + cert->log_certificate(cert, logger, utc, FALSE); + } + iterator->destroy(iterator); +} + +/** + * Implements credential_store_t.log_crls + */ +static void log_crls(private_credential_store_t *this, logger_t *logger, bool utc) +{ + iterator_t *iterator = this->crls->create_iterator(this->crls, TRUE); + + pthread_mutex_lock(&(this->crls_mutex)); + if (iterator->get_count(iterator)) + { + logger->log(logger, CONTROL, ""); + logger->log(logger, CONTROL, "List of X.509 CRLs:"); + logger->log(logger, CONTROL, ""); + } + + while (iterator->has_next(iterator)) + { + crl_t *crl; + + iterator->current(iterator, (void**)&crl); + crl->log_crl(crl, logger, utc, this->strict); + } + pthread_mutex_unlock(&(this->crls_mutex)); + + iterator->destroy(iterator); +} + +/** + * Implements credential_store_t.load_ca_certificates + */ +static void load_ca_certificates(private_credential_store_t *this, const char *path) +{ + struct dirent* entry; + struct stat stb; + DIR* dir; + x509_t *cert; + + this->logger->log(this->logger, CONTROL, "loading ca certificates from '%s/'", path); + + dir = opendir(path); + if (dir == NULL) + { + this->logger->log(this->logger, ERROR, "error opening ca certs directory %s'", path); + return; + } + + while ((entry = readdir(dir)) != NULL) + { + char file[PATH_BUF]; + + snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); + + if (stat(file, &stb) == -1) + { + continue; + } + /* try to parse all regular files */ + if (stb.st_mode & S_IFREG) + { + cert = x509_create_from_file(file, "ca certificate"); + if (cert) + { + err_t ugh = cert->is_valid(cert, NULL); + + if (ugh != NULL) + { + this->logger->log(this->logger, ERROR, "warning: ca certificate %s", ugh); + } + if (cert->is_ca(cert)) + { + cert = add_certificate(this->ca_certs, cert); + } + else + { + this->logger->log(this->logger, ERROR, + " CA basic constraints flag not set, cert discarded"); + cert->destroy(cert); + } + } + } + } + closedir(dir); +} + +/** + * Add the latest crl to a linked list + */ +static crl_t* add_crl(linked_list_t *crls, crl_t *crl, logger_t *logger) +{ + bool found = FALSE; + + iterator_t *iterator = crls->create_iterator(crls, TRUE); + + while (iterator->has_next(iterator)) + { + crl_t *current_crl; + + iterator->current(iterator, (void**)¤t_crl); + if (crl->equals_issuer(crl, current_crl)) + { + found = TRUE; + if (crl->is_newer(crl, current_crl)) + { + crl_t *old_crl = NULL; + + iterator->replace(iterator, (void**)&old_crl, (void*)crl); + if (old_crl != NULL) + { + old_crl->destroy(old_crl); + } + logger->log(logger, CONTROL|LEVEL1, " thisUpdate is newer - existing crl replaced"); + } + else + { + crl->destroy(crl); + crl = current_crl; + logger->log(logger, CONTROL|LEVEL1, " thisUpdate is not newer - existing crl retained"); + } + break; + } + } + iterator->destroy(iterator); + + if (!found) + { + crls->insert_last(crls, (void*)crl); + logger->log(logger, CONTROL|LEVEL1, " crl added"); + } + return crl; +} + +/** + * Implements credential_store_t.load_crls + */ +static void load_crls(private_credential_store_t *this, const char *path) +{ + struct dirent* entry; + struct stat stb; + DIR* dir; + crl_t *crl; + + this->logger->log(this->logger, CONTROL, "loading crls from '%s/'", path); + + dir = opendir(path); + if (dir == NULL) + { + this->logger->log(this->logger, ERROR, "error opening crl directory %s'", path); + return; + } + + while ((entry = readdir(dir)) != NULL) + { + char file[PATH_BUF]; + + snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); + + if (stat(file, &stb) == -1) + { + continue; + } + /* try to parse all regular files */ + if (stb.st_mode & S_IFREG) + { + crl = crl_create_from_file(file); + if (crl) + { + err_t ugh = crl->is_valid(crl, NULL, this->strict); + + if (ugh != NULL) + { + this->logger->log(this->logger, ERROR, "warning: crl %s", ugh); + } + pthread_mutex_lock(&(this->crls_mutex)); + crl = add_crl(this->crls, crl, this->logger); + pthread_mutex_unlock(&(this->crls_mutex)); + } + } + } + closedir(dir); +} + +/** + * Implements credential_store_t.load_private_keys + */ +static void load_private_keys(private_credential_store_t *this, const char *secretsfile, const char *defaultpath) +{ + FILE *fd = fopen(secretsfile, "r"); + + if (fd) + { + int bytes; + int line_nr = 0; + chunk_t chunk, src, line; + + this->logger->log(this->logger, CONTROL, "loading secrets from \"%s\"", secretsfile); + + fseek(fd, 0, SEEK_END); + chunk.len = ftell(fd); + rewind(fd); + chunk.ptr = malloc(chunk.len); + bytes = fread(chunk.ptr, 1, chunk.len, fd); + fclose(fd); + + src = chunk; + + while (fetchline(&src, &line)) + { + chunk_t ids, token; + + line_nr++; + + if (!eat_whitespace(&line)) + { + continue; + } + if (!extract_token(&ids, ':', &line)) + { + this->logger->log(this->logger, ERROR, "line %d: missing ':' separator", line_nr); + goto error; + } + if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) + { + this->logger->log(this->logger, ERROR, "line %d: missing token", line_nr); + goto error; + } + if (match("RSA", &token)) + { + char path[PATH_BUF]; + chunk_t filename; + + err_t ugh = extract_value(&filename, &line); + + if (ugh != NULL) + { + this->logger->log(this->logger, ERROR, "line %d: %s", line_nr, ugh); + goto error; + } + if (filename.len == 0) + { + this->logger->log(this->logger, ERROR, + "line %d: empty filename", line_nr); + goto error; + } + if (*filename.ptr == '/') + { + /* absolute path name */ + snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); + } + else + { + /* relative path name */ + snprintf(path, sizeof(path), "%s/%.*s", defaultpath, filename.len, filename.ptr); + } + + rsa_private_key_t *key = rsa_private_key_create_from_file(path, NULL); + if (key) + { + this->private_keys->insert_last(this->private_keys, (void*)key); + } + } + else if (match("PSK", &token)) + { + + } + else if (match("PIN", &token)) + { + + } + else + { + this->logger->log(this->logger, ERROR, + "line %d: token must be either RSA, PSK, or PIN", + line_nr, token.len); + goto error; + } + } +error: + free(chunk.ptr); + } + else + { + this->logger->log(this->logger, ERROR, "could not open file '%s'", secretsfile); + } +} + +/** + * Implementation of credential_store_t.destroy. + */ +static void destroy(private_credential_store_t *this) +{ + x509_t *cert; + crl_t *crl; + rsa_private_key_t *key; + + /* destroy cert list */ + while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS) + { + cert->destroy(cert); + } + this->certs->destroy(this->certs); + + /* destroy ca cert list */ + while (this->ca_certs->remove_last(this->ca_certs, (void**)&cert) == SUCCESS) + { + cert->destroy(cert); + } + this->ca_certs->destroy(this->ca_certs); + + /* destroy crl list */ + pthread_mutex_lock(&(this->crls_mutex)); + while (this->crls->remove_last(this->crls, (void**)&crl) == SUCCESS) + { + crl->destroy(crl); + } + this->crls->destroy(this->crls); + pthread_mutex_unlock(&(this->crls_mutex)); + + /* destroy private key list */ + while (this->private_keys->remove_last(this->private_keys, (void**)&key) == SUCCESS) + { + key->destroy(key); + } + this->private_keys->destroy(this->private_keys); + + free(this); +} + +/** + * Described in header. + */ +credential_store_t * credential_store_create(bool strict) +{ + private_credential_store_t *this = malloc_thing(private_credential_store_t); + + this->public.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret; + this->public.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,rsa_public_key_t*))get_rsa_private_key; + this->public.has_rsa_private_key = (bool(*)(credential_store_t*,rsa_public_key_t*))has_rsa_private_key; + this->public.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key; + this->public.add_end_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_end_certificate; + this->public.add_ca_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_ca_certificate; + this->public.log_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_certificates; + this->public.log_ca_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_ca_certificates; + this->public.log_crls = (void(*)(credential_store_t*,logger_t*,bool))log_crls; + this->public.load_ca_certificates = (void(*)(credential_store_t*,const char*))load_ca_certificates; + this->public.load_crls = (void(*)(credential_store_t*,const char*))load_crls; + this->public.load_private_keys = (void(*)(credential_store_t*,const char*, const char*))load_private_keys; + this->public.destroy = (void(*)(credential_store_t*))destroy; + + /* initialize mutexes */ + pthread_mutex_init(&(this->crls_mutex), NULL); + + /* private variables */ + this->private_keys = linked_list_create(); + this->certs = linked_list_create(); + this->ca_certs = linked_list_create(); + this->crls = linked_list_create(); + this->strict = strict; + this->logger = logger_manager->get_logger(logger_manager, CONFIG); + + return (&this->public); +} diff --git a/src/charon/config/credentials/credential_store.h b/src/charon/config/credentials/credential_store.h index f364ebddf..4b6623d7c 100755 --- a/src/charon/config/credentials/credential_store.h +++ b/src/charon/config/credentials/credential_store.h @@ -136,6 +136,39 @@ struct credential_store_t { void (*log_crls) (credential_store_t *this, logger_t *logger, bool utc); /** + * @brief Loads trusted CA certificates from a default directory. + * + * Certificates in both DER and PEM format are accepted + * + * @param this calling object + * @param path directory to load certificates from + */ + void (*load_ca_certificates) (credential_store_t *this, const char *path); + + /** + * @brief Loads CRLs from a default directory. + * + * Certificates in both DER and PEM format are accepted + * + * @param this calling object + * @param path directory to load crls from + */ + void (*load_crls) (credential_store_t *this, const char *path); + + /** + * @brief Loads RSA private keys defined in ipsec.secrets + * + * Currently, all keys must be unencrypted in either DER or PEM format. + * Other formats are ignored. Further, a certificate for the specific private + * key must already be loaded to get the ID from. + * + * @param this calling object + * @param secretsfile file where secrets are stored + * @param path default directory for private keys + */ + void (*load_private_keys) (credential_store_t *this, const char *secretsfile, const char *path); + + /** * @brief Destroys a credential_store_t object. * * @param this calling object @@ -143,4 +176,15 @@ struct credential_store_t { void (*destroy) (credential_store_t *this); }; +/** + * @brief Creates a credential_store_t instance. + * + * @param strict enforce a strict crl policy + * @return credential store instance. + * + * @ingroup config + */ +credential_store_t *credential_store_create(bool strict); + + #endif /*CREDENTIAL_STORE_H_*/ diff --git a/src/charon/daemon.c b/src/charon/daemon.c index 16bd271f5..71726620b 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -33,8 +33,8 @@ #include "daemon.h" #include <types.h> +#include <config/credentials/credential_store.h> #include <config/connections/local_connection_store.h> -#include <config/credentials/local_credential_store.h> #include <config/policies/local_policy_store.h> @@ -167,7 +167,7 @@ static void kill_daemon(private_daemon_t *this, char *reason) */ static void initialize(private_daemon_t *this, bool strict) { - local_credential_store_t* cred_store; + credential_store_t* credentials; this->public.configuration = configuration_create(); this->public.socket = socket_create(IKEV2_UDP_PORT); @@ -177,11 +177,13 @@ static void initialize(private_daemon_t *this, bool strict) this->public.send_queue = send_queue_create(); this->public.connections = (connection_store_t*)local_connection_store_create(); this->public.policies = (policy_store_t*)local_policy_store_create(); - this->public.credentials = (credential_store_t*)(cred_store = local_credential_store_create(strict)); - - /* load keys & certs */ - cred_store->load_ca_certificates(cred_store, CA_CERTIFICATE_DIR); - cred_store->load_private_keys(cred_store, SECRETS_FILE, PRIVATE_KEY_DIR); + this->public.credentials = credential_store_create(strict); + + /* load keys, ca certificates and crls */ + credentials = this->public.credentials; + credentials->load_ca_certificates(credentials, CA_CERTIFICATE_DIR); + credentials->load_crls(credentials, CRL_DIR); + credentials->load_private_keys(credentials, SECRETS_FILE, PRIVATE_KEY_DIR); /* start building threads, we are multi-threaded NOW */ diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index 1dc45fed4..6a86edbe9 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -414,7 +414,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) proposal = proposal_create_from_string(PROTO_ESP, proposal_string); if (proposal == NULL) { - this->logger->log(this->logger, ERROR, "invalid ESP proposal string: %s", msg->add_conn.algorithms.esp); + this->logger->log(this->logger, ERROR, + "invalid ESP proposal string: %s", msg->add_conn.algorithms.esp); policy->destroy(policy); connection->destroy(connection); return; @@ -494,13 +495,15 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->initiate.name); if (ike_sas->get_count(ike_sas) == 0) { - this->stroke_logger->log(this->stroke_logger, CONTROL, "initiating connection \"%s\" (see log)...", msg->initiate.name); + this->stroke_logger->log(this->stroke_logger, CONTROL, + "initiating connection \"%s\" (see log)...", msg->initiate.name); job = initiate_ike_sa_job_create(connection); charon->job_queue->add(charon->job_queue, (job_t*)job); } else { - this->stroke_logger->log(this->stroke_logger, CONTROL, "connection \"%s\" already up", msg->initiate.name); + this->stroke_logger->log(this->stroke_logger, CONTROL, + "connection \"%s\" already up", msg->initiate.name); } while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS) { @@ -601,6 +604,21 @@ static void stroke_list(private_stroke_t *this, stroke_msg_t *msg) } } +/** + * reread various information + */ +static void stroke_reread(private_stroke_t *this, stroke_msg_t *msg) +{ + if (msg->reread.flags & REREAD_CACERTS) + { + charon->credentials->load_ca_certificates(charon->credentials, CA_CERTIFICATE_DIR); + } + if (msg->reread.flags & REREAD_CRLS) + { + charon->credentials->load_crls(charon->credentials, CRL_DIR); + } +} + logger_context_t get_context(char *context) { if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS; @@ -797,6 +815,9 @@ static void stroke_receive(private_stroke_t *this) case STR_LIST: stroke_list(this, msg); break; + case STR_REREAD: + stroke_reread(this, msg); + break; default: this->logger->log(this->logger, ERROR, "received invalid stroke"); } |