diff options
Diffstat (limited to 'src/charon/config/credentials/local_credential_store.c')
-rw-r--r-- | src/charon/config/credentials/local_credential_store.c | 240 |
1 files changed, 237 insertions, 3 deletions
diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c index ef128845c..53e9cb64f 100644 --- a/src/charon/config/credentials/local_credential_store.c +++ b/src/charon/config/credentials/local_credential_store.c @@ -25,15 +25,18 @@ #include <string.h> #include <pthread.h> -#include "local_credential_store.h" - #include <utils/lexparser.h> #include <utils/linked_list.h> #include <utils/logger_manager.h> +#include <crypto/certinfo.h> +#include <crypto/rsa/rsa_public_key.h> #include <crypto/x509.h> #include <crypto/crl.h> -#define PATH_BUF 256 +#include "local_credential_store.h" + +#define PATH_BUF 256 +#define MAX_CA_PATH_LEN 7 typedef struct private_local_credential_store_t private_local_credential_store_t; @@ -166,6 +169,236 @@ static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_publ } /** + * Implementation of credential_store_t.get_issuer_certificate. + */ +static x509_t* get_issuer_certificate(private_local_credential_store_t *this, const x509_t *cert) +{ + x509_t *issuer_cert = NULL; + + iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE); + + while (iterator->has_next(iterator)) + { + x509_t *current_cert; + + iterator->current(iterator, (void**)¤t_cert); + if (cert->is_issuer(cert, current_cert)) + { + issuer_cert = current_cert; + break; + } + } + iterator->destroy(iterator); + + return issuer_cert; +} + +/** + * Implementation of credential_store_t.get_crl. + */ +static crl_t* get_crl(private_local_credential_store_t *this, const x509_t *issuer) +{ + crl_t *crl = NULL; + + iterator_t *iterator = this->crls->create_iterator(this->crls, TRUE); + + while (iterator->has_next(iterator)) + { + crl_t *current_crl; + + iterator->current(iterator, (void**)¤t_crl); + if (current_crl->is_issuer(current_crl, issuer)) + { + crl = current_crl; + break; + } + } + iterator->destroy(iterator); + + return crl; +} + +/** + * Verify the certificate status using CRLs + */ +static cert_status_t verify_by_crl(private_local_credential_store_t* this, const x509_t *cert, + const x509_t *issuer_cert, certinfo_t *certinfo) +{ + crl_t *crl; + bool valid_signature; + rsa_public_key_t *issuer_public_key; + + + pthread_mutex_lock(&(this->crls_mutex)); + + crl = get_crl(this, issuer_cert); + if (crl == NULL) + { + this->logger->log(this->logger, ERROR, "crl not found"); + goto err; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "crl found"); + + issuer_public_key = issuer_cert->get_public_key(issuer_cert); + valid_signature = crl->verify(crl, issuer_public_key); + issuer_public_key->destroy(issuer_public_key); + + if (!valid_signature) + { + this->logger->log(this->logger, ERROR, "crl signature is invalid"); + goto err; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "crl signature is valid"); + + crl->get_status(crl, certinfo); + +err: + pthread_mutex_unlock(&(this->crls_mutex)); + return certinfo->get_status(certinfo); +} + +/** + * Verify the certificate status using OCSP + */ +static cert_status_t verify_by_ocsp(private_local_credential_store_t* this, + const x509_t *cert, certinfo_t *certinfo) +{ + /* TODO implement function */ + return CERT_UNDEFINED; +} + +/** + * Remove a public key for the linked list + */ +static void remove_public_key(private_local_credential_store_t *this, const x509_t *cert) +{ + /* TODO implement function */ +} + +/** + * Implementation of credential_store_t.verify. + */ +static bool verify(private_local_credential_store_t *this, const x509_t *cert, time_t *until) +{ + int pathlen; + + *until = UNDEFINED_TIME; + + for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + { + err_t ugh = NULL; + x509_t *issuer_cert; + rsa_public_key_t *issuer_public_key; + bool valid_signature; + + identification_t *subject = cert->get_subject(cert); + identification_t *issuer = cert->get_issuer(cert); + + this->logger->log(this->logger, CONTROL|LEVEL1, "subject: '%s'", subject->get_string(subject)); + this->logger->log(this->logger, CONTROL|LEVEL1, "issuer: '%s'", issuer->get_string(issuer)); + + ugh = cert->is_valid(cert, until); + if (ugh != NULL) + { + this->logger->log(this->logger, ERROR, "certificate %s", ugh); + return FALSE; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "certificate is valid"); + + issuer_cert = get_issuer_certificate(this, cert); + if (issuer_cert == NULL) + { + this->logger->log(this->logger, ERROR, "issuer certificate not found"); + return FALSE; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "issuer certificate found"); + + issuer_public_key = issuer_cert->get_public_key(issuer_cert); + valid_signature = cert->verify(cert, issuer_public_key); + issuer_public_key->destroy(issuer_public_key); + + if (!valid_signature) + { + this->logger->log(this->logger, ERROR, "certificate signature is invalid"); + return FALSE; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "certificate signature is valid"); + + /* check if cert is a self-signed root ca */ + if (pathlen > 0 && cert->is_self_signed(cert)) + { + this->logger->log(this->logger, CONTROL|LEVEL1, "reached self-signed root ca"); + return TRUE; + } + else + { + time_t nextUpdate; + cert_status_t status; + certinfo_t *certinfo = certinfo_create(cert->get_serialNumber(cert)); + + certinfo->set_nextUpdate(certinfo, *until); + + /* first check certificate revocation using ocsp */ + status = verify_by_ocsp(this, cert, certinfo); + + /* if ocsp service is not available then fall back to crl */ + if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict)) + { + status = verify_by_crl(this, cert, issuer_cert, certinfo); + } + + nextUpdate = certinfo->get_nextUpdate(certinfo); + + switch (status) + { + case CERT_GOOD: + /* if status information is stale */ + if (this->strict && nextUpdate < time(NULL)) + { + this->logger->log(this->logger, CONTROL|LEVEL1, "certificate is good but status is stale"); + remove_public_key(this, cert); + return FALSE; + } + this->logger->log(this->logger, CONTROL|LEVEL1, "certificate is good"); + + /* with strict crl policy the public key must have the same + * lifetime as the validity of the ocsp status or crl lifetime + */ + if (this->strict && nextUpdate < *until) + *until = nextUpdate; + break; + case CERT_REVOKED: + { + u_char buf[TIMETOA_BUF]; + time_t revocationTime = certinfo->get_revocationTime(certinfo); + + timetoa(buf, TIMETOA_BUF, &revocationTime, TRUE); + this->logger->log(this->logger, ERROR, "certificate was revoked on %s, reason: %s", + buf, certinfo->get_revocationReason(certinfo)); + remove_public_key(this, cert); + return FALSE; + } + case CERT_UNKNOWN: + case CERT_UNDEFINED: + default: + this->logger->log(this->logger, CONTROL|LEVEL1, "certificate status unknown"); + if (this->strict) + { + remove_public_key(this, cert); + return FALSE; + } + break; + } + certinfo->destroy(certinfo); + } + /* go up one step in the trust chain */ + cert = issuer_cert; + } + this->logger->log(this->logger, ERROR, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + return FALSE; +} + +/** * Add a unique certificate to a linked list */ static x509_t* add_certificate(linked_list_t *certs, x509_t *cert) @@ -600,6 +833,7 @@ local_credential_store_t * local_credential_store_create(bool strict) this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,rsa_public_key_t*))get_rsa_private_key; this->public.credential_store.has_rsa_private_key = (bool(*)(credential_store_t*,rsa_public_key_t*))has_rsa_private_key; this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key; + this->public.credential_store.verify = (bool(*)(credential_store_t*,const x509_t*,time_t*))verify; this->public.credential_store.add_end_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_end_certificate; this->public.credential_store.add_ca_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_ca_certificate; this->public.credential_store.log_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_certificates; |