summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-11-22 10:32:04 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-19 15:29:37 +0100
commitddef51dde37bde22ae351b4cd36cc86e5ecc4049 (patch)
treece54f23559f978c9e9920021ed0df859c349ef10
parent5623c86b5678ef93e9670a6f7bc412e2c8dda62a (diff)
downloadgnutls-ddef51dde37bde22ae351b4cd36cc86e5ecc4049.tar.gz
ocsp: introduced gnutls_certificate_get_ocsp_expiration()
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>
-rw-r--r--lib/includes/gnutls/gnutls.h.in6
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/ocsp-api.c84
-rw-r--r--lib/x509/ocsp.c7
4 files changed, 92 insertions, 6 deletions
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 17f52424df..637b7ccee5 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -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,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 3ff7958b05..3b1d138271 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -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 {
diff --git a/lib/ocsp-api.c b/lib/ocsp-api.c
index eb87afa71b..b2e0297698 100644
--- a/lib/ocsp-api.c
+++ b/lib/ocsp-api.c
@@ -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;
}
@@ -516,6 +536,64 @@ gnutls_certificate_set_ocsp_status_request_mem(gnutls_certificate_credentials_t
}
/**
+ * 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
* @flags: should be zero or %GNUTLS_OCSP_SR_IS_AVAIL
diff --git a/lib/x509/ocsp.c b/lib/x509/ocsp.c
index 0c57f7cf2e..51a15c5c33 100644
--- a/lib/x509/ocsp.c
+++ b/lib/x509/ocsp.c
@@ -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;