caching of ocsp responses (experimental), no crl caching yet
authorMartin Willi <martin@strongswan.org>
Wed, 26 Mar 2008 15:21:50 +0000 (15:21 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 26 Mar 2008 15:21:50 +0000 (15:21 -0000)
12 files changed:
src/charon/credentials/credential_manager.c
src/charon/credentials/sets/cert_cache.c
src/libstrongswan/Makefile.am
src/libstrongswan/credentials/certificates/ac.h
src/libstrongswan/credentials/certificates/certificate.c
src/libstrongswan/credentials/certificates/certificate.h
src/libstrongswan/credentials/certificates/ocsp_request.c [deleted file]
src/libstrongswan/plugins/x509/x509_ac.c
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/plugins/x509/x509_crl.c
src/libstrongswan/plugins/x509/x509_ocsp_request.c
src/libstrongswan/plugins/x509/x509_ocsp_response.c

index 34a801e..35816a8 100644 (file)
@@ -331,6 +331,7 @@ static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
        request->destroy(request);
 
        DBG1(DBG_CFG, "requesting ocsp status from '%s' ...", url);
+       /* TODO: unlock manager while fetching? */
        if (lib->fetcher->fetch(lib->fetcher, url, &receive, 
                                                        FETCH_REQUEST_DATA, send,
                                                        FETCH_REQUEST_TYPE, "application/ocsp-request",
@@ -350,50 +351,111 @@ static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
                DBG1(DBG_CFG, "parsing ocsp response failed");
                return NULL;
        }
+       return response;
+}
+
+/**
+ * check the signature of an OCSP response 
+ */
+static bool check_ocsp_response(private_credential_manager_t *this,
+                                                           ocsp_response_t *response)
+{
+       certificate_t *issuer, *subject;
+       identification_t *responder;
+       auth_info_t *auth;
+       ocsp_response_wrapper_t *wrapper;
+
+       auth = auth_info_create();
+       wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
+       this->sets->remove(this->sets, this->cache, NULL);
+       this->sets->insert_first(this->sets, wrapper);
+       this->sets->insert_first(this->sets, this->cache);
+       
+       subject = &response->certificate;
+       responder = subject->get_issuer(subject);
+       issuer = get_trusted_cert(this, KEY_ANY, responder, auth, FALSE, FALSE);
        
+       this->sets->remove(this->sets, wrapper, NULL);
+       wrapper->destroy(wrapper);
+       auth->destroy(auth);
 
-       /* verify the signature of the ocsp response */
+       if (!issuer)
        {
-               certificate_t *issuer_cert;
-               identification_t *responder;
-               auth_info_t *auth;
-               ocsp_response_wrapper_t *wrapper;
-               auth = auth_info_create();
-               wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
-               this->sets->remove(this->sets, this->cache, NULL);
-               this->sets->insert_first(this->sets, wrapper);
-               this->sets->insert_first(this->sets, this->cache);
-               responder = response->get_issuer(response);
-               DBG1(DBG_CFG, "  ocsp signer is \"%D\"", responder);
-               issuer_cert = get_trusted_cert(this, KEY_ANY, responder, auth, FALSE, FALSE);
-               this->sets->remove(this->sets, wrapper, NULL);
-               wrapper->destroy(wrapper);
-               auth->destroy(auth);
+               DBG1(DBG_CFG, "OCSP response verification failed, responder cert missing");
+               return FALSE;
+       }
+       if (!this->cache->issued_by(this->cache, subject, issuer))
+       {
+               DBG1(DBG_CFG, "OCSP response verification failed");
+               issuer->destroy(issuer);
+               return FALSE;
+       }
+       issuer->destroy(issuer);
+       return TRUE;
+}
 
-               if (!issuer_cert)
+/**
+ * Get the better of two OCSP responses, and check for usable OCSP info
+ */
+static certificate_t *get_better_ocsp(private_credential_manager_t *this,
+                                                                         certificate_t *cand, certificate_t *best,
+                                                                         x509_t *subject, x509_t *issuer,
+                                                                         cert_validation_t *valid)
+{
+       ocsp_response_t *response;
+       time_t revocation, this_update, next_update, valid_until;
+       crl_reason_t reason;
+       
+       response = (ocsp_response_t*)cand;
+
+       /* check ocsp signature */
+       if (!check_ocsp_response(this, response))
+       {
+               cand->destroy(cand);
+               return best;
+       }
+       /* check if response contains our certificate */
+       switch (response->get_status(response, subject, issuer, &revocation, &reason,
+                                                                &this_update, &next_update))
+       {
+               case VALIDATION_REVOKED:
+                       /* subject has been revoked by a valid OCSP response */
+                       DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
+                                                 &revocation, crl_reason_names, reason);
+                       DESTROY_IF(best);
+                       return cand;
+               case VALIDATION_GOOD:
+                       /* results in either good or stale */
+                       break;
+               default:
+               case VALIDATION_FAILED:
+                       /* candidate unusable, does not contain our cert */
+                       cand->destroy(cand);
+                       return best;
+       }
+
+       /* select the better of the two responses */
+       if (best == NULL || cand->is_newer(cand, best))
+       {
+               DESTROY_IF(best);
+               best = cand;
+               if (best->get_validity(best, NULL, NULL, &valid_until))
                {
-                       DBG1(DBG_CFG, "ocsp response untrusted: no signer certificate found");
-                       response->destroy(response);
-                       return NULL;
-               }
-               if (this->cache->issued_by(this->cache, response, issuer_cert))
-               {
-                       DBG1(DBG_CFG, "  ocsp response correctly signed by \"%D\"",
-                                                  issuer_cert->get_subject(issuer_cert));
-                       issuer_cert->destroy(issuer_cert);
+                       DBG1(DBG_CFG, "  ocsp response is valid: until %#T", &valid_until);
+                       *valid = VALIDATION_GOOD;
                }
                else
                {
-                       DBG1(DBG_CFG, "ocsp response not accepted from \"%D\"",
-                                                  issuer_cert->get_subject(issuer_cert));
-                       issuer_cert->destroy(issuer_cert);
-                       response->destroy(response);
-                       return NULL;
+                       DBG1(DBG_CFG, "  ocsp response is stale: since %#T", &valid_until);
+                       *valid = VALIDATION_STALE;
                }
        }
-       /* TODO: cache response? */
-       return response;
+       else
+       {
+               *valid = VALIDATION_STALE;
+               cand->destroy(cand);
+       }
+       return best;
 }
 
 /**
@@ -403,92 +465,49 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this,
                                                                    x509_t *subject, x509_t *issuer, 
                                                                    auth_info_t *auth)
 {
-       certificate_t *sub = (certificate_t*)subject;
-       certificate_t *best_cert = NULL;
-       certificate_t *cert;
-       public_key_t *public;
+       enumerator_t *enumerator;
        cert_validation_t valid = VALIDATION_SKIPPED;
+       certificate_t *best = NULL, *current;
        identification_t *keyid = NULL;
-       bool stale = TRUE;
-       
-       /* derive the authorityKeyIdentifier from the issuer's public key */
-       cert = &issuer->interface;
-       public = cert->get_public_key(cert);
-       if (public)
-       {
-               keyid = public->get_id(public, ID_PUBKEY_SHA1);
-       }
-       
-       /* find a cached ocsp response by authorityKeyIdentifier */     
-       if (keyid)
-       {
-               enumerator_t *enumerator = create_cert_enumerator(this,
-                                                                                CERT_X509_OCSP_RESPONSE,
-                                                                                KEY_ANY, keyid, TRUE);
-               certificate_t *cert;
+       public_key_t *public;
+       char *uri = NULL;
 
-               while (enumerator->enumerate(enumerator, &cert))
+       /** lookup cache for valid OCSP responses */
+       enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE,
+                                                                               KEY_ANY, NULL, FALSE);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               current->get_ref(current);
+               best = get_better_ocsp(this, current, best, subject, issuer, &valid);
+               if (best && valid != VALIDATION_STALE)
                {
-                       if (cert->has_subject(cert, sub->get_subject(sub)))
-                       {
-                               /* select most recent ocsp response */
-                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
-                               {
-                                       DESTROY_IF(best_cert);
-                                       best_cert = cert->get_ref(cert);
-                               }
-                       }
+                       DBG1(DBG_CFG, "  used cached ocsp response");
+                       break;
                }
-               enumerator->destroy(enumerator);
        }
-
-       /* check the validity of the cached ocsp response if one was found */
-       if (best_cert)
+       enumerator->destroy(enumerator);
+       
+       /* derive the authorityKeyIdentifier from the issuer's public key */
+       current = &issuer->interface;
+       public = current->get_public_key(current);
+       if (public)
        {
-               time_t nextUpdate;
-
-               stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
-               DBG1(DBG_CFG, "cached ocsp response is %s %#T",
-                                          stale? "stale: since":"valid: until",
-                                          &nextUpdate, FALSE );
+               keyid = public->get_id(public, ID_PUBKEY_SHA1);
        }
-
-       /* fallback to URL fetching from CDPs */
-       if (stale && keyid)
+       /** fetch from configured OCSP responder URLs */
+       if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
        {
-               enumerator_t *enumerator = create_cdp_enumerator(this,
-                                                                                CERT_X509_OCSP_RESPONSE, keyid);
-               char *uri;
-
+               enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid);
                while (enumerator->enumerate(enumerator, &uri))
                {
-                       certificate_t* cert = fetch_ocsp(this, uri, &subject->interface,
-                                                                                                               &issuer->interface);
-
-                       /* redefine default since we have at least one uri */
-                       valid = VALIDATION_FAILED;
-
-                       if (cert)
+                       current = fetch_ocsp(this, uri, &subject->interface,
+                                                                &issuer->interface);
+                       if (current)
                        {
-                               /* select most recent ocsp response until valid one is found */
-                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
+                               best = get_better_ocsp(this, current, best, subject, issuer, &valid);
+                               if (best && valid != VALIDATION_STALE)
                                {
-                                       time_t nextUpdate;
-
-                                       DESTROY_IF(best_cert);
-                                       best_cert = cert;
-                                       stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
-                                       DBG1(DBG_CFG, "ocsp response is %s %#T",
-                                                                  stale? "stale: since":"valid: until",
-                                                                  &nextUpdate, FALSE );
-                                       if (!stale)
-                                       {
-                                               break;
-                                       }
-                               }
-                               else
-                               {
-                                       cert->destroy(cert);
+                                       break;
                                }
                        }
                }
@@ -497,76 +516,34 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this,
        DESTROY_IF(public);
 
        /* fallback to URL fetching from subject certificate's URIs */
-       if (stale)
+       if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
        {
-               enumerator_t *enumerator = subject->create_ocsp_uri_enumerator(subject);
-               char *uri;
-
+               enumerator = subject->create_ocsp_uri_enumerator(subject);
                while (enumerator->enumerate(enumerator, &uri))
                {
-                       certificate_t* cert = fetch_ocsp(this, uri, &subject->interface,
-                                                                                                               &issuer->interface);
-
-                       /* redefine default since we have at least one uri */
-                       valid = VALIDATION_FAILED;
-
-                       if (cert)
+                       current = fetch_ocsp(this, uri, &subject->interface,
+                                                                &issuer->interface);
+                       if (current)
                        {
-                               /* select most recent ocsp response until valid one is found */
-                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
-                               {
-                                       time_t nextUpdate;
-
-                                       DESTROY_IF(best_cert);
-                                       best_cert = cert;
-                                       stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
-                                       DBG1(DBG_CFG, "ocsp response is %s %#T",
-                                                                  stale? "stale: since":"valid: until",
-                                                                  &nextUpdate, FALSE );
-                                       if (!stale)
-                                       {
-                                               break;
-                                       }
-                               }
-                               else
+                               best = get_better_ocsp(this, current, best, subject, issuer, &valid);
+                               if (best && valid != VALIDATION_STALE)
                                {
-                                       cert->destroy(cert);
+                                       break;
                                }
                        }
                }
                enumerator->destroy(enumerator);
        }
-
-       /* if we have an ocsp response, check the revocation status */
-       if (best_cert)
+       /* an uri was found, but no result. switch validation state to failed */
+       if (valid == VALIDATION_SKIPPED && uri)
        {
-               time_t revocation, this_update, next_update;
-               crl_reason_t reason;
-               ocsp_response_t *response = (ocsp_response_t*)best_cert;
-               
-               valid = response->get_status(response, subject, issuer, &revocation,
-                                                                        &reason, &this_update, &next_update);
-               switch (valid)
-               {
-                       case VALIDATION_FAILED:
-                               DBG1(DBG_CFG, "subject not found in ocsp response");
-                               break;
-                       case VALIDATION_REVOKED:
-                               DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
-                                                         &revocation, crl_reason_names, reason);
-                               break;
-                       case VALIDATION_GOOD:
-                       case VALIDATION_UNKNOWN:
-                       default:
-                               break;
-               }
-               best_cert->destroy(best_cert);
+               valid = VALIDATION_FAILED;
        }
-       
        if (auth)
        {
                auth->add_item(auth, AUTHZ_OCSP_VALIDATION, &valid);
        }
+       DESTROY_IF(best);
        return valid;
 }
 
@@ -771,7 +748,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
                enumerator_t *enumerator = crl->create_enumerator(crl);
 
                /* redefine default */
-               valid = stale ? VALIDATION_UNKNOWN : VALIDATION_GOOD;
+               valid = stale ? VALIDATION_STALE : VALIDATION_GOOD;
 
                while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
                {
@@ -831,8 +808,10 @@ static bool check_certificate(private_credential_manager_t *this,
                                case VALIDATION_SKIPPED:
                                        DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
                                        break;
+                               case VALIDATION_STALE:
+                                       DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
+                                       break;
                                case VALIDATION_FAILED:
-                               case VALIDATION_UNKNOWN:
                                        DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
                                        break;
                        }
@@ -847,14 +826,12 @@ static bool check_certificate(private_credential_manager_t *this,
                                case VALIDATION_REVOKED:                
                                        /* has already been logged */                   
                                        return FALSE;
-                               case VALIDATION_UNKNOWN:
-                                       DBG1(DBG_CFG, "certificate status is unknown");
-                                       break;
                                case VALIDATION_FAILED:
                                case VALIDATION_SKIPPED:
                                        DBG1(DBG_CFG, "certificate status is not available");
-                                       break;          
-                               default:
+                                       break;
+                               case VALIDATION_STALE:
+                                       DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
                                        break;
                        }
                }
@@ -993,8 +970,8 @@ static certificate_t *get_trusted_cert(private_credential_manager_t *this,
        subject = get_pretrusted_cert(this, type, id);
        if (subject)
        {
-
-               if (subject->issued_by(subject, subject, TRUE))
+               /* if we find a trusted self signed certificate, we just accept it */
+               if (this->cache->issued_by(this->cache, subject, subject))
                {
                        DBG1(DBG_CFG, "  using trusted self-signed certificate \"%D\"",
                                 subject->get_subject(subject));
index 17e6d35..5d49643 100644 (file)
@@ -93,7 +93,7 @@ static bool issued_by(private_cert_cache_t *this,
                return TRUE;
        }
        /* no cache hit, check signature */
-       if (!subject->issued_by(subject, issuer, TRUE))
+       if (!subject->issued_by(subject, issuer))
        {
                return FALSE;
        }
@@ -131,10 +131,9 @@ static bool certs_filter(cert_data_t *data, relation_t **in, certificate_t **out
        public_key_t *public;
        certificate_t *cert;
        
-       /* serve all subjects, but only if an ID is requestd (no listing) */
        cert = (*in)->subject;
        if ((data->cert == CERT_ANY || cert->get_type(cert) == data->cert) &&
-               data->id && cert->has_subject(cert, data->id))
+               (!data->id || cert->has_subject(cert, data->id)))
        {
                if (data->key == KEY_ANY)
                {
index 5f2169c..9b0417f 100644 (file)
@@ -36,7 +36,7 @@ credentials/certificates/certificate.c credentials/certificates/certificate.h \
 credentials/certificates/x509.h credentials/certificates/x509.c \
 credentials/certificates/ac.h \
 credentials/certificates/crl.h credentials/certificates/crl.c \
-credentials/certificates/ocsp_request.h credentials/certificates/ocsp_request.c \
+credentials/certificates/ocsp_request.h \
 credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \
 fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \
 database/database.h database/database_factory.h database/database_factory.c \
index 7a3b747..c9645d6 100644 (file)
@@ -51,7 +51,7 @@ struct ac_t {
         * @param that                  other attribute certificate
         * @return                              TRUE if same holder
         */
-       bool (*equals_holder) (const ac_t *this, const ac_t *other);
+       bool (*equals_holder) (ac_t *this, ac_t *other);
 };
 
 #endif /* AC_H_ @}*/
index 8d15947..1a83bdf 100644 (file)
@@ -32,10 +32,10 @@ ENUM(certificate_type_names, CERT_ANY, CERT_PGP,
 );
 
 ENUM(cert_validation_names, VALIDATION_GOOD, VALIDATION_SKIPPED,
-       "GOOD",
-       "REVOKED",
-       "UNKNOWN",
-       "FAILED",
-       "SKIPPED",
+       "VALIDATION_GOOD",
+       "VALIDATION_STALE",
+       "VALIDATION_REVOKED",
+       "VALIDATION_FAILED",
+       "VALIDATION_SKIPPED",
 );
 
index cc3f73a..14f4de3 100644 (file)
@@ -62,13 +62,13 @@ extern enum_name_t *certificate_type_names;
 enum cert_validation_t {
        /** certificate has been validated successfully */
        VALIDATION_GOOD,
-       /** validation failed, certificate is revoked */
+       /** certificate has been validated, but check based on stale information */
+       VALIDATION_STALE,
+       /** certificate has been revoked */
        VALIDATION_REVOKED,
-       /* ocsp status is unknown or crl is stale */
-       VALIDATION_UNKNOWN,
-       /** validation process failed due to an error */
+       /** validation failed due to a processing error */
        VALIDATION_FAILED,
-       /** validation has been skipped (no cdps available) */
+       /** validation has been skipped due to missing validation information */
        VALIDATION_SKIPPED,
 };
 
@@ -129,17 +129,12 @@ struct certificate_t {
        id_match_t (*has_issuer)(certificate_t *this, identification_t *issuer);
        
        /**
-        * Check if this certificate is issued by a specific issuer.
+        * Check if this certificate is issued and signed by a specific issuer.
         *
-        * As signature verification is computional expensive, it is optional 
-        * and may be skipped. While this is not sufficient for verification
-        * purposes, it is to e.g. find matching certificates.
-        * 
         * @param issuer        issuer's certificate
-        * @param checksig      TRUE to verify signature, FALSE to compare issuer only
         * @return                      TRUE if certificate issued by issuer and trusted
         */
-       bool (*issued_by)(certificate_t *this, certificate_t *issuer, bool checksig);
+       bool (*issued_by)(certificate_t *this, certificate_t *issuer);
        
        /**
         * Get the public key associated to this certificate.
diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.c b/src/libstrongswan/credentials/certificates/ocsp_request.c
deleted file mode 100644 (file)
index 0958be4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- *
- * $Id$
- */
-
-#include "ocsp_request.h"
-
index 42dbc94..f90197b 100644 (file)
@@ -714,8 +714,7 @@ static id_match_t has_issuer(private_x509_ac_t *this, identification_t *issuer)
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_ac_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_ac_t *this, certificate_t *issuer)
 {
        public_key_t *key;
        signature_scheme_t scheme;
@@ -753,11 +752,6 @@ static bool issued_by(private_x509_ac_t *this, certificate_t *issuer,
                        return FALSE;
                }
        }
-
-       if (!sigcheck)
-       {
-               return TRUE;
-       }
        /* TODO: generic OID to scheme mapper? */
        switch (this->algorithm)
        {
@@ -912,7 +906,7 @@ static private_x509_ac_t *create_empty(void)
        this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject;
        this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
        this->public.interface.certificate.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
index dcd393c..ab32e13 100644 (file)
@@ -932,8 +932,7 @@ static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_cert_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_cert_t *this, certificate_t *issuer)
 {
        public_key_t *key;
        signature_scheme_t scheme;
@@ -962,10 +961,6 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer,
        {
                return FALSE;
        }
-       if (!sigcheck)
-       {
-               return TRUE;
-       }
        /* TODO: generic OID to scheme mapper? */
        switch (this->algorithm)
        {
@@ -1174,7 +1169,7 @@ static private_x509_cert_t* create_empty(void)
        this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
        this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
        this->public.interface.interface.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
@@ -1220,7 +1215,7 @@ static private_x509_cert_t *create_from_chunk(chunk_t chunk)
        }
 
        /* check if the certificate is self-signed */
-       if (issued_by(this, &this->public.interface.interface, TRUE))
+       if (issued_by(this, &this->public.interface.interface))
        {
                this->flags |= X509_SELF_SIGNED;
        }
index d59b153..a287197 100644 (file)
@@ -362,15 +362,7 @@ static certificate_type_t get_type(private_x509_crl_t *this)
 }
 
 /**
- * Implementation of certificate_t.get_subject
- */
-static identification_t* get_subject(private_x509_crl_t *this)
-{
-       return this->issuer;
-}
-
-/**
- * Implementation of certificate_t.get_issuer
+ * Implementation of certificate_t.get_issuer and get_subject
  */
 static identification_t* get_issuer(private_x509_crl_t *this)
 {
@@ -378,15 +370,7 @@ static identification_t* get_issuer(private_x509_crl_t *this)
 }
 
 /**
- * Implementation of certificate_t.has_subject.
- */
-static id_match_t has_subject(private_x509_crl_t *this, identification_t *subject)
-{
-       return ID_MATCH_NONE;   
-}
-
-/**
- * Implementation of certificate_t.has_issuer.
+ * Implementation of certificate_t.has_subject and has_issuer.
  */
 static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer)
 {
@@ -413,8 +397,7 @@ static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer)
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_crl_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_crl_t *this, certificate_t *issuer)
 {
        public_key_t *key;
        signature_scheme_t scheme;
@@ -452,11 +435,6 @@ static bool issued_by(private_x509_crl_t *this, certificate_t *issuer,
                        return FALSE;
                }
        }
-
-       if (!sigcheck)
-       {
-               return TRUE;
-       }
        /* TODO: generic OID to scheme mapper? */
        switch (this->algorithm)
        {
@@ -616,11 +594,11 @@ static private_x509_crl_t* create_empty(void)
        this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier;
        this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator;
        this->public.crl.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
-       this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
+       this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.crl.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
-       this->public.crl.certificate.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
+       this->public.crl.certificate.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_issuer;
        this->public.crl.certificate.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.crl.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.crl.certificate.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
        this->public.crl.certificate.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
index 7e32304..957df24 100644 (file)
@@ -378,8 +378,7 @@ static id_match_t has_issuer(private_x509_ocsp_request_t *this,
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_ocsp_request_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_ocsp_request_t *this, certificate_t *issuer)
 {
        DBG1("OCSP request validation not implemented!");
        return FALSE;
@@ -482,7 +481,7 @@ static private_x509_ocsp_request_t *create_empty()
        this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.interface.interface.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject;
        this->public.interface.interface.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.interface.interface.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
        this->public.interface.interface.get_encoding = (chunk_t(*)(certificate_t*))get_encoding;
index cf1de6b..0c1eb85 100644 (file)
 #include <credentials/certificates/x509.h>
 #include <credentials/certificates/crl.h>
 
+/**
+ * how long do we use an OCSP response without a nextUpdate
+ */
+#define OCSP_DEFAULT_LIFETIME 30
+
 typedef struct private_x509_ocsp_response_t private_x509_ocsp_response_t;
 
 /**
@@ -58,10 +63,7 @@ struct private_x509_ocsp_response_t {
        int signatureAlgorithm;
        
        /**
-        * signature    enumerator = this->responses->create_enumerator(this->responses);
-       while (enumerator->enumerate(enumerator, &response))
-       {
- value
+        * signature
         */
        chunk_t signature;
        
@@ -76,6 +78,11 @@ struct private_x509_ocsp_response_t {
        time_t producedAt;
        
        /**
+        * latest nextUpdate in this OCSP response
+        */
+       time_t usableUntil;
+       
+       /**
         * list of included certificates
         */
        linked_list_t *certs;
@@ -382,8 +389,9 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this,
        response->status = VALIDATION_FAILED;
        response->revocationTime = 0;
        response->revocationReason = CRL_UNSPECIFIED;
-       response->thisUpdate = 0;
-       response->nextUpdate = 0;
+       response->thisUpdate = UNDEFINED_TIME;
+       /* if nextUpdate is missing, we give it a short lifetime */
+       response->nextUpdate = this->producedAt + OCSP_DEFAULT_LIFETIME;
 
        asn1_init(&ctx, blob, level0, FALSE, FALSE);
        while (objectID < SINGLE_RESPONSE_ROOF)
@@ -423,17 +431,25 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this,
                                }
                        break;
                        case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
-                               response->status = VALIDATION_UNKNOWN;
+                               response->status = VALIDATION_FAILED;
                                break;
                        case SINGLE_RESPONSE_THIS_UPDATE:
                                response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
                                break;
                        case SINGLE_RESPONSE_NEXT_UPDATE:
                                response->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
+                               if (response->nextUpdate > this->usableUntil)
+                               {
+                                       this->usableUntil = response->nextUpdate;
+                               }
                        break;
                }
                objectID++;
        }
+       if (this->usableUntil == UNDEFINED_TIME)
+       {
+               this->usableUntil = this->producedAt + OCSP_DEFAULT_LIFETIME;
+       }
        this->responses->insert_last(this->responses, response);
        return TRUE;
 }
@@ -643,8 +659,7 @@ static id_match_t has_issuer(private_x509_ocsp_response_t *this,
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer)
 {
        public_key_t *key;
        signature_scheme_t scheme;
@@ -685,10 +700,6 @@ static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer,
        {
                return FALSE;
        }
-       if (!sigcheck)
-       {
-               return TRUE;
-       }
        /* TODO: generic OID to scheme mapper? */
        switch (this->signatureAlgorithm)
        {
@@ -734,19 +745,7 @@ static public_key_t* get_public_key(private_x509_ocsp_response_t *this)
 static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
                                                 time_t *not_before, time_t *not_after)
 {
-       enumerator_t *enumerator;
-       single_response_t *response;
-       time_t thisUpdate = this->producedAt;
-       time_t nextUpdate = 0;
        time_t t;
-       
-       enumerator = this->responses->create_enumerator(this->responses);
-       if (enumerator->enumerate(enumerator, &response))
-       {
-               thisUpdate = response->thisUpdate;
-               nextUpdate = response->nextUpdate;
-       }
-       enumerator->destroy(enumerator);
 
        if (when == NULL)
        {
@@ -758,13 +757,13 @@ static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
        }
        if (not_before)
        {
-               *not_before = thisUpdate;
+               *not_before = this->producedAt;
        }
        if (not_after)
        {
-               *not_after = nextUpdate;
+               *not_after = this->usableUntil;
        }
-       return (t < nextUpdate);
+       return (t < this->usableUntil);
 }
 
 /**
@@ -853,7 +852,7 @@ static x509_ocsp_response_t *load(chunk_t data)
        this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_issuer;
        this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
        this->public.interface.certificate.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
@@ -869,6 +868,7 @@ static x509_ocsp_response_t *load(chunk_t data)
        this->tbsResponseData = chunk_empty;
        this->responderId = NULL;
        this->producedAt = UNDEFINED_TIME;
+       this->usableUntil = UNDEFINED_TIME;
        this->responses = linked_list_create();
        this->nonce = chunk_empty;
        this->signatureAlgorithm = OID_UNKNOWN;