]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
ocsp: introduced gnutls_certificate_get_ocsp_expiration()
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 22 Nov 2017 09:32:04 +0000 (10:32 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 19 Feb 2018 14:29:37 +0000 (15:29 +0100)
This is a function to allow obtaining the validity of the OCSP responses
already set in the credential structures.

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
lib/ocsp-api.c
lib/x509/ocsp.c

index 17f52424df42bc73786c32a4a086e8c195778a10..637b7ccee50b1b487a4fe8368f45653248c7455b 100644 (file)
@@ -1917,6 +1917,12 @@ typedef struct gnutls_ocsp_data_st {
        unsigned char padding[32];
 } gnutls_ocsp_data_st;
 
+time_t
+gnutls_certificate_get_ocsp_expiration(gnutls_certificate_credentials_t sc,
+                                      unsigned idx,
+                                      int oidx,
+                                      unsigned flags);
+
 int gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
                                             gnutls_datum_t * responder_id,
                                             size_t responder_id_size,
index 3ff7958b053b52c837abdbbe7097c581780aade3..3b1d138271c35c7618e96b8ba977d0c8ee79c90d 100644 (file)
@@ -1217,6 +1217,7 @@ GNUTLS_3_6_xx
        gnutls_certificate_set_retrieve_function3;
        gnutls_certificate_set_ocsp_status_request_file2;
        gnutls_certificate_set_ocsp_status_request_mem;
+       gnutls_certificate_get_ocsp_expiration;
 } GNUTLS_3_6_2;
 
 GNUTLS_FIPS140_3_4 {
index eb87afa71bb899c4b8133b340dc8a652a919ac49..b2e0297698ab68072285241110552723e06b6e88 100644 (file)
@@ -240,6 +240,11 @@ unsigned resp_matches_pcert(gnutls_ocsp_resp_t resp, const gnutls_pcert_st *cert
  * To revert to the previous behavior set the flag %GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK
  * in the certificate credentials structure. In that case, only the
  * end-certificate's OCSP response can be set.
+ * If the response is already expired at the time of loading the code
+ * %GNUTLS_E_EXPIRED is returned.
+ *
+ * To revert to the previous behavior of this function which does not return
+ * any errors, set the flag %GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
  *   otherwise a negative error code is returned.
@@ -284,8 +289,11 @@ static int append_response(gnutls_certificate_credentials_t sc, unsigned idx,
                t = _gnutls_ocsp_get_validity(resp);
                /* if already invalid */
                if (t == (time_t)-1) {
-                       gnutls_assert();
-                       continue;
+                       _gnutls_debug_log("the OCSP response associated with chain %d on pos %d, is invalid/expired\n", idx, i);
+                       return GNUTLS_E_EXPIRED;
+               } else if (t == (time_t)-2) {
+                       _gnutls_debug_log("the OCSP response associated with chain %d on pos %d, is too old (ignoring)\n", idx, i);
+                       return 0;
                }
 
                if (t >= 0)
@@ -350,6 +358,8 @@ static int append_response(gnutls_certificate_credentials_t sc, unsigned idx,
  * applicable to the certificate chain are available.
  * If the response provided does not match any certificates present
  * in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
+ * If the response is already expired at the time of loading the code
+ * %GNUTLS_E_EXPIRED is returned.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
  *   otherwise a negative error code is returned.
@@ -405,6 +415,10 @@ gnutls_certificate_set_ocsp_status_request_file2(gnutls_certificate_credentials_
  * apply to the certificate chain are available.
  * If the response provided does not match any certificates present
  * in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
+ * If the response is already expired at the time of loading the code
+ * %GNUTLS_E_EXPIRED is returned.
+ * If the response is already expired at the time of loading the code
+ * %GNUTLS_E_EXPIRED is returned.
  *
  * Returns: On success, the number of loaded responses is returned,
  *   otherwise a negative error code.
@@ -477,6 +491,13 @@ gnutls_certificate_set_ocsp_status_request_mem(gnutls_certificate_credentials_t
        } else {
                /* DER: load a single response */
                if (sc->flags & GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK) {
+                       ret = gnutls_ocsp_resp_import2(resp, resp_data, GNUTLS_X509_FMT_DER);
+                       if (ret >= 0) {
+                               sc->certs[idx].ocsp_data[0].exptime = _gnutls_ocsp_get_validity(resp);
+                               if (sc->certs[idx].ocsp_data[0].exptime <= 0)
+                                       sc->certs[idx].ocsp_data[0].exptime = 0;
+                       }
+
                        /* quick load of first response */
                        gnutls_free(sc->certs[idx].ocsp_data[0].response.data);
 
@@ -488,7 +509,6 @@ gnutls_certificate_set_ocsp_status_request_mem(gnutls_certificate_credentials_t
                                goto cleanup;
                        }
 
-                       sc->certs[idx].ocsp_data[0].exptime = 0;
                        sc->certs[idx].ocsp_data_length = 1;
                        goto cleanup;
                }
@@ -515,6 +535,64 @@ gnutls_certificate_set_ocsp_status_request_mem(gnutls_certificate_credentials_t
        return ret;
 }
 
+/**
+ * gnutls_certificate_get_ocsp_expiration:
+ * @sc: is a credentials structure.
+ * @idx: is a certificate chain index as returned by gnutls_certificate_set_key() and friends
+ * @oidx: is an OCSP response index
+ * @flags: should be zero
+ *
+ * This function returns the validity of the loaded OCSP responses,
+ * to provide information on when to reload/refresh them.
+ *
+ * Note that the credentials structure should be read-only when in
+ * use, thus when reloading, either the credentials structure must not
+ * be in use by any sessions, or a new credentials structure should be
+ * allocated for new sessions.
+ *
+ * When @oidx is (-1) then the minimum refresh time for all responses
+ * is returned. Otherwise the index specifies the response corresponding
+ * to the @odix certificate in the certificate chain.
+ *
+ * Returns: On success, the expiration time of the OCSP response. Otherwise
+ *   (time_t)(-1) on error, or (time_t)-2 on out of bounds.
+ *
+ * Since: 3.6.xx
+ **/
+time_t
+gnutls_certificate_get_ocsp_expiration(gnutls_certificate_credentials_t sc,
+                                      unsigned idx,
+                                      int oidx,
+                                      unsigned flags)
+{
+       unsigned j;
+
+       if (idx >= sc->ncerts)
+               return (time_t)-2;
+
+       if (oidx == -1) {
+               time_t min = 0;
+
+               for (j=0;j<MIN(sc->certs[idx].cert_list_length, MAX_OCSP_RESPONSES);j++) {
+                       if (min <= 0)
+                               min = sc->certs[idx].ocsp_data[j].exptime;
+                       else
+                               if (sc->certs[idx].ocsp_data[j].exptime > 0 &&
+                                   min >= sc->certs[idx].ocsp_data[j].exptime)
+                                       min = sc->certs[idx].ocsp_data[j].exptime;
+               }
+               return min;
+       }
+
+       if (oidx >= MAX_OCSP_RESPONSES || (unsigned)oidx >= sc->certs[idx].cert_list_length)
+               return (time_t)-2;
+
+       if (sc->certs[idx].ocsp_data[oidx].response.data == NULL)
+               return (time_t)-1;
+
+       return sc->certs[idx].ocsp_data[oidx].exptime;
+}
+
 /**
  * gnutls_ocsp_status_request_is_checked:
  * @session: is a gnutls session
index 0c57f7cf2ef689e3877eed217ca2bb58a1bd6ffd..51a15c5c33f407340f13e99e1fc71fc8e5ee9b61 100644 (file)
@@ -2546,8 +2546,9 @@ gnutls_ocsp_resp_list_import2(gnutls_ocsp_resp_t **ocsps,
 }
 
 /* This returns -1 if the OCSP response is invalid (revoked) or its
- * data are too old. Otherwise it returns the time after which that data
- * is invalid.
+ * data are too old. It returns -2 if it cannot determine the expiration
+ * time, and would otherwise treat it as too old.
+ * Otherwise it returns the time after which that data  is invalid.
  */
 time_t _gnutls_ocsp_get_validity(gnutls_ocsp_resp_t resp)
 {
@@ -2581,7 +2582,7 @@ time_t _gnutls_ocsp_get_validity(gnutls_ocsp_resp_t resp)
                 * limit we apply when verifying responses. */
                if (now - vtime > MAX_OCSP_VALIDITY_SECS) {
                        _gnutls_debug_log("The OCSP response is old\n");
-                       return gnutls_assert_val(-1);
+                       return gnutls_assert_val(-2);
                }
 
                return now + MAX_OCSP_VALIDITY_SECS;