diff --git a/src/charon/config/credentials/credential_store.h b/src/charon/config/credentials/credential_store.h index 302eefedc..b1dd87784 100755 --- a/src/charon/config/credentials/credential_store.h +++ b/src/charon/config/credentials/credential_store.h @@ -91,6 +91,16 @@ struct credential_store_t { */ bool (*has_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey); + /** + * @brief Verify an X.509 certificate up to trust anchor including revocation checks + * + * @param this calling object + * @param cert certificate to be verified + * @param until time until which the cert can be trusted + * @return TRUE if trusted + */ + bool (*verify) (credential_store_t *this, const x509_t *cert, time_t *until); + /** * @brief If an end certificate does not already exists in the credential store then add it. * @@ -108,7 +118,7 @@ struct credential_store_t { * @return pointer to the added or already existing certificate */ x509_t* (*add_ca_certificate) (credential_store_t *this, x509_t *cert); - + /** * @brief Lists all certificates kept in the local credential store. * 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 #include -#include "local_credential_store.h" - #include #include #include +#include +#include #include #include -#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; @@ -165,6 +168,236 @@ static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_publ return found; } +/** + * 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 */ @@ -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; diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index 0bb97ca02..912213b1c 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -136,6 +136,7 @@ static x509_t* load_end_certificate(const char *filename, identification_t **idp { identification_t *id = *idp; identification_t *subject = cert->get_subject(cert); + time_t until; err_t ugh = cert->is_valid(cert, NULL); @@ -149,6 +150,20 @@ static x509_t* load_end_certificate(const char *filename, identification_t **idp id = subject; *idp = id->clone(id); } + /* test output */ + if (charon->credentials->verify(charon->credentials, cert, &until)) + { + char buf[TIMETOA_BUF]; + + timetoa(buf, TIMETOA_BUF, &until, TRUE); + logger->log(logger, CONTROL, " end entity certificate is trusted until %s", buf); + cert->set_until(cert, until); + } + else + { + logger->log(logger, ERROR, " end entity certificate is not trusted"); + } + /* end of test output */ return charon->credentials->add_end_certificate(charon->credentials, cert); } return NULL; @@ -305,7 +320,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) } if (msg->add_conn.me.cert) { - x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->stroke_logger); + x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->logger); if (my_ca == NULL && !my_ca_same && cert) { @@ -316,7 +331,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) } if (msg->add_conn.other.cert) { - x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->stroke_logger); + x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->logger); if (other_ca == NULL && !other_ca_same && cert) { diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 968342d48..23ade329f 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -21,6 +21,7 @@ crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \ crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \ crypto/prf_plus.h crypto/prf_plus.c \ crypto/hmac.c crypto/hmac.h \ +crypto/certinfo.c crypto/certinfo.h \ crypto/x509.c crypto/x509.h \ crypto/crl.c crypto/crl.h \ crypto/diffie_hellman.c crypto/diffie_hellman.h \ diff --git a/src/libstrongswan/crypto/certinfo.c b/src/libstrongswan/crypto/certinfo.c new file mode 100644 index 000000000..7fef2fa4f --- /dev/null +++ b/src/libstrongswan/crypto/certinfo.c @@ -0,0 +1,198 @@ +/** + * @file certinfo.c + * + * @brief Implementation of certinfo_t. + * + */ + +/* + * Copyright (C) 2006 Andreas Steffen + * 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 . + * + * 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 + +#include +#include + +#include "certinfo.h" + +typedef struct private_certinfo_t private_certinfo_t; + +/** + * Private data of a certinfo_t object. + */ +struct private_certinfo_t { + /** + * Public interface for this certificate status information object. + */ + certinfo_t public; + + /** + * Serial number of the certificate + */ + chunk_t serialNumber; + + /** + * Certificate status + */ + cert_status_t status; + + /** + * Time when the certificate status info was generated + */ + time_t thisUpdate; + + /** + * Time when an updated certifcate status info will be available + */ + time_t nextUpdate; + + /** + * Time of certificate revocation + */ + time_t revocationTime; + + /** + * Reason of certificate revocation + */ + crl_reason_t revocationReason; +}; + +/** + * RFC 2459 CRL reason codes + */ +static const char *const crl_reason_name[] = { + "unspecified", + "key compromise", + "ca compromise", + "affiliation changed", + "superseded", + "cessation of operation", + "certificate hold", + "reason #7", + "remove from crl" + }; + +enum_names crl_reason_names = + { REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, crl_reason_name, NULL}; + +/** + * Implements certinfo_t.get_serialNumber + */ +static chunk_t get_serialNumber(const private_certinfo_t *this) +{ + return this->serialNumber; +} + +/** + * Implements certinfo_t.set_status + */ +static void set_status(private_certinfo_t *this, cert_status_t status) +{ + this->status = status; +} + +/** + * Implements certinfo_t.get_status + */ +static cert_status_t get_status(const private_certinfo_t *this) +{ + return this->status; +} + +/** + * Implements certinfo_t.set_nextUpdate + */ +static void set_nextUpdate(private_certinfo_t *this, time_t nextUpdate) +{ + this->nextUpdate = nextUpdate; +} + +/** + * Implements certinfo_t.get_nextUpdate + */ +static time_t get_nextUpdate(const private_certinfo_t *this) +{ + return this->nextUpdate; +} + +/** + * Implements certinfo_t.set_revocationTime + */ +static void set_revocationTime(private_certinfo_t *this, time_t revocationTime) +{ + this->revocationTime = revocationTime; +} + +/** + * Implements certinfo_t.get_revocationTime + */ +static time_t get_revocationTime(const private_certinfo_t *this) +{ + return this->revocationTime; +} + +/** + * Implements certinfo_t.set_revocationReason + */ +static void set_revocationReason(private_certinfo_t *this, crl_reason_t reason) +{ + this->revocationReason = reason; +} + +/** + * Implements certinfo_t.get_revocationReason + */ +static const char *get_revocationReason(const private_certinfo_t *this) +{ + return enum_name(&crl_reason_names, this->revocationReason); +} + +/** + * Implements certinfo_t.destroy + */ +static void destroy(private_certinfo_t *this) +{ + free(this->serialNumber.ptr); + free(this); +} + +/* + * Described in header. + */ +certinfo_t *certinfo_create(chunk_t serial) +{ + private_certinfo_t *this = malloc_thing(private_certinfo_t); + + /* initialize */ + this->serialNumber = chunk_clone(serial); + this->status = CERT_UNDEFINED; + this->nextUpdate = UNDEFINED_TIME; + this->revocationTime = UNDEFINED_TIME; + this->revocationReason = REASON_UNSPECIFIED; + + /* public functions */ + this->public.get_serialNumber = (chunk_t (*) (const certinfo_t*))get_serialNumber; + this->public.set_status = (void (*) (certinfo_t*,cert_status_t))set_status; + this->public.get_status = (cert_status_t (*) (const certinfo_t*))get_status; + this->public.set_nextUpdate = (void (*) (certinfo_t*,time_t))set_nextUpdate; + this->public.get_nextUpdate = (time_t (*) (const certinfo_t*))get_nextUpdate; + this->public.set_revocationTime = (void (*) (certinfo_t*,time_t))set_revocationTime; + this->public.get_revocationTime = (time_t (*) (const certinfo_t*))get_revocationTime; + this->public.set_revocationReason = (void (*) (certinfo_t*, crl_reason_t))set_revocationReason; + this->public.get_revocationReason = (const char *(*) (const certinfo_t*))get_revocationReason; + this->public.destroy = (void (*) (certinfo_t*))destroy; + + return &this->public; +} diff --git a/src/libstrongswan/crypto/certinfo.h b/src/libstrongswan/crypto/certinfo.h new file mode 100644 index 000000000..81707fad8 --- /dev/null +++ b/src/libstrongswan/crypto/certinfo.h @@ -0,0 +1,166 @@ +/** + * @file certinfo.h + * + * @brief Interface of certinfo_t. + * + */ + +/* + * Copyright (C) 2006 Andreas Steffen + * 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 . + * + * 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. + */ + +#ifndef CERTINFO_H_ +#define CERTINFO_H_ + +#include +#include + +/** + * RFC 2560 OCSP - certificate status + */ +typedef enum { + CERT_GOOD = 0, + CERT_REVOKED = 1, + CERT_UNKNOWN = 2, + CERT_UNDEFINED = 3 +} cert_status_t; + +/** + * RFC 2459 CRL reason codes + */ + +extern enum_names crl_reason_names; + +typedef enum { + REASON_UNSPECIFIED = 0, + REASON_KEY_COMPROMISE = 1, + REASON_CA_COMPROMISE = 2, + REASON_AFFILIATION_CHANGED = 3, + REASON_SUPERSEDED = 4, + REASON_CESSATION_OF_OPERATON = 5, + REASON_CERTIFICATE_HOLD = 6, + REASON_REMOVE_FROM_CRL = 8 +} crl_reason_t; + +typedef struct certinfo_t certinfo_t; + +/** + * @brief X.509 certificate status information + * + * + * @ingroup transforms + */ +struct certinfo_t { + + /** + * @brief Get serial number + * + * + * @param this calling object + * @return serialNumber + */ + chunk_t (*get_serialNumber) (const certinfo_t *this); + + /** + * @brief Set certificate status + * + * + * @param this calling object + * @param status status + */ + void (*set_status) (certinfo_t *this, cert_status_t status); + + /** + * @brief Get certificate status + * + * + * @param this calling object + * @return status + */ + cert_status_t (*get_status) (const certinfo_t *this); + + /** + * @brief Set nextUpdate + * + * + * @param this calling object + * @return nextUpdate + */ + void (*set_nextUpdate) (certinfo_t *this, time_t nextUpdate); + + /** + * @brief Get nextUpdate + * + * + * @param this calling object + * @return nextUpdate + */ + time_t (*get_nextUpdate) (const certinfo_t *this); + + /** + * @brief Set revocationTime + * + * + * @param this calling object + * @param revocationTime revocationTime + */ + void (*set_revocationTime) (certinfo_t *this, time_t revocationTime); + + /** + * @brief Get revocationTime + * + * + * @param this calling object + * @return revocationTime + */ + time_t (*get_revocationTime) (const certinfo_t *this); + + /** + * @brief Set revocationReason + * + * + * @param this calling object + * @param reason revocationReason + */ + void (*set_revocationReason) (certinfo_t *this, crl_reason_t reason); + + /** + * @brief Get revocationReason + * + * + * @param this calling object + * @return revocationReason + */ + const char *(*get_revocationReason) (const certinfo_t *this); + + /** + * @brief Destroys the certinfo_t object. + * + * @param this crl to destroy + */ + void (*destroy) (certinfo_t *this); + +}; + +/** + * @brief Create a certinfo_t object. + * + * @param serial chunk serial number of the certificate + * @return created certinfo_t object + * + * @ingroup transforms + */ +certinfo_t *certinfo_create(chunk_t serial); + +#endif /* CERTINFO_H_ */ diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c index 603334089..f7e172c57 100755 --- a/src/libstrongswan/crypto/crl.c +++ b/src/libstrongswan/crypto/crl.c @@ -33,8 +33,9 @@ #include #include -#include "crl.h" +#include "certinfo.h" #include "x509.h" +#include "crl.h" #define CRL_WARNING_INTERVAL 7 /* days */ @@ -132,8 +133,9 @@ struct private_crl_t { chunk_t signature; }; -/* ASN.1 definition of an X.509 certificate revocation list */ - +/** + * ASN.1 definition of an X.509 certificate revocation list + */ static const asn1Object_t crlObjects[] = { { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ @@ -201,7 +203,8 @@ static crl_reason_t parse_crl_reasonCode(chunk_t object) { reason = *object.ptr; } - /* TODO logger->log(logger, CONTROL|LEVEL2, " '%s'", enum_name(&crl_reason_names, reason)) */ + logger->log(logger, CONTROL|LEVEL2, " '%s'", enum_name(&crl_reason_names, reason)); + return reason; } @@ -331,14 +334,6 @@ static err_t is_valid(const private_crl_t *this, time_t *until, bool strict) return NULL; } -/** - * Implements crl_t.is_newer - */ -static bool is_newer(const private_crl_t *this, const private_crl_t *other) -{ - return (this->nextUpdate > other->nextUpdate); -} - /** * Implements crl_t.get_issuer */ @@ -359,7 +354,61 @@ static bool equals_issuer(const private_crl_t *this, const private_crl_t *other) } /** - * destroy + * Implements crl_t.is_issuer + */ +static bool is_issuer(const private_crl_t *this, const x509_t *issuer) +{ + return (this->authKeyID.ptr) + ? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer)) + : (this->issuer->equals(this->issuer, issuer->get_subject(issuer)) + && chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer))); +} + +/** + * Implements crl_t.is_newer + */ +static bool is_newer(const private_crl_t *this, const private_crl_t *other) +{ + return (this->nextUpdate > other->nextUpdate); +} + +/** + * Implements crl_t.verify + */ +static bool verify(const private_crl_t *this, const rsa_public_key_t *signer) +{ + return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature); +} + +/** + * Implements crl_t.get_status + */ +static void get_status(const private_crl_t *this, certinfo_t *certinfo) +{ + chunk_t serialNumber = certinfo->get_serialNumber(certinfo); + iterator_t *iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE); + + certinfo->set_nextUpdate(certinfo, this->nextUpdate); + certinfo->set_status(certinfo, CERT_GOOD); + + while (iterator->has_next(iterator)) + { + revokedCert_t *revokedCert; + + iterator->current(iterator, (void**)&revokedCert); + if (chunk_equals(serialNumber, revokedCert->userCertificate)) + { + certinfo->set_status(certinfo, CERT_REVOKED); + certinfo->set_revocationTime(certinfo, revokedCert->revocationDate); + certinfo->set_revocationReason(certinfo, revokedCert->revocationReason); + break; + } + } + iterator->destroy(iterator); +} + +/** + * Implements crl_t.destroy */ static void destroy(private_crl_t *this) { @@ -440,12 +489,15 @@ crl_t *crl_create_from_chunk(chunk_t chunk) this->authKeySerialNumber = CHUNK_INITIALIZER; /* public functions */ - this->public.is_valid = (err_t (*) (const crl_t*,time_t*))is_valid; - this->public.destroy = (void (*) (crl_t*))destroy; this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer; this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer; + this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer; + this->public.is_valid = (err_t (*) (const crl_t*,time_t*,bool))is_valid; this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer; + this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify; + this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status; this->public.log_crl = (void (*) (const crl_t*,logger_t*,bool,bool))log_crl; + this->public.destroy = (void (*) (crl_t*))destroy; /* we do not use a per-instance logger right now, since its not always accessible */ logger = logger_manager->get_logger(logger_manager, ASN1); diff --git a/src/libstrongswan/crypto/crl.h b/src/libstrongswan/crypto/crl.h index 4cecee737..e4739fc29 100755 --- a/src/libstrongswan/crypto/crl.h +++ b/src/libstrongswan/crypto/crl.h @@ -26,11 +26,11 @@ #include #include #include +#include #include #include #include - typedef struct crl_t crl_t; /** @@ -54,7 +54,7 @@ struct crl_t { * @return issuers ID */ identification_t *(*get_issuer) (const crl_t *this); - + /** * @brief Check if both crls have the same issuer. * @@ -65,15 +65,14 @@ struct crl_t { bool (*equals_issuer) (const crl_t *this, const crl_t *other); /** - * @brief Check if a crl is trustworthy + * @brief Check if ia candidate cert is the issuer of the crl * - * Use the issuer's public key to verify - * the trustworthiness of a crl. - * - * @todo implement! + * @param this calling object + * @param issuer candidate issuer of the crl + * @return TRUE if issuer */ - bool (*verify) (const crl_t *this, rsa_public_key_t *signer); - + bool (*is_issuer) (const crl_t *this, const x509_t *issuer); + /** * @brief Checks the validity interval of the crl * @@ -94,13 +93,21 @@ struct crl_t { bool (*is_newer) (const crl_t *this, const crl_t *other); /** - * @brief Check if a certificate has been revoked. - * - * This function uses the certificate's serialNumber - * to get the revocation status. + * @brief Check if a crl is trustworthy. * + * @param this calling object + * @param signer signer's RSA public key + * @return TRUE if crl is trustworthy */ - bool (*get_status) (const crl_t *this, chunk_t serial); + bool (*verify) (const crl_t *this, const rsa_public_key_t *signer); + + /** + * @brief Get the certificate status + * + * @param this calling object + * @param certinfo certinfo is updated + */ + void (*get_status) (const crl_t *this, certinfo_t *certinfo); /** * @brief Destroys the crl. diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c index 87c0bd019..cc714b0ea 100644 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.c +++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c @@ -141,7 +141,7 @@ struct private_rsa_public_key_t { * @param data data to process * @return processed data */ - chunk_t (*rsaep) (private_rsa_public_key_t *this, chunk_t data); + chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data); /** * @brief Implements the RSASVP1 algorithm specified in PKCS#1. @@ -150,7 +150,7 @@ struct private_rsa_public_key_t { * @param data data to process * @return processed data */ - chunk_t (*rsavp1) (private_rsa_public_key_t *this, chunk_t data); + chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data); }; private_rsa_public_key_t *rsa_public_key_create_empty(void); @@ -158,7 +158,7 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void); /** * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1 */ -static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data) +static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data) { mpz_t m, c; chunk_t encrypted; @@ -182,7 +182,7 @@ static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data) /** * Implementation of rsa_public_key.verify_emsa_pkcs1_signature. */ -static status_t verify_emsa_pkcs1_signature(private_rsa_public_key_t *this, chunk_t data, chunk_t signature) +static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature) { hasher_t *hasher = NULL; chunk_t hash; @@ -291,7 +291,7 @@ end: /** * Implementation of rsa_public_key.get_key. */ -static status_t get_key(private_rsa_public_key_t *this, chunk_t *key) +static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key) { chunk_t n, e; @@ -313,7 +313,7 @@ static status_t get_key(private_rsa_public_key_t *this, chunk_t *key) /** * Implementation of rsa_public_key.save_key. */ -static status_t save_key(private_rsa_public_key_t *this, char *file) +static status_t save_key(const private_rsa_public_key_t *this, char *file) { return NOT_SUPPORTED; } @@ -321,7 +321,7 @@ static status_t save_key(private_rsa_public_key_t *this, char *file) /** * Implementation of rsa_public_key.get_modulus. */ -static mpz_t *get_modulus(private_rsa_public_key_t *this) +static mpz_t *get_modulus(const private_rsa_public_key_t *this) { return &this->n; } @@ -329,7 +329,7 @@ static mpz_t *get_modulus(private_rsa_public_key_t *this) /** * Implementation of rsa_public_key.get_keysize. */ -static size_t get_keysize(private_rsa_public_key_t *this) +static size_t get_keysize(const private_rsa_public_key_t *this) { return this->k; } @@ -337,7 +337,7 @@ static size_t get_keysize(private_rsa_public_key_t *this) /** * Implementation of rsa_public_key.get_keyid. */ -static chunk_t get_keyid(private_rsa_public_key_t *this) +static chunk_t get_keyid(const private_rsa_public_key_t *this) { return this->keyid; } @@ -345,7 +345,7 @@ static chunk_t get_keyid(private_rsa_public_key_t *this) /** * Implementation of rsa_public_key.clone. */ -static rsa_public_key_t* _clone(private_rsa_public_key_t *this) +static rsa_public_key_t* _clone(const private_rsa_public_key_t *this) { private_rsa_public_key_t *clone = rsa_public_key_create_empty(); @@ -376,13 +376,13 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void) private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t); /* public functions */ - this->public.verify_emsa_pkcs1_signature = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature; - this->public.get_key = (status_t (*) (rsa_public_key_t*,chunk_t*))get_key; - this->public.save_key = (status_t (*) (rsa_public_key_t*,char*))save_key; - this->public.get_modulus = (mpz_t *(*) (rsa_public_key_t*))get_modulus; - this->public.get_keysize = (size_t (*) (rsa_public_key_t*))get_keysize; - this->public.get_keyid = (chunk_t (*) (rsa_public_key_t*))get_keyid; - this->public.clone = (rsa_public_key_t* (*) (rsa_public_key_t*))_clone; + this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature; + this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key; + this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key; + this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus; + this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize; + this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid; + this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone; this->public.destroy = (void (*) (rsa_public_key_t*))destroy; /* private functions */ diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h index 61796aec9..62bdd7db5 100644 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.h +++ b/src/libstrongswan/crypto/rsa/rsa_public_key.h @@ -67,7 +67,7 @@ struct rsa_public_key_t { * - INVALID_ARG, if signature is not a signature * - FAILED if signature invalid or unable to verify */ - status_t (*verify_emsa_pkcs1_signature) (rsa_public_key_t *this, chunk_t data, chunk_t signature); + status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, chunk_t data, chunk_t signature); /** * @brief Gets the key. @@ -83,7 +83,7 @@ struct rsa_public_key_t { * - SUCCESS * - INVALID_STATE, if key not set */ - status_t (*get_key) (rsa_public_key_t *this, chunk_t *key); + status_t (*get_key) (const rsa_public_key_t *this, chunk_t *key); /** * @brief Saves a key to a file. @@ -94,7 +94,7 @@ struct rsa_public_key_t { * @param file file to which the key should be written. * @return NOT_SUPPORTED */ - status_t (*save_key) (rsa_public_key_t *this, char *file); + status_t (*save_key) (const rsa_public_key_t *this, char *file); /** * @brief Get the modulus of the key. @@ -102,7 +102,7 @@ struct rsa_public_key_t { * @param this calling object * @return modulus (n) of the key */ - mpz_t *(*get_modulus) (rsa_public_key_t *this); + mpz_t *(*get_modulus) (const rsa_public_key_t *this); /** * @brief Get the size of the modulus in bytes. @@ -110,7 +110,7 @@ struct rsa_public_key_t { * @param this calling object * @return size of the modulus (n) in bytes */ - size_t (*get_keysize) (rsa_public_key_t *this); + size_t (*get_keysize) (const rsa_public_key_t *this); /** * @brief Get the keyid formed as the SHA-1 hash of a publicKeyInfo object. @@ -118,7 +118,7 @@ struct rsa_public_key_t { * @param this calling object * @return keyid in the form of a SHA-1 hash */ - chunk_t (*get_keyid) (rsa_public_key_t *this); + chunk_t (*get_keyid) (const rsa_public_key_t *this); /** * @brief Clone the public key. @@ -126,7 +126,7 @@ struct rsa_public_key_t { * @param this public key to clone * @return clone of this */ - rsa_public_key_t *(*clone) (rsa_public_key_t *this); + rsa_public_key_t *(*clone) (const rsa_public_key_t *this); /** * @brief Destroys the public key. diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c index 905fc4c95..c65071c72 100755 --- a/src/libstrongswan/crypto/x509.c +++ b/src/libstrongswan/crypto/x509.c @@ -73,6 +73,11 @@ struct private_x509_t { */ time_t installed; + /** + * Time until certificate can be trusted + */ + time_t until; + /** * X.509 Certificate in DER format */ @@ -909,6 +914,14 @@ static bool is_ca(const private_x509_t *this) return this->isCA; } +/** + * Implements x509_t.is_self_signed + */ +static bool is_self_signed(const private_x509_t *this) +{ + return this->subject->equals(this->subject, this->issuer); +} + /** * Implements x509_t.equals_subjectAltName */ @@ -932,6 +945,17 @@ static bool equals_subjectAltName(const private_x509_t *this, identification_t * return found; } +/** + * Implements x509_t.is_issuer + */ +static bool is_issuer(const private_x509_t *this, const private_x509_t *issuer) +{ + return (this->authKeyID.ptr) + ? chunk_equals(this->authKeyID, issuer->subjectKeyID) + : (this->issuer->equals(this->issuer, issuer->subject) + && chunk_equals_or_null(this->authKeySerialNumber, issuer->serialNumber)); +} + /** * Implements x509_t.get_public_key */ @@ -940,6 +964,30 @@ static rsa_public_key_t *get_public_key(const private_x509_t *this) return this->public_key->clone(this->public_key); } +/** + * Implements x509_t.get_serialNumber + */ +static chunk_t get_serialNumber(const private_x509_t *this) +{ + return this->serialNumber; +} + +/** + * Implements x509_t.get_subjectKeyID + */ +static chunk_t get_subjectKeyID(const private_x509_t *this) +{ + return this->subjectKeyID; +} + +/** + * Implements x509_t.get_issuer + */ +static identification_t *get_issuer(const private_x509_t *this) +{ + return this->issuer; +} + /** * Implements x509_t.get_subject */ @@ -949,11 +997,19 @@ static identification_t *get_subject(const private_x509_t *this) } /** - * Implements x509_t.get_issuer + * Implements x509_t.set_until */ -static identification_t *get_issuer(const private_x509_t *this) +static void set_until(private_x509_t *this, time_t until) { - return this->issuer; + this->until = until; +} + +/** + * Implements x509_t.verify + */ +static bool verify(const private_x509_t *this, const rsa_public_key_t *signer) +{ + return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature); } /** @@ -1060,8 +1116,11 @@ static void log_certificate(const private_x509_t *this, logger_t *logger, bool u logger->log(logger, CONTROL, " not after %s %s", buf, check_expiry(this->notAfter, CERT_WARNING_INTERVAL, TRUE)); - logger->log(logger, CONTROL, " pubkey: RSA %d bits%s", - BITS_PER_BYTE * pubkey->get_keysize(pubkey), has_key? ", has private key":""); + timetoa(buf, BUF_LEN, &this->until, utc); + logger->log(logger, CONTROL, " pubkey: RSA %d bits%s, until %s", + BITS_PER_BYTE * pubkey->get_keysize(pubkey), + has_key? ", has private key":"", buf); + chunk_to_hex(buf, BUF_LEN, pubkey->get_keyid(pubkey)); logger->log(logger, CONTROL, " keyid: %s", buf); @@ -1103,12 +1162,18 @@ x509_t *x509_create_from_chunk(chunk_t chunk) /* public functions */ this->public.equals = (bool (*) (const x509_t*,const x509_t*))equals; this->public.equals_subjectAltName = (bool (*) (const x509_t*,identification_t*))equals_subjectAltName; + this->public.is_issuer = (bool (*) (const x509_t*,const x509_t*))is_issuer; this->public.is_valid = (err_t (*) (const x509_t*,time_t*))is_valid; this->public.is_ca = (bool (*) (const x509_t*))is_ca; - this->public.destroy = (void (*) (x509_t*))destroy; + this->public.is_self_signed = (bool (*) (const x509_t*))is_self_signed; this->public.get_public_key = (rsa_public_key_t* (*) (const x509_t*))get_public_key; - this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject; + this->public.get_serialNumber = (chunk_t (*) (const x509_t*))get_serialNumber; + this->public.get_subjectKeyID = (chunk_t (*) (const x509_t*))get_subjectKeyID; this->public.get_issuer = (identification_t* (*) (const x509_t*))get_issuer; + this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject; + this->public.set_until = (void (*) (x509_t*,time_t))set_until; + this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify; + this->public.destroy = (void (*) (x509_t*))destroy; this->public.log_certificate = (void (*) (const x509_t*,logger_t*,bool,bool))log_certificate; /* we do not use a per-instance logger right now, since its not always accessible */ @@ -1127,7 +1192,8 @@ x509_t *x509_create_from_chunk(chunk_t chunk) destroy(this); return NULL; } - + /* set trusted lifetime of public key to notAfter */ + this->until = this->notAfter; return &this->public; } diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h index 9f0bbf426..a4451eb41 100755 --- a/src/libstrongswan/crypto/x509.h +++ b/src/libstrongswan/crypto/x509.h @@ -48,6 +48,14 @@ typedef struct x509_t x509_t; */ struct x509_t { + /** + * @brief Set trusted public key life. + * + * @param this calling object + * @param until time until public key is trusted + */ + void (*set_until) (x509_t *this, time_t until); + /** * @brief Get the RSA public key from the certificate. * @@ -55,9 +63,25 @@ struct x509_t { * @return public_key */ rsa_public_key_t *(*get_public_key) (const x509_t *this); + + /** + * @brief Get serial number from the certificate. + * + * @param this calling object + * @return serialNumber + */ + chunk_t (*get_serialNumber) (const x509_t *this); /** - * @brief Get the certificate issuers ID. + * @brief Get serial number from the certificate. + * + * @param this calling object + * @return subjectKeyID + */ + chunk_t (*get_subjectKeyID) (const x509_t *this); + + /** + * @brief Get the certificate issuer's ID. * * The resulting ID is always a identification_t * of type ID_DER_ASN1_DN. @@ -81,19 +105,10 @@ struct x509_t { /** * @brief Check if a certificate is trustworthy * - * Use the issuer's public key to verify - * the trustworthiness of a certificate. - * - * @todo implement! + * @param this calling object + * @param signer signer's RSA public key */ - bool (*verify) (const x509_t *this, rsa_public_key_t *signer); - - /** - * @brief Get the key identifier of the public key. - * - * @todo implement! - */ - chunk_t (*get_subject_key_identifier) (const x509_t *this); + bool (*verify) (const x509_t *this, const rsa_public_key_t *signer); /** * @brief Compare two certificates. @@ -102,7 +117,7 @@ struct x509_t { * * @param this first cert for compare * @param other second cert for compare - * @return TRUE if signature is equal + * @return TRUE if signature is equal */ bool (*equals) (const x509_t *this, const x509_t *that); @@ -111,16 +126,25 @@ struct x509_t { * * @param this certificate being examined * @param id id which is being compared to the subjectAltNames - * @return TRUE if a match is found + * @return TRUE if a match is found */ bool (*equals_subjectAltName) (const x509_t *this, identification_t *id); + /** + * @brief Checks if the subject of the other cert is the issuer of this cert. + * + * @param this certificate + * @param issuer potential issuer certificate + * @return TRUE if issuer is found + */ + bool (*is_issuer) (const x509_t *this, const x509_t *issuer); + /** * @brief Checks the validity interval of the certificate * * @param this certificate being examined * @param until until = min(until, notAfter) - * @return NULL if the certificate is valid + * @return NULL if the certificate is valid */ err_t (*is_valid) (const x509_t *this, time_t *until); @@ -128,10 +152,18 @@ struct x509_t { * @brief Returns the CA basic constraints flag * * @param this certificate being examined - * @return TRUE if the CA flag is set + * @return TRUE if the CA flag is set */ bool (*is_ca) (const x509_t *this); + /** + * @brief Checks if the certificate is self-signed (subject equals issuer) + * + * @param this certificate being examined + * @return TRUE if self-signed + */ + bool (*is_self_signed) (const x509_t *this); + /** * @brief Destroys the certificate. * @@ -154,7 +186,7 @@ struct x509_t { * @brief Read a x509 certificate from a DER encoded blob. * * @param chunk chunk containing DER encoded data - * @return created x509_t certificate, or NULL if invalid. + * @return created x509_t certificate, or NULL if invlid. * * @ingroup transforms */ diff --git a/src/libstrongswan/definitions.c b/src/libstrongswan/definitions.c index 59c97a29b..c6cabe5f6 100644 --- a/src/libstrongswan/definitions.c +++ b/src/libstrongswan/definitions.c @@ -20,6 +20,8 @@ * for more details. */ +#include + #include "definitions.h" /* @@ -38,3 +40,19 @@ char *mapping_find(mapping_t * maps, int value) } return "INVALID MAPPING"; } + +/* + * Described in header + */ +const char *enum_name(enum_names *ed, unsigned long val) +{ + enum_names *p; + + for (p = ed; p != NULL; p = p->en_next_range) + { + if (p->en_first <= val && val <= p->en_last) + return p->en_names[val - p->en_first]; + } + return NULL; +} + diff --git a/src/libstrongswan/definitions.h b/src/libstrongswan/definitions.h index b8e6ba906..001f5f3b9 100644 --- a/src/libstrongswan/definitions.h +++ b/src/libstrongswan/definitions.h @@ -135,4 +135,22 @@ struct mapping_t */ char *mapping_find(mapping_t *mappings, int value); +/** + * @brief Describes an enumeration + * enum_name() returns the name of an enum value, or NULL if invalid. + */ +typedef const struct enum_names enum_names; + +struct enum_names { + unsigned long en_first; /* first value in range */ + unsigned long en_last; /* last value in range (inclusive) */ + const char *const *en_names; + enum_names *en_next_range; /* descriptor of next range */ +}; + +/** + * @brief Returns the name of an enum value, or NULL if invalid + */ +const char *enum_name(enum_names *ed, unsigned long val); + #endif /*DEFINITIONS_H_*/ diff --git a/src/libstrongswan/types.h b/src/libstrongswan/types.h index 0a1ea08a0..e18010561 100644 --- a/src/libstrongswan/types.h +++ b/src/libstrongswan/types.h @@ -109,23 +109,6 @@ enum status_t { CREATED, }; -/** - * RFC 2459 CRL reason codes - */ - -/* TODO extern enum_names crl_reason_names; */ - -typedef enum { - REASON_UNSPECIFIED = 0, - REASON_KEY_COMPROMISE = 1, - REASON_CA_COMPROMISE = 2, - REASON_AFFILIATION_CHANGED = 3, - REASON_SUPERSEDED = 4, - REASON_CESSATION_OF_OPERATON = 5, - REASON_CERTIFICATE_HOLD = 6, - REASON_REMOVE_FROM_CRL = 8 -} crl_reason_t; - /** * String mappings for type status_t. */