haproxy/include/haproxy/ssl_ocsp.h
Remi Tricot-Le Breton 69071490ff BUG/MAJOR: ocsp: Separate refcount per instance and per store
With the current way OCSP responses are stored, a single OCSP response
is stored (in a certificate_ocsp structure) when it is loaded during a
certificate parsing, and each SSL_CTX that references it increments its
refcount. The reference to the certificate_ocsp is kept in the SSL_CTX
linked to each ckch_inst, in an ex_data entry that gets freed when the
context is freed.
One of the downsides of this implementation is that if every ckch_inst
referencing a certificate_ocsp gets detroyed, then the OCSP response is
removed from the system. So if we were to remove all crt-list lines
containing a given certificate (that has an OCSP response), and if all
the corresponding SSL_CTXs were destroyed (no ongoing connection using
them), the OCSP response would be destroyed even if the certificate
remains in the system (as an unused certificate).
In such a case, we would want the OCSP response not to be "usable",
since it is not used by any ckch_inst, but still remain in the OCSP
response tree so that if the certificate gets reused (via an "add ssl
crt-list" command for instance), its OCSP response is still known as
well.
But we would also like such an entry not to be updated automatically
anymore once no instance uses it. An easy way to do it could have been
to keep a reference to the certificate_ocsp structure in the ckch_store
as well, on top of all the ones in the ckch_instances, and to remove the
ocsp response from the update tree once the refcount falls to 1, but it
would not work because of the way the ocsp response tree keys are
calculated. They are decorrelated from the ckch_store and are the actual
OCSP_CERTIDs, which is a combination of the issuer's name hash and key
hash, and the certificate's serial number. So two copies of the same
certificate but with different names would still point to the same ocsp
response tree entry.

The solution that answers to all the needs expressed aboved is actually
to have two reference counters in the certificate_ocsp structure, one
actual reference counter corresponding to the number of "live" pointers
on the certificate_ocsp structure, incremented for every SSL_CTX using
it, and one for the ckch stores.
If the ckch_store reference counter falls to 0, the corresponding
certificate must have been removed via CLI calls ('set ssl cert' for
instance).
If the actual refcount falls to 0, then no live SSL_CTX uses the
response anymore. It could happen if all the corresponding crt-list
lines were removed and there are no live SSL sessions using the
certificate anymore.
If any of the two refcounts becomes 0, we will always remove the
response from the auto update tree, because there's no point in spending
time updating an OCSP response that no new SSL connection will be able
to use. But the certificate_ocsp object won't be removed from the tree
unless both refcounts are 0.

Must be backported up to 2.8. Wait a little bit before backporting.
2024-03-20 16:12:10 +01:00

71 lines
2.7 KiB
C

/*
* include/haproxy/ssl_ocsp.h
* This file contains definition for ssl OCSP operations
*
* Copyright (C) 2022 Remi Tricot-Le Breton - rlebreton@haproxy.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_SSL_OCSP_H
#define _HAPROXY_SSL_OCSP_H
#ifdef USE_OPENSSL
#include <haproxy/openssl-compat.h>
#include <haproxy/ssl_ckch-t.h>
#include <haproxy/ssl_crtlist-t.h>
#include <haproxy/ssl_ocsp-t.h>
#if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
int ssl_ocsp_build_response_key(OCSP_CERTID *ocsp_cid, unsigned char certid[OCSP_MAX_CERTID_ASN1_LENGTH], unsigned int *key_length);
int ssl_sock_get_ocsp_arg_kt_index(int evp_keytype);
int ssl_sock_ocsp_stapling_cbk(SSL *ssl, void *arg);
void ssl_sock_free_ocsp(struct certificate_ocsp *ocsp);
void ssl_sock_free_ocsp_instance(struct certificate_ocsp *ocsp);
int ssl_sock_load_ocsp_response(struct buffer *ocsp_response,
struct certificate_ocsp *ocsp,
OCSP_CERTID *cid, char **err);
int ssl_sock_update_ocsp_response(struct buffer *ocsp_response, char **err);
void ssl_sock_ocsp_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp);
int ssl_ocsp_get_uri_from_cert(X509 *cert, struct buffer *out, char **err);
int ssl_ocsp_create_request_details(const OCSP_CERTID *certid, struct buffer *req_url,
struct buffer *req_body, char **err);
int ssl_ocsp_check_response(STACK_OF(X509) *chain, X509 *issuer,
struct buffer *respbuf, char **err);
int ssl_create_ocsp_update_task(char **err);
void ssl_destroy_ocsp_update_task(void);
int ssl_ocsp_update_insert(struct certificate_ocsp *ocsp);
int ocsp_update_check_cfg_consistency(struct ckch_store *store, struct crtlist_entry *entry, char *crt_path, char **err);
#endif /* (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) */
#endif /* USE_OPENSSL */
#endif /* _HAPROXY_SSL_OCSP_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/