[gnutls-devel] Fwd: support of stapled OCSP responses under TLS1.3

Nikos Mavrogiannopoulos n.mavrogiannopoulos at gmail.com
Mon Nov 27 14:35:41 CET 2017

[moving to mailing list - hope that's ok]

On Mon, Nov 27, 2017 at 8:24 AM, Thomas Klute
<thomas2.klute at uni-dortmund.de> wrote:
> Hi Nikos,
> The concept looks good to me, but from my mod_gnutls perspective I see two potential issues:
> 1) If I understand the comment in lib/tls13/certificate.c,
> append_status_request() correctly stapling multiple certificates would
> actually not work together with
> gnutls_certificate_set_retrieve_function2, which mod_gnutls needs to use
>  for virtual hosts.

The use of gnutls_certificate_set_retrieve_function2 remains
unaffected. However, to take advantage of multiple responses, it would
have to be modified to utilize

> 2) The certificate is passed to the callback as a gnutls_pcert_st. I'd
> need to call gnutls_pcert_export_x509 during each run of the callback to
> get a gnutls_x509_crt_t and access things like fingerprint (used for the
> cache key) or OCSP responder URL. I'm not sure if that might hurt
> performance.

If you are storing the certificate as a gnutls_pcert_st internally,
I'd also store the OCSP response in the same structure. E.g.
struct int_store_st {
  gnutls_pcert_st *certs[];
  gnutls_datum_t ocsp_responses[];

where each response corresponds to each cert. When the callback from
gnutls_certificate_set_ocsp_status_request_function3 is set, you'll
get a gnutls_cert_info_st which has an index indicating the positioni
n the chain the OCSP is asked for. With such a setup no additional
parsing will be required. If I misread what you were describing,
please let me know.

> Regarding the first issue, I don't quite understand why the limitation
> exists: The glob_ocsp_func is still tied to a single credentials
> structure, so the stored ptr could still contain a reference to the
> associated vhost or something like that. The OCSP client and caching
> implementation in mod_gnutls needs just the following:
> * Fingerprint as cache key
> * Certificate itself to generate an OCSP request if there is no current
> response in the cache
> * Issuer certificate/trust chain to verify response
> Looking at the gnutls_cert_info_st structure, these are almost there,
> just one question:
>> typedef struct gnutls_cert_info_st {
>>       const struct gnutls_pcert_st *pcert;
> Is this only the certificate in question, or an array with cert_index
> being the index? In the latter case the issuer cert is already
> available, too, but there should be an array length parameter unless the
> API guarantees that the callback is only called if the element
> cert_index + 1 exists.

It is a single certificate only. cert_index is the index for this
certificate in the whole chain.

>>       unsigned cert_index; /* position in chain - zero being the end-certificate */
>>       unsigned flags;
>> } gnutls_cert_info_st;
> A validity check on the response returned by the callback can't replace
> the issuer certificate for mod_gnutls, because an invalid response
> should not end up the the cache.
> Internal caching seems needlessly complex to me, especially regarding
> memory consistency, and with a multi-process structure like the Apache
> server caches will quickly differ between processes. I would prefer an
> interface similar to the session cache (gnutls_db_set_*_function), if it
> is built to let the application update the cache independently. I want
> to move to regularly scheduled OCSP response updates for mod_gnutls
> anyway, so the structure I'm thinking of could be:
> a) Try to get OCSP response via cache retrieve function, use it if valid.
> b) Otherwise, call ocsp_func callback to get a fresh response.
> c) Store response in cache if valid (ideally asynchronously).
> If the application regularly updates the cache on its own, b) and c)
> would never happen. The application being able to update the cache
> whenever is also important to have fresh responses, because I've often
> seen OCSP responses that are valid for multiple days. To encourage
> simple applications to use stapling, GnuTLS could provide a memory-based
> default implementation.

The way I though of it, is that with the callback approach, gnutls
will call 'gnutls_status_request_ocsp_func2' when an OCSP response is
needed for a particular certificate. Application at that point could
return a cached response or initiate/schedule (a) and (c) and use a
cache outside gnutls' boundary. If I understand well, what you are
suggesting is that gnutls does the caching in a "virtual" db which can
be overriden by the application.

We could even use the same db as set by the
gnutls_db_set_store_function, and rely on another set of keys. That
is, gnutls calls 'gnutls_status_request_ocsp_func2', parses the
response given and stores it into db with expiration time set to the
OCSP response expiration time. Subsequent gnutls sessions would use
the db retrieve function to get the OCSP responses, until none is
available when gnutls_status_request_ocsp_func2 will be called again.

I see few advantages and disadvantages over that.
1. (adv) This consolidates the OCSP response usage of expiration time
and validity across gnutls applications.
2. (disadv) This introduces a little more overhead for OCSP response
obtaining by calling both the callback and the DB functions for each
certificate in a chain.
3. (disadv) The semantics of renewal will be quite complex. gnutls
should call gnutls_status_request_ocsp_func2 even before the OCSP
response is expired to somehow indicate that it should be renewed
without blocking the current session. Alternatively, we need a method
to notify the caller on when to provide a fresher OCSP response.

As we have seen in the handling of OCSP responses in existing servers
(1) is quite important, however 3 is also not very trivial to address
either. What do you think?

> For OCSP response files, an equivalent to gnutls_ocsp_resp_import2 that
> parses a file containing multiple responses into a list would be
> helpful. The current mod_gnutls implementation just pushes the file
> content into the internal cache, and a list would make it easy to do the
> same for multiple certificates. Of course applications could do that on
> their own, but it seems like a common use case.

Do you mean something like gnutls_x509_crt_list_import2? That is a
function which will import the responses from a memory buffer and
store them as gnutls_ocsp_resp_t?


More information about the Gnutls-devel mailing list