You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@serf.apache.org by br...@apache.org on 2016/12/16 09:05:57 UTC
svn commit: r1774562 - in /serf/branches/ocsp-verification: BRANCH-README
buckets/ssl_buckets.c serf_bucket_types.h
Author: brane
Date: Fri Dec 16 09:05:57 2016
New Revision: 1774562
URL: http://svn.apache.org/viewvc?rev=1774562&view=rev
Log:
On the ocsp-verification branch: Implement response parsing and verification.
* BRANCH-README: Update branch docs.
* serf_bucket_types.h
(serf_ssl_ocsp_request_export): Update docstring.
(serf_ssl_ocsp_response_parse
serf_ssl_ocsp_response_verify): Update prototype and docstring.
* buckets/ssl_buckets.c
(ocsp_response_status): New private helper function, extracted from ...
(ocsp_callback): ... here, which uses it for response status checking.
(ssl_ocsp_request_t): Replace the encoded server and issuer certificates
with the OCSP certificate ID used to create requests and verify
responses.
(serf_ssl_ocsp_request_create,
serf_ssl_ocsp_request_export,
serf_ssl_ocsp_request_import): Update to match changed ssl_ocsp_request_t.
(serf_ssl_ocsp_response_t): Change the type of the enclosed response.
(free_ocsp_cert_id, free_ocsp_response): New; pool cleanup functions.
(convert_asn1_generalized_time): New private helper function.
(serf_ssl_ocsp_response_parse,
serf_ssl_ocsp_response_verify): Update prototypes and implement.
Modified:
serf/branches/ocsp-verification/BRANCH-README
serf/branches/ocsp-verification/buckets/ssl_buckets.c
serf/branches/ocsp-verification/serf_bucket_types.h
Modified: serf/branches/ocsp-verification/BRANCH-README
URL: http://svn.apache.org/viewvc/serf/branches/ocsp-verification/BRANCH-README?rev=1774562&r1=1774561&r2=1774562&view=diff
==============================================================================
--- serf/branches/ocsp-verification/BRANCH-README (original)
+++ serf/branches/ocsp-verification/BRANCH-README Fri Dec 16 09:05:57 2016
@@ -132,9 +132,8 @@ These are the proposed changes:
const serf_ssl_ocsp_request_t *ocsp_request);
/**
- * Export @a ocsp_request, including request, server and issuer
- * certificates, to a zero-terminated string, allocated from
- * @a result_pool.
+ * Export @a ocsp_request to a zero-terminated string,
+ * allocated from @a result_pool.
*
* Use @a scratch_pool for temporary allocations.
*
@@ -178,24 +177,32 @@ These are the proposed changes:
typedef struct serf_ssl_ocsp_response_t serf_ssl_ocsp_response_t;
/**
- * Parse the body of an HTTP OCSP response, @a ocsp_response_body,
- * of size @a ocsp_response_size, and construct an OCSP response,
- * allocated from @a result pool.
+ * Parse the body of an OCSP response in DER form, @a ocsp_response,
+ * of size @a ocsp_response_size, and construct an internal
+ * representation, allocated from @a result_pool.
+ *
+ * If @a failures is not @c NULL, it will be set as in
+ * #serf_ssl_need_server_cert_t.
*
* Use @a scratch_pool for temporary allocations.
*
- * Returns @c NULL if the response body is not well-formed.
+ * Returns @c NULL if on failure.
*/
- serf_ssl_ocsp_request_t *serf_ssl_ocsp_response_parse(
- const void *ocsp_response_body,
+ serf_ssl_ocsp_response_t *serf_ssl_ocsp_response_parse(
+ const void *ocsp_response,
apr_size_t ocsp_response_size,
+ int *failures,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Check if the given @a ocsp_response is valid for the given
- * @a ocsp_request, per the algorighm documented in RFC 2560,
- * section 3.5.
+ * @a ocsp_request in the provided @a ssl_ctx, as defined by
+ * the algorithm documented in RFC 2560, section 3.5.
+ *
+ * The OCSP responder and application wall clocks may be out of sync
+ * by @a clock_skew, and @a max_age is the acceptable age of the
+ * request. Their values are truncated to the nearest second.
*
* The returned value will be:
*
@@ -208,20 +215,22 @@ These are the proposed changes:
* - SERF_ERROR_SSL_OCSP_RESPONSE_INVALID,
* if the response itself is invalid or not well-formed.
*
- * The @a this_update, @a next_update and @a produced_at output
- * arguments are described in RFC 2560, section 2.4 and, when not
- * @c NULL and if the verificateion succeeded, will be parsed from
- * the response. Any of these times that are not present in the
- * response will be set to the epoch, i.e., @c APR_TIME_C(0).
+ * The @a this_update and @a next_update output arguments are
+ * described in RFC 2560, section 2.4 and, when not @c NULL and if the
+ * verificateion succeeded, will be parsed from the response. Any of
+ * these times that are not present in the response will be set to the
+ * epoch, i.e., @c APR_TIME_C(0).
*
* Uses @a scratch_pool for temporary allocations.
*/
apr_status_t serf_ssl_ocsp_response_verify(
+ serf_ssl_context_t *ssl_ctx,
const serf_ssl_ocsp_response_t *ocsp_response,
const serf_ssl_ocsp_request_t *ocsp_request,
+ apr_time_t clock_skew,
+ apr_time_t max_age,
apr_time_t *this_update,
apr_time_t *next_update,
- apr_time_t *produced_at,
apr_pool_t *scratch_pool);
Modified: serf/branches/ocsp-verification/buckets/ssl_buckets.c
URL: http://svn.apache.org/viewvc/serf/branches/ocsp-verification/buckets/ssl_buckets.c?rev=1774562&r1=1774561&r2=1774562&view=diff
==============================================================================
--- serf/branches/ocsp-verification/buckets/ssl_buckets.c (original)
+++ serf/branches/ocsp-verification/buckets/ssl_buckets.c Fri Dec 16 09:05:57 2016
@@ -588,6 +588,28 @@ static void bio_meth_free(BIO_METHOD *bi
}
#ifndef OPENSSL_NO_TLSEXT
+static int ocsp_response_status(int failures, OCSP_RESPONSE *response)
+{
+ long resp_status = OCSP_response_status(response);
+ switch (resp_status) {
+ case OCSP_RESPONSE_STATUS_SUCCESSFUL:
+ break;
+ case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
+ case OCSP_RESPONSE_STATUS_INTERNALERROR:
+ case OCSP_RESPONSE_STATUS_SIGREQUIRED:
+ case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
+ failures |= SERF_SSL_OCSP_RESPONDER_ERROR;
+ break;
+ case OCSP_RESPONSE_STATUS_TRYLATER:
+ failures |= SERF_SSL_OCSP_RESPONDER_TRYLATER;
+ break;
+ default:
+ failures |= SERF_SSL_OCSP_RESPONDER_UNKNOWN_FAILURE;
+ break;
+ }
+ return failures;
+}
+
/* Callback called when the server response has some OCSP info.
Returns 1 if the application accepts the OCSP response as successful,
0 in case of error.
@@ -598,7 +620,6 @@ static int ocsp_callback(SSL *ssl, void
OCSP_RESPONSE *response;
const unsigned char *resp_der;
int len;
- long resp_status;
int failures = 0;
int cert_valid = 0;
@@ -618,23 +639,7 @@ static int ocsp_callback(SSL *ssl, void
}
/* Did the server get a valid response from the OCSP responder */
- resp_status = OCSP_response_status(response);
- switch (resp_status) {
- case OCSP_RESPONSE_STATUS_SUCCESSFUL:
- break;
- case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
- case OCSP_RESPONSE_STATUS_INTERNALERROR:
- case OCSP_RESPONSE_STATUS_SIGREQUIRED:
- case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
- failures |= SERF_SSL_OCSP_RESPONDER_ERROR;
- break;
- case OCSP_RESPONSE_STATUS_TRYLATER:
- failures |= SERF_SSL_OCSP_RESPONDER_TRYLATER;
- break;
- default:
- failures |= SERF_SSL_OCSP_RESPONDER_UNKNOWN_FAILURE;
- break;
- }
+ failures = ocsp_response_status(failures, response);
/* TODO: check certificate status */
@@ -2626,13 +2631,12 @@ struct serf_ssl_ocsp_request_t {
/* OpenSSL's internal representation of the OCSP request. */
OCSP_REQUEST *request;
+ /* The certificate ID of the request. */
+ OCSP_CERTID *cert_id;
+
/* DER-encoded request and size. */
const void *der_request;
apr_size_t der_request_size;
-
- /* Exported server and issuer certificates. */
- const char *encoded_server_cert;
- const char *encoded_issuer_cert;
};
static apr_status_t free_ocsp_request(void *data)
@@ -2640,6 +2644,12 @@ static apr_status_t free_ocsp_request(vo
OCSP_REQUEST_free(data);
return APR_SUCCESS;
}
+
+static apr_status_t free_ocsp_cert_id(void *data)
+{
+ OCSP_CERTID_free(data);
+ return APR_SUCCESS;
+}
#endif /* OPENSSL_NO_OCSP */
@@ -2675,7 +2685,12 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
if (!OCSP_request_add0_id(ocsp_req, cert_id))
goto cleanup;
- cert_id = NULL;
+
+ /* Generate another ID to put into the result struct.
+ TODO: see above re hash algorithms. */
+ cert_id = OCSP_cert_to_id(NULL, cert, issuer);
+ if (!cert_id)
+ goto cleanup;
if (generate_nonce) {
/* Generates a random nonce, using the internal random generator. */
@@ -2696,18 +2711,19 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
req = apr_palloc(result_pool, sizeof(*req));
req->der_request = der;
req->der_request_size = len;
- req->encoded_server_cert =
- serf_ssl_cert_export2(server_cert, result_pool, scratch_pool);
- req->encoded_issuer_cert =
- serf_ssl_cert_export2(issuer_cert, result_pool, scratch_pool);
- /* Now move the unencoded request to the result. */
req->request = ocsp_req;
apr_pool_cleanup_register(result_pool, ocsp_req,
free_ocsp_request,
apr_pool_cleanup_null);
ocsp_req = NULL;
+ req->cert_id = cert_id;
+ apr_pool_cleanup_register(result_pool, cert_id,
+ free_ocsp_cert_id,
+ apr_pool_cleanup_null);
+ cert_id = NULL;
+
cleanup:
if (ocsp_req)
OCSP_REQUEST_free(ocsp_req);
@@ -2719,6 +2735,7 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
#endif /* OPENSSL_NO_OCSP */
}
+
const void *serf_ssl_ocsp_request_body(
const serf_ssl_ocsp_request_t *ocsp_request)
{
@@ -2739,6 +2756,7 @@ apr_size_t serf_ssl_ocsp_request_body_si
#endif /* OPENSSL_NO_OCSP */
}
+
const char *serf_ssl_ocsp_request_export(
const serf_ssl_ocsp_request_t *ocsp_request,
apr_pool_t *result_pool,
@@ -2749,30 +2767,36 @@ const char *serf_ssl_ocsp_request_export
/*
The structure of the exported request is:
- "Base64-server-cert" "\x1"
- "Base64-issuer-cert" "\x1"
- "Base64-DER-formatted-request" "\0"
+ "Base64-DER-formatted-request" "\x1"
+ "Base64-DER-formatted-cert-id" "\0"
*/
- const apr_size_t s_size = strlen(ocsp_request->encoded_server_cert);
- const apr_size_t i_size = strlen(ocsp_request->encoded_issuer_cert);
- const apr_size_t all_size = (
- apr_base64_encode_len(ocsp_request->der_request_size)
- + s_size + i_size + 3); /* Three terminator bytes */
+ OCSP_CERTID *const cert_id = ocsp_request->cert_id;
+ int id_len, req_size, id_size;
+ unsigned char *unused;
+ char *buffer = NULL;
+ char *p;
+ void *id_der;
+
+ /* Generate the DER form of the certificate ID. */
+ id_len = i2d_OCSP_CERTID(cert_id, NULL);
+ if (id_len < 0)
+ return NULL;
- char *const buffer = apr_palloc(result_pool, all_size);
- char *p = buffer;
+ unused = id_der = apr_palloc(scratch_pool, id_len);
+ id_len = i2d_OCSP_CERTID(cert_id, &unused); /* unused is incremented */
+ if (id_len < 0)
+ return NULL;
- memcpy(p, ocsp_request->encoded_server_cert, s_size);
- p += s_size;
- *p++ = '\x1';
+ req_size = apr_base64_encode_len(ocsp_request->der_request_size);
+ id_size = apr_base64_encode_len(id_len);
- memcpy(p, ocsp_request->encoded_issuer_cert, i_size);
- p += i_size;
+ buffer = apr_palloc(result_pool, req_size + id_size + 2);
+ req_size = apr_base64_encode(buffer, ocsp_request->der_request,
+ ocsp_request->der_request_size);
+ p = buffer + req_size - 1; /* The trailing \0 is part of the size! */
*p++ = '\x1';
-
- apr_base64_encode(p, ocsp_request->der_request,
- ocsp_request->der_request_size);
+ apr_base64_encode(p, id_der, id_len);
return buffer;
#else
@@ -2780,6 +2804,7 @@ const char *serf_ssl_ocsp_request_export
#endif /* OPENSSL_NO_OCSP */
}
+
serf_ssl_ocsp_request_t *serf_ssl_ocsp_request_import(
const char *encoded_ocsp_request,
apr_pool_t *result_pool,
@@ -2787,45 +2812,47 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
{
#ifndef OPENSSL_NO_OCSP
serf_ssl_ocsp_request_t *req = NULL;
- const char *encoded_server_cert = encoded_ocsp_request;
- const char *encoded_issuer_cert;
- const char *end_server_cert;
- const char *end_issuer_cert;
+ const char *end_request = strchr(encoded_ocsp_request, '\x1');
- end_server_cert = strchr(encoded_server_cert, '\x1');
- if (!end_server_cert)
- return NULL;
-
- encoded_issuer_cert = end_server_cert + 1;
- end_issuer_cert = strchr(encoded_issuer_cert, '\x1');
+ if (end_request) {
+ const char *base64_id = end_request + 1;
+ const char *base64_request = apr_pstrmemdup(
+ scratch_pool, encoded_ocsp_request,
+ end_request - encoded_ocsp_request);
+ long der_request_size = apr_base64_decode_len(base64_request);
+ long der_id_size = apr_base64_decode_len(base64_id);
- if (end_issuer_cert) {
OCSP_REQUEST *ocsp_req;
- const char *base64_request = end_issuer_cert + 1;
- long der_request_size = apr_base64_decode_len(base64_request);
- /* FIXME: Use scratch pool instead and pmemdup later? */
- void *der_request = apr_palloc(result_pool, der_request_size);
- const unsigned char *unused = der_request;
+ OCSP_CERTID *cert_id;
+ const unsigned char *unused;
+ void *der_request;
+ void *der_id;
+ unused = der_request = apr_palloc(result_pool, der_request_size);
der_request_size = apr_base64_decode(der_request, base64_request);
ocsp_req = d2i_OCSP_REQUEST(NULL, &unused, der_request_size);
if (!ocsp_req)
return NULL;
+ unused = der_id = apr_palloc(scratch_pool, der_id_size);
+ der_id_size = apr_base64_decode(der_id, base64_id);
+ cert_id = d2i_OCSP_CERTID(NULL, &unused, der_id_size);
+ if (!cert_id)
+ return NULL;
+
req = apr_palloc(result_pool, sizeof(*req));
req->der_request = der_request;
req->der_request_size = der_request_size;
- req->encoded_server_cert =
- apr_pstrmemdup(result_pool, encoded_server_cert,
- end_server_cert - encoded_server_cert);
- req->encoded_issuer_cert =
- apr_pstrmemdup(result_pool, encoded_issuer_cert,
- end_issuer_cert - encoded_issuer_cert);
req->request = ocsp_req;
apr_pool_cleanup_register(result_pool, ocsp_req,
free_ocsp_request,
apr_pool_cleanup_null);
+
+ req->cert_id = cert_id;
+ apr_pool_cleanup_register(result_pool, cert_id,
+ free_ocsp_cert_id,
+ apr_pool_cleanup_null);
}
return req;
@@ -2834,36 +2861,189 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
#endif /* OPENSSL_NO_OCSP */
}
+
#ifndef OPENSSL_NO_OCSP
struct serf_ssl_ocsp_response_t {
/* OpenSSL's internal representation of the OCSP response. */
- OCSP_BASICRESP *response;
+ OCSP_RESPONSE *response;
};
+
+static apr_status_t free_ocsp_response(void *data)
+{
+ OCSP_RESPONSE_free(data);
+ return APR_SUCCESS;
+}
#endif /* OPENSSL_NO_OCSP */
+
serf_ssl_ocsp_response_t *serf_ssl_ocsp_response_parse(
- const void *ocsp_response_body,
+ const void *ocsp_response,
apr_size_t ocsp_response_size,
+ int *failures,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
#ifndef OPENSSL_NO_OCSP
- return NULL;
+ serf_ssl_ocsp_response_t *rsp = NULL;
+ OCSP_RESPONSE *ocsp_rsp = NULL;
+ const unsigned char *unused;
+ int rsp_failures = 0;
+
+ unused = ocsp_response;
+ ocsp_rsp = d2i_OCSP_RESPONSE(NULL, &unused, ocsp_response_size);
+ if (!ocsp_rsp)
+ goto cleanup;
+
+ rsp_failures = ocsp_response_status(rsp_failures, ocsp_rsp);
+ if (rsp_failures)
+ goto cleanup;
+
+ rsp = apr_palloc(result_pool, sizeof(*rsp));
+ rsp->response = ocsp_rsp;
+ apr_pool_cleanup_register(result_pool, ocsp_rsp,
+ free_ocsp_response,
+ apr_pool_cleanup_null);
+ ocsp_rsp = NULL;
+
+ cleanup:
+ if (failures)
+ *failures = rsp_failures;
+ if (ocsp_rsp)
+ OCSP_RESPONSE_free(ocsp_rsp);
+ return rsp;
#else
return NULL;
#endif /* OPENSSL_NO_OCSP */
}
+
+#ifndef OPENSSL_NO_OCSP
+/* Ripped from Subversion and well kneaded. */
+static apr_status_t
+convert_asn1_generalized_time(ASN1_GENERALIZEDTIME *asn1_time,
+ apr_time_t *humane_time,
+ apr_pool_t *scratch_pool,
+ apr_status_t parse_error)
+{
+ apr_time_exp_t xt = { 0 };
+ void *data;
+ char *date;
+ int len;
+ char tz;
+
+ if (ASN1_STRING_type(asn1_time) != V_ASN1_GENERALIZEDTIME)
+ return 0;
+
+ len = ASN1_STRING_length(asn1_time);
+ data = ASN1_STRING_data(asn1_time);
+ date = apr_pstrndup(scratch_pool, data, len);
+
+ if (6 > sscanf(date, "%4d%2d%2d%2d%2d%2d%c",
+ &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
+ &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz))
+ return parse_error;
+
+ /* GeneralizedTime has the full 4 digit year. But apr_time_exp_t
+ wants years as the number of years since 1900. */
+ xt.tm_year -= 1900;
+
+ /* Check that the timezone is GMT.
+ ASN.1 allows for the timezone to be specified but X.509 says it
+ must always be GMT. A little bit of extra paranoia here seems
+ like a good idea. */
+ if (tz != 'Z')
+ return parse_error;
+
+ /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
+ xt.tm_mon -= 1;
+
+ return apr_time_exp_gmt_get(humane_time, &xt);
+}
+#endif /* OPENSSL_NO_OCSP */
+
apr_status_t serf_ssl_ocsp_response_verify(
+ serf_ssl_context_t *ssl_ctx,
const serf_ssl_ocsp_response_t *ocsp_response,
const serf_ssl_ocsp_request_t *ocsp_request,
+ apr_time_t clock_skew,
+ apr_time_t max_age,
apr_time_t *this_update,
apr_time_t *next_update,
- apr_time_t *produced_at,
apr_pool_t *scratch_pool)
{
#ifndef OPENSSL_NO_OCSP
- return SERF_ERROR_SSL_OCSP_RESPONSE_INVALID;
+ OCSP_BASICRESP *ocsp_basic = NULL;
+ apr_status_t status = SERF_ERROR_SSL_OCSP_RESPONSE_INVALID;
+ ASN1_GENERALIZEDTIME *asn1_revoked_at;
+ ASN1_GENERALIZEDTIME *asn1_this_update;
+ ASN1_GENERALIZEDTIME *asn1_next_update;
+ int cert_status, cert_reason;
+ X509_STORE *store;
+
+ ocsp_basic = OCSP_response_get1_basic(ocsp_response->response);
+ if (!ocsp_basic)
+ goto cleanup;
+
+ if (0 >= OCSP_check_nonce(ocsp_request->request, ocsp_basic))
+ goto cleanup;
+
+ store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
+ if (0 >= OCSP_basic_verify(ocsp_basic, NULL, store, 0))
+ goto cleanup;
+
+ if (!OCSP_resp_find_status(ocsp_basic, ocsp_request->cert_id,
+ &cert_status, &cert_reason,
+ &asn1_revoked_at,
+ &asn1_this_update,
+ &asn1_next_update))
+ goto cleanup;
+
+ if (!OCSP_check_validity(asn1_this_update, asn1_next_update,
+ (long)apr_time_sec(clock_skew),
+ (long)apr_time_sec(max_age)))
+ goto cleanup;
+
+ if (this_update) {
+ if (asn1_this_update) {
+ status = convert_asn1_generalized_time(asn1_this_update, this_update,
+ scratch_pool, status);
+ if (status)
+ goto cleanup;
+ }
+ else
+ *this_update = APR_TIME_C(0);
+ }
+
+ if (next_update) {
+ if (asn1_next_update) {
+ status = convert_asn1_generalized_time(asn1_next_update, next_update,
+ scratch_pool, status);
+ if (status)
+ goto cleanup;
+ }
+ else
+ *next_update = APR_TIME_C(0);
+ }
+
+ switch (cert_status)
+ {
+ case V_OCSP_CERTSTATUS_REVOKED:
+ status = SERF_ERROR_SSL_OCSP_RESPONSE_CERT_REVOKED;
+ break;
+
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ status = SERF_ERROR_SSL_OCSP_RESPONSE_CERT_UNKNOWN;
+ break;
+
+ case V_OCSP_CERTSTATUS_GOOD:
+ default:
+ status = APR_SUCCESS;
+ }
+
+ cleanup:
+ if (ocsp_basic)
+ OCSP_BASICRESP_free(ocsp_basic);
+ return status;
#else
return SERF_ERROR_SSL_OCSP_RESPONSE_INVALID;
#endif /* OPENSSL_NO_OCSP */
Modified: serf/branches/ocsp-verification/serf_bucket_types.h
URL: http://svn.apache.org/viewvc/serf/branches/ocsp-verification/serf_bucket_types.h?rev=1774562&r1=1774561&r2=1774562&view=diff
==============================================================================
--- serf/branches/ocsp-verification/serf_bucket_types.h (original)
+++ serf/branches/ocsp-verification/serf_bucket_types.h Fri Dec 16 09:05:57 2016
@@ -850,9 +850,8 @@ apr_size_t serf_ssl_ocsp_request_body_si
const serf_ssl_ocsp_request_t *ocsp_request);
/**
- * Export @a ocsp_request, including request, server and issuer
- * certificates, to a zero-terminated string, allocated from
- * @a result_pool.
+ * Export @a ocsp_request to a zero-terminated string,
+ * allocated from @a result_pool.
*
* Use @a scratch_pool for temporary allocations.
*
@@ -883,24 +882,32 @@ serf_ssl_ocsp_request_t *serf_ssl_ocsp_r
typedef struct serf_ssl_ocsp_response_t serf_ssl_ocsp_response_t;
/**
- * Parse the body of an HTTP OCSP response, @a ocsp_response_body,
- * of size @a ocsp_response_size, and construct an OCSP response,
- * allocated from @a result pool.
+ * Parse the body of an OCSP response in DER form, @a ocsp_response,
+ * of size @a ocsp_response_size, and construct an internal
+ * representation, allocated from @a result_pool.
+ *
+ * If @a failures is not @c NULL, it will be set as in
+ * #serf_ssl_need_server_cert_t.
*
* Use @a scratch_pool for temporary allocations.
*
- * Returns @c NULL if the response body is not well-formed.
+ * Returns @c NULL if on failure.
*/
serf_ssl_ocsp_response_t *serf_ssl_ocsp_response_parse(
- const void *ocsp_response_body,
+ const void *ocsp_response,
apr_size_t ocsp_response_size,
+ int *failures,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Check if the given @a ocsp_response is valid for the given
- * @a ocsp_request, per the algorighm documented in RFC 2560,
- * section 3.5.
+ * @a ocsp_request in the provided @a ssl_ctx, as defined by
+ * the algorithm documented in RFC 2560, section 3.5.
+ *
+ * The OCSP responder and application wall clocks may be out of sync
+ * by @a clock_skew, and @a max_age is the acceptable age of the
+ * request. Their values are truncated to the nearest second.
*
* The returned value will be:
*
@@ -913,20 +920,22 @@ serf_ssl_ocsp_response_t *serf_ssl_ocsp_
* - SERF_ERROR_SSL_OCSP_RESPONSE_INVALID,
* if the response itself is invalid or not well-formed.
*
- * The @a this_update, @a next_update and @a produced_at output
- * arguments are described in RFC 2560, section 2.4 and, when not
- * @c NULL and if the verificateion succeeded, will be parsed from
- * the response. Any of these times that are not present in the
- * response will be set to the epoch, i.e., @c APR_TIME_C(0).
+ * The @a this_update and @a next_update output arguments are
+ * described in RFC 2560, section 2.4 and, when not @c NULL and if the
+ * verificateion succeeded, will be parsed from the response. Any of
+ * these times that are not present in the response will be set to the
+ * epoch, i.e., @c APR_TIME_C(0).
*
* Uses @a scratch_pool for temporary allocations.
*/
apr_status_t serf_ssl_ocsp_response_verify(
+ serf_ssl_context_t *ssl_ctx,
const serf_ssl_ocsp_response_t *ocsp_response,
const serf_ssl_ocsp_request_t *ocsp_request,
+ apr_time_t clock_skew,
+ apr_time_t max_age,
apr_time_t *this_update,
apr_time_t *next_update,
- apr_time_t *produced_at,
apr_pool_t *scratch_pool);
/* ==================================================================== */