made is_newer() a certificate_t method
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 18 Mar 2008 10:36:08 +0000 (10:36 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 18 Mar 2008 10:36:08 +0000 (10:36 -0000)
src/charon/credentials/credential_manager.c
src/charon/plugins/stroke/stroke.c
src/libstrongswan/credentials/certificates/certificate.h
src/libstrongswan/credentials/certificates/crl.h
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/plugins/x509/x509_crl.c
src/libstrongswan/plugins/x509/x509_ocsp_response.c

index f694556..387c5ad 100644 (file)
@@ -414,8 +414,8 @@ static ocsp_wrapper_t *ocsp_wrapper_create(ocsp_response_t *response)
 /**
  * Do an OCSP request
  */
-static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url,
-                                                                  certificate_t *subject, certificate_t *issuer)
+static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
+                                                                certificate_t *subject, certificate_t *issuer)
 {
        certificate_t *request, *response, *issuer_cert;
        chunk_t send, receive;
@@ -430,7 +430,7 @@ static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url
                                                BUILD_CERT, subject->get_ref(subject), BUILD_END);
        if (!request)
        {
-               DBG1(DBG_CFG, "generating OCSP request failed");
+               DBG1(DBG_CFG, "  generating ocsp request failed");
                return NULL;
        }
        
@@ -441,7 +441,7 @@ static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url
                                                        FETCH_REQUEST_TYPE, "application/ocsp-request",
                                                        FETCH_END) != SUCCESS)
        {
-               DBG1(DBG_CFG, "OCSP request to %s failed", url);
+               DBG1(DBG_CFG, "  ocsp request to %s failed", url);
                chunk_free(&send);
                return NULL;
        }
@@ -452,7 +452,7 @@ static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url
                                                                  BUILD_BLOB_ASN1_DER, receive, BUILD_END);
        if (!response)
        {
-               DBG1(DBG_CFG, "parsing OCSP response from %s failed", url);
+               DBG1(DBG_CFG, "  parsing ocsp response failed");
                return NULL;
        }
        
@@ -466,14 +466,13 @@ static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url
        auth->destroy(auth);
        if (!issuer_cert)
        {
-               DBG1(DBG_CFG, "verifying OCSP response failed, no trusted "
-                        "certificate found");
+               DBG1(DBG_CFG, "  ocsp response untrusted: no signer certificate found");
                response->destroy(response);
                return NULL;
        }
        if (!response->issued_by(response, issuer_cert, TRUE))
        {
-               DBG1(DBG_CFG, "verifying OCSP response signature failed");
+               DBG1(DBG_CFG, "  ocsp response untrusted: bad signature");
                response->destroy(response);
                issuer_cert->destroy(issuer_cert);
                return NULL;
@@ -481,8 +480,7 @@ static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url
        issuer_cert->destroy(issuer_cert);
        
        /* TODO: cache response? */
-       
-       return (ocsp_response_t*)response;
+       return response;
 }
 
 /**
@@ -492,99 +490,155 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this,
                                                                    x509_t *subject, x509_t *issuer, 
                                                                    auth_info_t *auth)
 {
-       public_key_t *public;
-       enumerator_t *enumerator;
-       ocsp_response_t *response = NULL;
-       certificate_t *cert, *sub = (certificate_t*)subject;
+       certificate_t *sub = (certificate_t*)subject;
+       certificate_t *best_cert = NULL;
        cert_validation_t valid = VALIDATION_SKIPPED;
        identification_t *keyid = NULL;
-       char *url;
+       bool stale = TRUE;
        
-       cert = &issuer->interface;
-       public = cert->get_public_key(cert);
-       if (public)
+       /* derive the authorityKeyIdentifier from the issuer's public key */
        {
-               keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
+               certificate_t *cert = &issuer->interface;
+               public_key_t *public = cert->get_public_key(cert);
+
+               if (public)
+               {
+                       keyid = public->get_id(public, ID_PUBKEY_SHA1);
+                       public->destroy(public);
+               }
        }
-       
-       /* find a OCSP response by Authority key identifier (cache) */  
+
+       /* find a cached ocsp response by authorityKeyIdentifier */     
        if (keyid)
        {
-               time_t update, best_update = 0;
+               enumerator_t *enumerator = create_cert_enumerator(this,
+                                                                                CERT_X509_OCSP_RESPONSE,
+                                                                                KEY_ANY, keyid, TRUE);
+               certificate_t *cert;
 
-               enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE,
-                                                                                       KEY_ANY, keyid, TRUE);
                while (enumerator->enumerate(enumerator, &cert))
-               {       /* get newest valid response */
-                       if (cert->has_subject(cert, sub->get_subject(sub)) &&
-                               cert->get_validity(cert, NULL, &update, NULL) &&
-                               update > best_update)
+               {
+                       if (cert->has_subject(cert, sub->get_subject(sub)))
                        {
-                               best_update = update;
-                               DESTROY_IF(&response->certificate);
-                               response = (ocsp_response_t*)cert;
-                               valid = VALIDATION_FAILED;
+                               /* 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);
+                               }
                        }
                }
                enumerator->destroy(enumerator);
        }
+
+       /* check the validity of the cached ocsp response if one was found */
+       if (best_cert)
+       {
+               stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL);
+               DBG1(DBG_CFG, "cached ocsp response is %s", stale? "stale":"valid");
+       }
+
        /* fallback to URL fetching from CDPs */
-       if (!response && keyid)
+       if (stale && keyid)
        {
-               enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid);
-               while (enumerator->enumerate(enumerator, &url))
+               enumerator_t *enumerator = create_cdp_enumerator(this,
+                                                                                CERT_X509_OCSP_RESPONSE, keyid);
+               char *uri;
+
+               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;
-                       response = fetch_ocsp(this, url, &subject->interface, &issuer->interface);
-                       if (response)
+
+                       if (cert)
                        {
-                               break;
+                               /* select most recent ocsp response until valid one is found */
+                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
+                               {
+                                       DESTROY_IF(best_cert);
+                                       best_cert = cert;
+                                       stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL);
+                                       DBG1(DBG_CFG, "ocsp response is %s", stale? "stale":"valid");
+                                       if (!stale)
+                                       {
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       cert->destroy(cert);
+                               }
                        }
                }
                enumerator->destroy(enumerator);
        }
+
        /* fallback to URL fetching from subject certificate's URIs */
-       if (!response)
+       if (stale)
        {
-               enumerator = subject->create_ocsp_uri_enumerator(subject);
-               while (enumerator->enumerate(enumerator, &url))
+               enumerator_t *enumerator = subject->create_ocsp_uri_enumerator(subject);
+               char *uri;
+
+               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;
-                       response = fetch_ocsp(this, url, &subject->interface, &issuer->interface);
-                       if (response)
+
+                       if (cert)
                        {
-                               break;
+                               /* select most recent ocsp response until valid one is found */
+                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
+                               {
+                                       DESTROY_IF(best_cert);
+                                       best_cert = cert;
+                                       stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL);
+                                       DBG1(DBG_CFG, "ocsp response is %s", stale? "stale":"valid");
+                                       if (!stale)
+                                       {
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       cert->destroy(cert);
+                               }
                        }
                }
                enumerator->destroy(enumerator);
        }
-       /* look for subject in response */
-       if (response)
+
+       /* if we have an ocsp response, check the revocation status */
+       if (best_cert)
        {
                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");
+                               DBG1(DBG_CFG, "subject not found in ocsp response");
                                break;
                        case VALIDATION_REVOKED:
-                               DBG1(DBG_CFG, "certificate %D revoked by OCSP at %T: %N",
-                                        cert->get_subject(cert), &revocation,
-                                        crl_reason_names, reason);
+                               DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
+                                                         &revocation, crl_reason_names, reason);
                                break;
                        case VALIDATION_GOOD:
-                               break;
+                       case VALIDATION_UNKNOWN:
                        default:
                                break;
                }
-               cert = (certificate_t*)response;
-               cert->destroy(cert);
+               best_cert->destroy(best_cert);
        }
-       DESTROY_IF(public);
+
        if (auth)
        {
                auth->add_item(auth, AUTHZ_OCSP_VALIDATION, &valid);
@@ -668,7 +722,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
                }
        }
        
-       /* find a local crl by authorityKeyIdentifier */
+       /* find a cached crl by authorityKeyIdentifier */
        if (keyid)
        {
                enumerator_t *enumerator = create_cert_enumerator(this, CERT_X509_CRL,
@@ -677,11 +731,8 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
 
                while (enumerator->enumerate(enumerator, &cert))
                {
-                       crl_t *crl = (crl_t*)cert;
-                       crl_t *best_crl = (crl_t*)best_cert;
-       
                        /* select most recent crl */
-                       if (best_cert == NULL || crl->is_newer(crl, best_crl))
+                       if (best_cert == NULL || cert->is_newer(cert, best_cert))
                        {
                                DESTROY_IF(best_cert);
                                best_cert = cert->get_ref(cert);
@@ -690,15 +741,11 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
                enumerator->destroy(enumerator);
        }
 
-       /* check the validity of the local crl if one was found */
+       /* check the validity of the cached crl if one was found */
        if (best_cert)
        {
                stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL);
-               DBG1(DBG_CFG, "locally-stored crl is %s", stale? "stale":"valid");
-       }
-       else
-       {
-               DBG1(DBG_CFG, "no locally-stored crl found");
+               DBG1(DBG_CFG, "cached crl is %s", stale? "stale":"valid");
        }
 
        /* fallback to fetching crls from cdps defined in ca info sections */
@@ -717,11 +764,8 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
 
                        if (cert)
                        {
-                               crl_t *crl = (crl_t*)cert;
-                               crl_t *best_crl = (crl_t*)best_cert;
-
-                               /* select most recent crl */
-                               if (best_cert == NULL || crl->is_newer(crl, best_crl))
+                               /* select most recent crl until valid one is found */
+                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
                                {
                                        DESTROY_IF(best_cert);
                                        best_cert = cert;
@@ -756,11 +800,8 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
 
                        if (cert)
                        {
-                               crl_t *crl = (crl_t*)cert;
-                               crl_t *best_crl = (crl_t*)best_cert;
-
-                               /* select most recent crl */
-                               if (best_cert == NULL || crl->is_newer(crl, best_crl))
+                               /* select most recent crl until valid one is found */
+                               if (best_cert == NULL || cert->is_newer(cert, best_cert))
                                {
                                        DESTROY_IF(best_cert);
                                        best_cert = cert;
@@ -783,6 +824,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
        /* if we have a crl, check the revocation status */
        if (best_cert)
        {
+               chunk_t subject_serial = subject->get_serial(subject);
                chunk_t serial;
                time_t revocation;
                crl_reason_t reason;
@@ -794,7 +836,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
 
                while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
                {
-                       if (chunk_equals(serial, subject->get_serial(subject)))
+                       if (chunk_equals(serial, subject_serial))
                        {
                                DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
                                         &revocation, crl_reason_names, reason);
@@ -842,10 +884,11 @@ static bool check_certificate(private_credential_manager_t *this,
                        switch (check_ocsp(this, (x509_t*)subject, (x509_t*)issuer, auth))
                        {
                                case VALIDATION_GOOD:
-                                       DBG1(DBG_CFG, "certificate %D validated by OCSP",
+                                       DBG1(DBG_CFG, "certificate status is good",
                                                 subject->get_subject(subject));
                                        return TRUE;
                                case VALIDATION_REVOKED:
+                                       /* has already been logged */                   
                                        return FALSE;
                                case VALIDATION_SKIPPED:
                                        DBG2(DBG_CFG, "OCSP check skipped, no OCSP URI found");
index cfea918..c3ee330 100755 (executable)
@@ -853,7 +853,7 @@ static void add_crl(private_stroke_t *this, crl_t* crl)
                        }
                        if (found)
                        {
-                               new = crl->is_newer(crl, crl_c);
+                               new = cert->is_newer(cert, current);
                                if (new)
                                {
                                        this->creds.certs->remove_at(this->creds.certs, enumerator);
index 94f19a0..cc3f73a 100644 (file)
@@ -160,6 +160,13 @@ struct certificate_t {
                                                 time_t *not_before, time_t *not_after);
        
        /**
+        * Is this newer than that?
+        *
+        * @return                      TRUE if newer, FALSE otherwise
+        */
+       bool (*is_newer)(certificate_t *this, certificate_t *that);
+       
+       /**
         * Get the certificate in an encoded form.
         *
         * @return                              allocated chunk of encoded cert
index 752293f..16d9e24 100644 (file)
@@ -58,13 +58,6 @@ struct crl_t {
        certificate_t certificate;
        
        /**
-        * Is that newer than this?
-        *
-        * @return                      TRUE if newer, FALSE otherwise
-        */
-       bool (*is_newer)(crl_t *this, crl_t *that);
-       
-       /**
         * Get the CRL serial number.
         *
         * @return                      chunk pointing to internal crlNumber
index e85076d..a1d4109 100644 (file)
@@ -1035,16 +1035,33 @@ static bool get_validity(private_x509_cert_t *this, time_t *when,
        {
                t = time(NULL);
        }
-       if (not_after)
-       {
-               *not_after = this->notAfter;
-       }
        if (not_before)
        {
                *not_before = this->notBefore;
        }
+       if (not_after)
+       {
+               *not_after = this->notAfter;
+       }
        return (t >= this->notBefore && t <= this->notAfter);
 }
+
+/**
+ * Implementation of certificate_t.is_newer.
+ */
+static bool is_newer(certificate_t *this, certificate_t *that)
+{
+       time_t this_update, that_update, now = time(NULL);
+       bool new;
+
+       this->get_validity(this, &now, &this_update, NULL);
+       that->get_validity(that, &now, &that_update, NULL);
+       new = this_update > that_update;
+       DBG1("  certificate from %#T is %s - existing certificate from %#T %s",
+                               &this_update, FALSE, new ? "newer":"not newer",
+                               &that_update, FALSE, new ? "replaced":"retained");
+       return new;
+}
        
 /**
  * Implementation of certificate_t.get_encoding.
@@ -1155,6 +1172,7 @@ static private_x509_cert_t *load(chunk_t chunk)
        this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))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;
        this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
        this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
        this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
index 3c1a562..1748edb 100644 (file)
@@ -326,39 +326,6 @@ static bool filter(void *data, revoked_t **revoked, chunk_t *serial, void *p2,
 }
 
 /**
- * Implementation of crl_t.is_newer.
- */
-static bool is_newer(private_x509_crl_t *this, crl_t *that)
-{
-       chunk_t that_crlNumber = that->get_serial(that);
-       bool new;
-       
-       /* compare crlNumbers if available - otherwise use thisUpdate */
-       if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL)
-       {
-               new = chunk_compare(this->crlNumber, that_crlNumber) > 0;
-               DBG1("  crl #%#B is %s - existing crl #%#B %s",
-                               &this->crlNumber, new ? "newer":"not newer",
-                               &that_crlNumber,  new ? "replaced":"retained");
-       }
-       else 
-       {
-               certificate_t *this_cert = &this->public.crl.certificate;
-               certificate_t *that_cert = &that->certificate;
-
-               time_t this_update, that_update, now = time(NULL);
-
-               this_cert->get_validity(this_cert, &now, &this_update, NULL);
-               that_cert->get_validity(that_cert, &now, &that_update, NULL);
-               new = this_update > that_update;
-               DBG1("  crl from %#T is %s - existing crl from %#T %s",
-                               &this_update, FALSE, new ? "newer":"not newer",
-                               &that_update, FALSE, new ? "replaced":"retained");
-       }
-       return new;
-}
-
-/**
  * Implementation of crl_t.get_serial.
  */
 static chunk_t get_serial(private_x509_crl_t *this)
@@ -550,15 +517,48 @@ static bool get_validity(private_x509_crl_t *this, time_t *when,
        {
                t = time(NULL);
        }
+       if (not_before)
+       {
+               *not_before = this->thisUpdate;
+       }
        if (not_after)
        {
                *not_after = this->nextUpdate;
        }
-       if (not_before)
+       return (t <= this->nextUpdate);
+}
+
+/**
+ * Implementation of certificate_t.is_newer.
+ */
+static bool is_newer(private_x509_crl_t *this, crl_t *that)
+{
+       chunk_t that_crlNumber = that->get_serial(that);
+       bool new;
+       
+       /* compare crlNumbers if available - otherwise use thisUpdate */
+       if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL)
        {
-               *not_before = this->thisUpdate;
+               new = chunk_compare(this->crlNumber, that_crlNumber) > 0;
+               DBG1("  crl #%#B is %s - existing crl #%#B %s",
+                               &this->crlNumber, new ? "newer":"not newer",
+                               &that_crlNumber,  new ? "replaced":"retained");
        }
-       return (t <= this->nextUpdate);
+       else 
+       {
+               certificate_t *this_cert = &this->public.crl.certificate;
+               certificate_t *that_cert = &that->certificate;
+
+               time_t this_update, that_update, now = time(NULL);
+
+               this_cert->get_validity(this_cert, &now, &this_update, NULL);
+               that_cert->get_validity(that_cert, &now, &that_update, NULL);
+               new = this_update > that_update;
+               DBG1("  crl from %#T is %s - existing crl from %#T %s",
+                               &this_update, FALSE, new ? "newer":"not newer",
+                               &that_update, FALSE, new ? "replaced":"retained");
+       }
+       return new;
 }
        
 /**
@@ -609,7 +609,6 @@ static x509_crl_t *load(chunk_t chunk)
 {
        private_x509_crl_t *this = malloc_thing(private_x509_crl_t);
        
-       this->public.crl.is_newer = (bool (*)(crl_t*,crl_t*))is_newer;
        this->public.crl.get_serial = (chunk_t (*)(crl_t*))get_serial;
        this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier;
        this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator;
@@ -621,6 +620,7 @@ static x509_crl_t *load(chunk_t chunk)
        this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))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;
        this->public.crl.certificate.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
        this->public.crl.certificate.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
        this->public.crl.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
index 4ea2871..87971f2 100644 (file)
@@ -58,7 +58,10 @@ struct private_x509_ocsp_response_t {
        int signatureAlgorithm;
        
        /**
-        * signature value
+        * signature    enumerator = this->responses->create_enumerator(this->responses);
+       while (enumerator->enumerate(enumerator, &response))
+       {
+ value
         */
        chunk_t signature;
        
@@ -420,7 +423,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this,
                                }
                        break;
                        case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
-                               response->status = VALIDATION_FAILED;
+                               response->status = VALIDATION_UNKNOWN;
                                break;
                        case SINGLE_RESPONSE_THIS_UPDATE:
                                response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
@@ -725,13 +728,25 @@ static public_key_t* get_public_key(private_x509_ocsp_response_t *this)
 }
 
 /**
- * Implementation of x509_cert_t.get_validity.
+ * Implementation of certificate_t.get_validity.
  */
 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)
        {
                t = time(NULL);
@@ -742,18 +757,30 @@ static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
        }
        if (not_before)
        {
-               *not_before = this->producedAt;
+               *not_before = thisUpdate;
        }
        if (not_after)
        {
-               *not_after = ~0;
+               *not_after = nextUpdate;
        }
-       /* valid from produceAt up to infinity */
-       if (t >= this->producedAt)
-       {
-               return TRUE;
-       }
-       return FALSE;
+       return (t < nextUpdate);
+}
+
+/**
+ * Implementation of certificate_t.is_newer.
+ */
+static bool is_newer(certificate_t *this, certificate_t *that)
+{
+       time_t this_update, that_update, now = time(NULL);
+       bool new;
+
+       this->get_validity(this, &now, &this_update, NULL);
+       that->get_validity(that, &now, &that_update, NULL);
+       new = this_update > that_update;
+       DBG1("  ocsp response from %#T is %s - existing ocsp response from %#T %s",
+                               &this_update, FALSE, new ? "newer":"not newer",
+                               &that_update, FALSE, new ? "replaced":"retained");
+       return new;
 }
        
 /**
@@ -828,6 +855,7 @@ static x509_ocsp_response_t *load(chunk_t data)
        this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))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;
        this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding;
        this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals;
        this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;