]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: ssl: move 'generate-certificates' code to ssl_gencert.c
authorWilliam Lallemand <wlallemand@haproxy.com>
Fri, 12 Jan 2024 14:23:49 +0000 (15:23 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Fri, 12 Jan 2024 16:40:42 +0000 (17:40 +0100)
A lot of code specific to the 'generate-certificates' option was left in
ssl_sock.c.

Move the code to 'ssl_gencert.c' and 'ssl_gencert.h'

Makefile
include/haproxy/ssl_gencert.h [new file with mode: 0644]
include/haproxy/ssl_sock.h
src/ssl_gencert.c [new file with mode: 0644]
src/ssl_sock.c

index a66c9b69c0f1bb93f11697e82f5d48f420d9a59f..3fab62d692fa9035d72d646b9b752b14f2bef84c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -599,7 +599,7 @@ ifneq ($(USE_OPENSSL),)
     SSL_LDFLAGS   := $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
   endif
   USE_SSL         := $(if $(USE_SSL),$(USE_SSL),implicit)
-  OPTIONS_OBJS += src/ssl_sock.o src/ssl_ckch.o src/ssl_sample.o src/ssl_crtlist.o src/cfgparse-ssl.o src/ssl_utils.o src/jwt.o src/ssl_ocsp.o
+  OPTIONS_OBJS += src/ssl_sock.o src/ssl_ckch.o src/ssl_sample.o src/ssl_crtlist.o src/cfgparse-ssl.o src/ssl_utils.o src/jwt.o src/ssl_ocsp.o src/ssl_gencert.o
 endif
 
 ifneq ($(USE_ENGINE),)
diff --git a/include/haproxy/ssl_gencert.h b/include/haproxy/ssl_gencert.h
new file mode 100644 (file)
index 0000000..4f9510e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * include/haproxy/ssl_gencert.h
+ * This file contains definition for ssl 'generate-certificates' option.
+ *
+ * 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_GENCERT_H
+#define _HAPROXY_SSL_GENCERT_H
+#ifdef USE_OPENSSL
+
+int ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf, SSL *ssl);
+int ssl_sock_generate_certificate_from_conn(struct bind_conf *bind_conf, SSL *ssl);
+SSL_CTX *ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind_conf, SSL *ssl);
+SSL_CTX *ssl_sock_get_generated_cert(unsigned int key, struct bind_conf *bind_conf);
+int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf *bind_conf);
+unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
+
+#endif /* USE_OPENSSL */
+#endif /* _HAPROXY_SSL_GENCERT_H */
index 02d5b023fcf63bb0651fa4125b279ea8a0324db0..0befb570cca21cd2d4d5ebae955ad5d77391d297 100644 (file)
@@ -114,11 +114,9 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv);
 #endif
 
 int increment_sslconn();
-SSL_CTX *ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind_conf, SSL *ssl);
-SSL_CTX *ssl_sock_get_generated_cert(unsigned int key, struct bind_conf *bind_conf);
-int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf *bind_conf);
-unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
 void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf *bind_conf);
+struct sni_ctx *ssl_sock_chose_sni_ctx(struct bind_conf *s, const char *servername,
+                                                             int have_rsa_sig, int have_ecdsa_sig);
 #ifdef SSL_MODE_ASYNC
 void ssl_async_fd_handler(int fd);
 void ssl_async_fd_free(int fd);
@@ -139,6 +137,12 @@ int ssl_get_ocspresponse_detail(unsigned char *ocsp_certid, struct buffer *out);
 int ssl_ocsp_response_print(struct buffer *ocsp_response, struct buffer *out);
 #endif
 
+#if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
+DH *ssl_get_tmp_dh_cbk(SSL *ssl, int export, int keylen);
+#else
+void ssl_sock_set_tmp_dh_from_pkey(SSL_CTX *ctx, EVP_PKEY *pkey);
+#endif
+
 /* ssl shctx macro */
 
 #define sh_ssl_sess_tree_delete(s)     ebmb_delete(&(s)->key);
diff --git a/src/ssl_gencert.c b/src/ssl_gencert.c
new file mode 100644 (file)
index 0000000..95195d1
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * SSL 'generate-certificate' option logic.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define _GNU_SOURCE
+#include <import/lru.h>
+
+#include <haproxy/errors.h>
+#include <haproxy/openssl-compat.h>
+#include <haproxy/ssl_ckch.h>
+#include <haproxy/ssl_sock.h>
+#include <haproxy/xxhash.h>
+
+#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
+/* X509V3 Extensions that will be added on generated certificates */
+#define X509V3_EXT_SIZE 5
+static char *x509v3_ext_names[X509V3_EXT_SIZE] = {
+       "basicConstraints",
+       "nsComment",
+       "subjectKeyIdentifier",
+       "authorityKeyIdentifier",
+       "keyUsage",
+};
+static char *x509v3_ext_values[X509V3_EXT_SIZE] = {
+       "CA:FALSE",
+       "\"OpenSSL Generated Certificate\"",
+       "hash",
+       "keyid,issuer:always",
+       "nonRepudiation,digitalSignature,keyEncipherment"
+};
+/* LRU cache to store generated certificate */
+static struct lru64_head *ssl_ctx_lru_tree = NULL;
+static unsigned int       ssl_ctx_lru_seed = 0;
+static unsigned int      ssl_ctx_serial;
+__decl_rwlock(ssl_ctx_lru_rwlock);
+
+#endif // SSL_CTRL_SET_TLSEXT_HOSTNAME
+
+#ifndef SSL_NO_GENERATE_CERTIFICATES
+
+/* Configure a DNS SAN extension on a certificate. */
+int ssl_sock_add_san_ext(X509V3_CTX* ctx, X509* cert, const char *servername) {
+       int failure = 0;
+       X509_EXTENSION *san_ext = NULL;
+       CONF *conf = NULL;
+       struct buffer *san_name = get_trash_chunk();
+
+       conf = NCONF_new(NULL);
+       if (!conf) {
+               failure = 1;
+               goto cleanup;
+       }
+
+       /* Build an extension based on the DNS entry above */
+       chunk_appendf(san_name, "DNS:%s", servername);
+       san_ext = X509V3_EXT_nconf_nid(conf, ctx, NID_subject_alt_name, san_name->area);
+       if (!san_ext) {
+               failure = 1;
+               goto cleanup;
+       }
+
+       /* Add the extension */
+       if (!X509_add_ext(cert, san_ext, -1 /* Add to end */)) {
+               failure = 1;
+               goto cleanup;
+       }
+
+       /* Success */
+       failure = 0;
+
+cleanup:
+       if (NULL != san_ext) X509_EXTENSION_free(san_ext);
+       if (NULL != conf) NCONF_free(conf);
+
+       return failure;
+}
+
+/* Create a X509 certificate with the specified servername and serial. This
+ * function returns a SSL_CTX object or NULL if an error occurs. */
+static SSL_CTX *ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL *ssl)
+{
+       X509         *cacert  = bind_conf->ca_sign_ckch->cert;
+       EVP_PKEY     *capkey  = bind_conf->ca_sign_ckch->key;
+       SSL_CTX      *ssl_ctx = NULL;
+       X509         *newcrt  = NULL;
+       EVP_PKEY     *pkey    = NULL;
+       SSL          *tmp_ssl = NULL;
+       CONF         *ctmp    = NULL;
+       X509_NAME    *name;
+       const EVP_MD *digest;
+       X509V3_CTX    ctx;
+       unsigned int  i;
+       int           key_type;
+       struct sni_ctx *sni_ctx;
+
+       sni_ctx = ssl_sock_chose_sni_ctx(bind_conf, "", 1, 1);
+       if (!sni_ctx)
+               goto mkcert_error;
+
+       /* Get the private key of the default certificate and use it */
+#ifdef HAVE_SSL_CTX_get0_privatekey
+       pkey = SSL_CTX_get0_privatekey(sni_ctx->ctx);
+#else
+       tmp_ssl = SSL_new(sni_ctx->ctx);
+       if (tmp_ssl)
+               pkey = SSL_get_privatekey(tmp_ssl);
+#endif
+       if (!pkey)
+               goto mkcert_error;
+
+       /* Create the certificate */
+       if (!(newcrt = X509_new()))
+               goto mkcert_error;
+
+       /* Set version number for the certificate (X509v3) and the serial
+        * number */
+       if (X509_set_version(newcrt, 2L) != 1)
+               goto mkcert_error;
+       ASN1_INTEGER_set(X509_get_serialNumber(newcrt), _HA_ATOMIC_ADD_FETCH(&ssl_ctx_serial, 1));
+
+       /* Set duration for the certificate */
+       if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) ||
+           !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365))
+               goto mkcert_error;
+
+       /* set public key in the certificate */
+       if (X509_set_pubkey(newcrt, pkey) != 1)
+               goto mkcert_error;
+
+       /* Set issuer name from the CA */
+       if (!(name = X509_get_subject_name(cacert)))
+               goto mkcert_error;
+       if (X509_set_issuer_name(newcrt, name) != 1)
+               goto mkcert_error;
+
+       /* Set the subject name using the same, but the CN */
+       name = X509_NAME_dup(name);
+       if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+                                      (const unsigned char *)servername,
+                                      -1, -1, 0) != 1) {
+               X509_NAME_free(name);
+               goto mkcert_error;
+       }
+       if (X509_set_subject_name(newcrt, name) != 1) {
+               X509_NAME_free(name);
+               goto mkcert_error;
+       }
+       X509_NAME_free(name);
+
+       /* Add x509v3 extensions as specified */
+       ctmp = NCONF_new(NULL);
+       X509V3_set_ctx(&ctx, cacert, newcrt, NULL, NULL, 0);
+       for (i = 0; i < X509V3_EXT_SIZE; i++) {
+               X509_EXTENSION *ext;
+
+               if (!(ext = X509V3_EXT_nconf(ctmp, &ctx, x509v3_ext_names[i], x509v3_ext_values[i])))
+                       goto mkcert_error;
+               if (!X509_add_ext(newcrt, ext, -1)) {
+                       X509_EXTENSION_free(ext);
+                       goto mkcert_error;
+               }
+               X509_EXTENSION_free(ext);
+       }
+
+       /* Add SAN extension */
+       if (ssl_sock_add_san_ext(&ctx, newcrt, servername)) {
+               goto mkcert_error;
+       }
+
+       /* Sign the certificate with the CA private key */
+
+       key_type = EVP_PKEY_base_id(capkey);
+
+       if (key_type == EVP_PKEY_DSA)
+               digest = EVP_sha1();
+       else if (key_type == EVP_PKEY_RSA)
+               digest = EVP_sha256();
+       else if (key_type == EVP_PKEY_EC)
+               digest = EVP_sha256();
+       else {
+#ifdef ASN1_PKEY_CTRL_DEFAULT_MD_NID
+               int nid;
+
+               if (EVP_PKEY_get_default_digest_nid(capkey, &nid) <= 0)
+                       goto mkcert_error;
+               if (!(digest = EVP_get_digestbynid(nid)))
+                       goto mkcert_error;
+#else
+               goto mkcert_error;
+#endif
+       }
+
+       if (!(X509_sign(newcrt, capkey, digest)))
+               goto mkcert_error;
+
+       /* Create and set the new SSL_CTX */
+       if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
+               goto mkcert_error;
+       if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
+               goto mkcert_error;
+       if (!SSL_CTX_use_certificate(ssl_ctx, newcrt))
+               goto mkcert_error;
+       if (!SSL_CTX_check_private_key(ssl_ctx))
+               goto mkcert_error;
+
+       /* Build chaining the CA cert and the rest of the chain, keep these order */
+#if defined(SSL_CTX_add1_chain_cert)
+       if (!SSL_CTX_add1_chain_cert(ssl_ctx, bind_conf->ca_sign_ckch->cert)) {
+               goto mkcert_error;
+       }
+
+       if (bind_conf->ca_sign_ckch->chain) {
+               for (i = 0; i < sk_X509_num(bind_conf->ca_sign_ckch->chain); i++) {
+                       X509 *chain_cert = sk_X509_value(bind_conf->ca_sign_ckch->chain, i);
+                       if (!SSL_CTX_add1_chain_cert(ssl_ctx, chain_cert)) {
+                               goto mkcert_error;
+                       }
+               }
+       }
+#endif
+
+       if (newcrt) X509_free(newcrt);
+
+#ifndef OPENSSL_NO_DH
+#if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
+       SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_get_tmp_dh_cbk);
+#else
+       ssl_sock_set_tmp_dh_from_pkey(ssl_ctx, pkey);
+#endif
+#endif
+
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
+#if defined(SSL_CTX_set1_curves_list)
+       {
+               const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
+               if (!SSL_CTX_set1_curves_list(ssl_ctx, ecdhe))
+                       goto end;
+       }
+#endif
+#else
+#if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
+       {
+               const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
+               EC_KEY     *ecc;
+               int         nid;
+
+               if ((nid = OBJ_sn2nid(ecdhe)) == NID_undef)
+                       goto end;
+               if (!(ecc = EC_KEY_new_by_curve_name(nid)))
+                       goto end;
+               SSL_CTX_set_tmp_ecdh(ssl_ctx, ecc);
+               EC_KEY_free(ecc);
+       }
+#endif /* defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH) */
+#endif /* HA_OPENSSL_VERSION_NUMBER >= 0x10101000L */
+ end:
+       return ssl_ctx;
+
+ mkcert_error:
+       if (ctmp) NCONF_free(ctmp);
+       if (tmp_ssl) SSL_free(tmp_ssl);
+       if (ssl_ctx) SSL_CTX_free(ssl_ctx);
+       if (newcrt)  X509_free(newcrt);
+       return NULL;
+}
+
+
+/* Do a lookup for a certificate in the LRU cache used to store generated
+ * certificates and immediately assign it to the SSL session if not null. */
+SSL_CTX *ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind_conf, SSL *ssl)
+{
+       struct lru64 *lru = NULL;
+
+       if (ssl_ctx_lru_tree) {
+               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+               lru = lru64_lookup(key, ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
+               if (lru && lru->domain) {
+                       if (ssl)
+                               SSL_set_SSL_CTX(ssl, (SSL_CTX *)lru->data);
+                       HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+                       return (SSL_CTX *)lru->data;
+               }
+               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+       }
+       return NULL;
+}
+
+/* Same as <ssl_sock_assign_generated_cert> but without SSL session. This
+ * function is not thread-safe, it should only be used to check if a certificate
+ * exists in the lru cache (with no warranty it will not be removed by another
+ * thread). It is kept for backward compatibility. */
+SSL_CTX *
+ssl_sock_get_generated_cert(unsigned int key, struct bind_conf *bind_conf)
+{
+       return ssl_sock_assign_generated_cert(key, bind_conf, NULL);
+}
+
+/* Set a certificate int the LRU cache used to store generated
+ * certificate. Return 0 on success, otherwise -1 */
+int ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int key, struct bind_conf *bind_conf)
+{
+       struct lru64 *lru = NULL;
+
+       if (ssl_ctx_lru_tree) {
+               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+               lru = lru64_get(key, ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
+               if (!lru) {
+                       HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+                       return -1;
+               }
+               if (lru->domain && lru->data)
+                       lru->free((SSL_CTX *)lru->data);
+               lru64_commit(lru, ssl_ctx, bind_conf->ca_sign_ckch->cert, 0, (void (*)(void *))SSL_CTX_free);
+               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+               return 0;
+       }
+       return -1;
+}
+
+/* Compute the key of the certificate. */
+unsigned int
+ssl_sock_generated_cert_key(const void *data, size_t len)
+{
+       return XXH32(data, len, ssl_ctx_lru_seed);
+}
+
+/* Generate a cert and immediately assign it to the SSL session so that the cert's
+ * refcount is maintained regardless of the cert's presence in the LRU cache.
+ */
+int ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf, SSL *ssl)
+{
+       X509         *cacert  = bind_conf->ca_sign_ckch->cert;
+       SSL_CTX      *ssl_ctx = NULL;
+       struct lru64 *lru     = NULL;
+       unsigned int  key;
+
+       key = ssl_sock_generated_cert_key(servername, strlen(servername));
+       if (ssl_ctx_lru_tree) {
+               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+               lru = lru64_get(key, ssl_ctx_lru_tree, cacert, 0);
+               if (lru && lru->domain)
+                       ssl_ctx = (SSL_CTX *)lru->data;
+               if (!ssl_ctx && lru) {
+                       ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
+                       lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
+               }
+               SSL_set_SSL_CTX(ssl, ssl_ctx);
+               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
+               return 1;
+       }
+       else {
+               ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
+               SSL_set_SSL_CTX(ssl, ssl_ctx);
+               /* No LRU cache, this CTX will be released as soon as the session dies */
+               SSL_CTX_free(ssl_ctx);
+               return 1;
+       }
+       return 0;
+}
+int ssl_sock_generate_certificate_from_conn(struct bind_conf *bind_conf, SSL *ssl)
+{
+       unsigned int key;
+       struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
+
+       if (conn_get_dst(conn)) {
+               key = ssl_sock_generated_cert_key(conn->dst, get_addr_len(conn->dst));
+               if (ssl_sock_assign_generated_cert(key, bind_conf, ssl))
+                       return 1;
+       }
+       return 0;
+}
+
+/* Load CA cert file and private key used to generate certificates */
+int
+ssl_sock_load_ca(struct bind_conf *bind_conf)
+{
+       struct proxy *px = bind_conf->frontend;
+       struct ckch_data *data = NULL;
+       int ret = 0;
+       char *err = NULL;
+
+       if (!(bind_conf->options & BC_O_GENERATE_CERTS))
+               return ret;
+
+#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
+       if (global_ssl.ctx_cache) {
+               ssl_ctx_lru_tree = lru64_new(global_ssl.ctx_cache);
+       }
+       ssl_ctx_lru_seed = (unsigned int)time(NULL);
+       ssl_ctx_serial   = now_ms;
+#endif
+
+       if (!bind_conf->ca_sign_file) {
+               ha_alert("Proxy '%s': cannot enable certificate generation, "
+                        "no CA certificate File configured at [%s:%d].\n",
+                        px->id, bind_conf->file, bind_conf->line);
+               goto failed;
+       }
+
+       /* Allocate cert structure */
+       data = calloc(1, sizeof(*data));
+       if (!data) {
+               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain allocation failure\n",
+                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
+               goto failed;
+       }
+
+       /* Try to parse file */
+       if (ssl_sock_load_files_into_ckch(bind_conf->ca_sign_file, data, &err)) {
+               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain loading failed: %s\n",
+                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line, err);
+               free(err);
+               goto failed;
+       }
+
+       /* Fail if missing cert or pkey */
+       if ((!data->cert) || (!data->key)) {
+               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain missing certificate or private key\n",
+                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
+               goto failed;
+       }
+
+       /* Final assignment to bind */
+       bind_conf->ca_sign_ckch = data;
+       return ret;
+
+ failed:
+       if (data) {
+               ssl_sock_free_cert_key_and_chain_contents(data);
+               free(data);
+       }
+
+       bind_conf->options &= ~BC_O_GENERATE_CERTS;
+       ret++;
+       return ret;
+}
+
+/* Release CA cert and private key used to generate certificated */
+void
+ssl_sock_free_ca(struct bind_conf *bind_conf)
+{
+       if (bind_conf->ca_sign_ckch) {
+               ssl_sock_free_cert_key_and_chain_contents(bind_conf->ca_sign_ckch);
+               ha_free(&bind_conf->ca_sign_ckch);
+       }
+}
+
+#endif /* !defined SSL_NO_GENERATE_CERTIFICATES */
+
+
+static void __ssl_gencert_deinit(void)
+{
+#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
+       if (ssl_ctx_lru_tree) {
+               lru64_destroy(ssl_ctx_lru_tree);
+               HA_RWLOCK_DESTROY(&ssl_ctx_lru_rwlock);
+       }
+#endif
+}
+REGISTER_POST_DEINIT(__ssl_gencert_deinit);
+
index f0e76ba7e64be05c66c811c8a9e8ba03ab82c02d..0c5fe96f229729a221ccb7cfc05349ef312bf803 100644 (file)
@@ -72,6 +72,7 @@
 #include <haproxy/shctx.h>
 #include <haproxy/ssl_ckch.h>
 #include <haproxy/ssl_crtlist.h>
+#include <haproxy/ssl_gencert.h>
 #include <haproxy/ssl_sock.h>
 #include <haproxy/ssl_utils.h>
 #include <haproxy/stats.h>
@@ -504,38 +505,8 @@ static HASSL_DH *global_dh = NULL;
 static HASSL_DH *local_dh_1024 = NULL;
 static HASSL_DH *local_dh_2048 = NULL;
 static HASSL_DH *local_dh_4096 = NULL;
-#if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
-static DH *ssl_get_tmp_dh_cbk(SSL *ssl, int export, int keylen);
-#else
-static void ssl_sock_set_tmp_dh_from_pkey(SSL_CTX *ctx, EVP_PKEY *pkey);
-#endif
 #endif /* OPENSSL_NO_DH */
 
-#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
-/* X509V3 Extensions that will be added on generated certificates */
-#define X509V3_EXT_SIZE 5
-static char *x509v3_ext_names[X509V3_EXT_SIZE] = {
-       "basicConstraints",
-       "nsComment",
-       "subjectKeyIdentifier",
-       "authorityKeyIdentifier",
-       "keyUsage",
-};
-static char *x509v3_ext_values[X509V3_EXT_SIZE] = {
-       "CA:FALSE",
-       "\"OpenSSL Generated Certificate\"",
-       "hash",
-       "keyid,issuer:always",
-       "nonRepudiation,digitalSignature,keyEncipherment"
-};
-/* LRU cache to store generated certificate */
-static struct lru64_head *ssl_ctx_lru_tree = NULL;
-static unsigned int       ssl_ctx_lru_seed = 0;
-static unsigned int      ssl_ctx_serial;
-__decl_rwlock(ssl_ctx_lru_rwlock);
-
-#endif // SSL_CTRL_SET_TLSEXT_HOSTNAME
-
 /* The order here matters for picking a default context,
  * keep the most common keytype at the bottom of the list
  */
@@ -1891,350 +1862,6 @@ static int ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
 }
 #endif
 
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-#ifndef SSL_NO_GENERATE_CERTIFICATES
-
-/* Configure a DNS SAN extension on a certificate. */
-int ssl_sock_add_san_ext(X509V3_CTX* ctx, X509* cert, const char *servername) {
-       int failure = 0;
-       X509_EXTENSION *san_ext = NULL;
-       CONF *conf = NULL;
-       struct buffer *san_name = get_trash_chunk();
-
-       conf = NCONF_new(NULL);
-       if (!conf) {
-               failure = 1;
-               goto cleanup;
-       }
-
-       /* Build an extension based on the DNS entry above */
-       chunk_appendf(san_name, "DNS:%s", servername);
-       san_ext = X509V3_EXT_nconf_nid(conf, ctx, NID_subject_alt_name, san_name->area);
-       if (!san_ext) {
-               failure = 1;
-               goto cleanup;
-       }
-
-       /* Add the extension */
-       if (!X509_add_ext(cert, san_ext, -1 /* Add to end */)) {
-               failure = 1;
-               goto cleanup;
-       }
-
-       /* Success */
-       failure = 0;
-
-cleanup:
-       if (NULL != san_ext) X509_EXTENSION_free(san_ext);
-       if (NULL != conf) NCONF_free(conf);
-
-       return failure;
-}
-
-static __maybe_unused struct sni_ctx *ssl_sock_chose_sni_ctx(struct bind_conf *s, const char *servername,
-                                                             int have_rsa_sig, int have_ecdsa_sig);
-
-/* Create a X509 certificate with the specified servername and serial. This
- * function returns a SSL_CTX object or NULL if an error occurs. */
-static SSL_CTX *
-ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL *ssl)
-{
-       X509         *cacert  = bind_conf->ca_sign_ckch->cert;
-       EVP_PKEY     *capkey  = bind_conf->ca_sign_ckch->key;
-       SSL_CTX      *ssl_ctx = NULL;
-       X509         *newcrt  = NULL;
-       EVP_PKEY     *pkey    = NULL;
-       SSL          *tmp_ssl = NULL;
-       CONF         *ctmp    = NULL;
-       X509_NAME    *name;
-       const EVP_MD *digest;
-       X509V3_CTX    ctx;
-       unsigned int  i;
-       int           key_type;
-       struct sni_ctx *sni_ctx;
-
-       sni_ctx = ssl_sock_chose_sni_ctx(bind_conf, "", 1, 1);
-       if (!sni_ctx)
-               goto mkcert_error;
-
-       /* Get the private key of the default certificate and use it */
-#ifdef HAVE_SSL_CTX_get0_privatekey
-       pkey = SSL_CTX_get0_privatekey(sni_ctx->ctx);
-#else
-       tmp_ssl = SSL_new(sni_ctx->ctx);
-       if (tmp_ssl)
-               pkey = SSL_get_privatekey(tmp_ssl);
-#endif
-       if (!pkey)
-               goto mkcert_error;
-
-       /* Create the certificate */
-       if (!(newcrt = X509_new()))
-               goto mkcert_error;
-
-       /* Set version number for the certificate (X509v3) and the serial
-        * number */
-       if (X509_set_version(newcrt, 2L) != 1)
-               goto mkcert_error;
-       ASN1_INTEGER_set(X509_get_serialNumber(newcrt), _HA_ATOMIC_ADD_FETCH(&ssl_ctx_serial, 1));
-
-       /* Set duration for the certificate */
-       if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) ||
-           !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365))
-               goto mkcert_error;
-
-       /* set public key in the certificate */
-       if (X509_set_pubkey(newcrt, pkey) != 1)
-               goto mkcert_error;
-
-       /* Set issuer name from the CA */
-       if (!(name = X509_get_subject_name(cacert)))
-               goto mkcert_error;
-       if (X509_set_issuer_name(newcrt, name) != 1)
-               goto mkcert_error;
-
-       /* Set the subject name using the same, but the CN */
-       name = X509_NAME_dup(name);
-       if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
-                                      (const unsigned char *)servername,
-                                      -1, -1, 0) != 1) {
-               X509_NAME_free(name);
-               goto mkcert_error;
-       }
-       if (X509_set_subject_name(newcrt, name) != 1) {
-               X509_NAME_free(name);
-               goto mkcert_error;
-       }
-       X509_NAME_free(name);
-
-       /* Add x509v3 extensions as specified */
-       ctmp = NCONF_new(NULL);
-       X509V3_set_ctx(&ctx, cacert, newcrt, NULL, NULL, 0);
-       for (i = 0; i < X509V3_EXT_SIZE; i++) {
-               X509_EXTENSION *ext;
-
-               if (!(ext = X509V3_EXT_nconf(ctmp, &ctx, x509v3_ext_names[i], x509v3_ext_values[i])))
-                       goto mkcert_error;
-               if (!X509_add_ext(newcrt, ext, -1)) {
-                       X509_EXTENSION_free(ext);
-                       goto mkcert_error;
-               }
-               X509_EXTENSION_free(ext);
-       }
-
-       /* Add SAN extension */
-       if (ssl_sock_add_san_ext(&ctx, newcrt, servername)) {
-               goto mkcert_error;
-       }
-
-       /* Sign the certificate with the CA private key */
-
-       key_type = EVP_PKEY_base_id(capkey);
-
-       if (key_type == EVP_PKEY_DSA)
-               digest = EVP_sha1();
-       else if (key_type == EVP_PKEY_RSA)
-               digest = EVP_sha256();
-       else if (key_type == EVP_PKEY_EC)
-               digest = EVP_sha256();
-       else {
-#ifdef ASN1_PKEY_CTRL_DEFAULT_MD_NID
-               int nid;
-
-               if (EVP_PKEY_get_default_digest_nid(capkey, &nid) <= 0)
-                       goto mkcert_error;
-               if (!(digest = EVP_get_digestbynid(nid)))
-                       goto mkcert_error;
-#else
-               goto mkcert_error;
-#endif
-       }
-
-       if (!(X509_sign(newcrt, capkey, digest)))
-               goto mkcert_error;
-
-       /* Create and set the new SSL_CTX */
-       if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
-               goto mkcert_error;
-       if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
-               goto mkcert_error;
-       if (!SSL_CTX_use_certificate(ssl_ctx, newcrt))
-               goto mkcert_error;
-       if (!SSL_CTX_check_private_key(ssl_ctx))
-               goto mkcert_error;
-
-       /* Build chaining the CA cert and the rest of the chain, keep these order */
-#if defined(SSL_CTX_add1_chain_cert)
-       if (!SSL_CTX_add1_chain_cert(ssl_ctx, bind_conf->ca_sign_ckch->cert)) {
-               goto mkcert_error;
-       }
-
-       if (bind_conf->ca_sign_ckch->chain) {
-               for (i = 0; i < sk_X509_num(bind_conf->ca_sign_ckch->chain); i++) {
-                       X509 *chain_cert = sk_X509_value(bind_conf->ca_sign_ckch->chain, i);
-                       if (!SSL_CTX_add1_chain_cert(ssl_ctx, chain_cert)) {
-                               goto mkcert_error;
-                       }
-               }
-       }
-#endif
-
-       if (newcrt) X509_free(newcrt);
-
-#ifndef OPENSSL_NO_DH
-#if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
-       SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_get_tmp_dh_cbk);
-#else
-       ssl_sock_set_tmp_dh_from_pkey(ssl_ctx, pkey);
-#endif
-#endif
-
-#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
-#if defined(SSL_CTX_set1_curves_list)
-       {
-               const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
-               if (!SSL_CTX_set1_curves_list(ssl_ctx, ecdhe))
-                       goto end;
-       }
-#endif
-#else
-#if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
-       {
-               const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
-               EC_KEY     *ecc;
-               int         nid;
-
-               if ((nid = OBJ_sn2nid(ecdhe)) == NID_undef)
-                       goto end;
-               if (!(ecc = EC_KEY_new_by_curve_name(nid)))
-                       goto end;
-               SSL_CTX_set_tmp_ecdh(ssl_ctx, ecc);
-               EC_KEY_free(ecc);
-       }
-#endif /* defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH) */
-#endif /* HA_OPENSSL_VERSION_NUMBER >= 0x10101000L */
- end:
-       return ssl_ctx;
-
- mkcert_error:
-       if (ctmp) NCONF_free(ctmp);
-       if (tmp_ssl) SSL_free(tmp_ssl);
-       if (ssl_ctx) SSL_CTX_free(ssl_ctx);
-       if (newcrt)  X509_free(newcrt);
-       return NULL;
-}
-
-
-/* Do a lookup for a certificate in the LRU cache used to store generated
- * certificates and immediately assign it to the SSL session if not null. */
-SSL_CTX *
-ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind_conf, SSL *ssl)
-{
-       struct lru64 *lru = NULL;
-
-       if (ssl_ctx_lru_tree) {
-               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-               lru = lru64_lookup(key, ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
-               if (lru && lru->domain) {
-                       if (ssl)
-                               SSL_set_SSL_CTX(ssl, (SSL_CTX *)lru->data);
-                       HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-                       return (SSL_CTX *)lru->data;
-               }
-               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-       }
-       return NULL;
-}
-
-/* Same as <ssl_sock_assign_generated_cert> but without SSL session. This
- * function is not thread-safe, it should only be used to check if a certificate
- * exists in the lru cache (with no warranty it will not be removed by another
- * thread). It is kept for backward compatibility. */
-SSL_CTX *
-ssl_sock_get_generated_cert(unsigned int key, struct bind_conf *bind_conf)
-{
-       return ssl_sock_assign_generated_cert(key, bind_conf, NULL);
-}
-
-/* Set a certificate int the LRU cache used to store generated
- * certificate. Return 0 on success, otherwise -1 */
-int
-ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int key, struct bind_conf *bind_conf)
-{
-       struct lru64 *lru = NULL;
-
-       if (ssl_ctx_lru_tree) {
-               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-               lru = lru64_get(key, ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
-               if (!lru) {
-                       HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-                       return -1;
-               }
-               if (lru->domain && lru->data)
-                       lru->free((SSL_CTX *)lru->data);
-               lru64_commit(lru, ssl_ctx, bind_conf->ca_sign_ckch->cert, 0, (void (*)(void *))SSL_CTX_free);
-               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-               return 0;
-       }
-       return -1;
-}
-
-/* Compute the key of the certificate. */
-unsigned int
-ssl_sock_generated_cert_key(const void *data, size_t len)
-{
-       return XXH32(data, len, ssl_ctx_lru_seed);
-}
-
-/* Generate a cert and immediately assign it to the SSL session so that the cert's
- * refcount is maintained regardless of the cert's presence in the LRU cache.
- */
-static int
-ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf, SSL *ssl)
-{
-       X509         *cacert  = bind_conf->ca_sign_ckch->cert;
-       SSL_CTX      *ssl_ctx = NULL;
-       struct lru64 *lru     = NULL;
-       unsigned int  key;
-
-       key = ssl_sock_generated_cert_key(servername, strlen(servername));
-       if (ssl_ctx_lru_tree) {
-               HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-               lru = lru64_get(key, ssl_ctx_lru_tree, cacert, 0);
-               if (lru && lru->domain)
-                       ssl_ctx = (SSL_CTX *)lru->data;
-               if (!ssl_ctx && lru) {
-                       ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
-                       lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
-               }
-               SSL_set_SSL_CTX(ssl, ssl_ctx);
-               HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
-               return 1;
-       }
-       else {
-               ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
-               SSL_set_SSL_CTX(ssl, ssl_ctx);
-               /* No LRU cache, this CTX will be released as soon as the session dies */
-               SSL_CTX_free(ssl_ctx);
-               return 1;
-       }
-       return 0;
-}
-static int
-ssl_sock_generate_certificate_from_conn(struct bind_conf *bind_conf, SSL *ssl)
-{
-       unsigned int key;
-       struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
-
-       if (conn_get_dst(conn)) {
-               key = ssl_sock_generated_cert_key(conn->dst, get_addr_len(conn->dst));
-               if (ssl_sock_assign_generated_cert(key, bind_conf, ssl))
-                       return 1;
-       }
-       return 0;
-}
-#endif /* !defined SSL_NO_GENERATE_CERTIFICATES */
-
 #if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL)
 
 static void ctx_set_SSLv3_func(SSL_CTX *ctx, set_context_func c)
@@ -2340,7 +1967,7 @@ static void ssl_sock_switchctx_set(SSL *ssl, SSL_CTX *ctx)
  *
  * This function does a lookup in the bind_conf sni tree so the caller should lock its tree.
  */
-static __maybe_unused struct sni_ctx *ssl_sock_chose_sni_ctx(struct bind_conf *s, const char *servername,
+struct sni_ctx *ssl_sock_chose_sni_ctx(struct bind_conf *s, const char *servername,
                                                              int have_rsa_sig, int have_ecdsa_sig)
 {
        struct ebmb_node *node, *n, *node_ecdsa = NULL, *node_rsa = NULL, *node_anonymous = NULL;
@@ -2827,7 +2454,6 @@ sni_lookup:
        return SSL_TLSEXT_ERR_OK;
 }
 #endif /* (!) OPENSSL_IS_BORINGSSL */
-#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
 
 #if defined(USE_OPENSSL_WOLFSSL)
 /* This implement the equivalent of the clientHello Callback but using the cert_cb.
@@ -3235,7 +2861,7 @@ static HASSL_DH *ssl_get_tmp_dh(EVP_PKEY *pkey)
 #if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
 /* Returns Diffie-Hellman parameters matching the private key length
    but not exceeding global_ssl.default_dh_param */
-static HASSL_DH *ssl_get_tmp_dh_cbk(SSL *ssl, int export, int keylen)
+HASSL_DH *ssl_get_tmp_dh_cbk(SSL *ssl, int export, int keylen)
 {
        EVP_PKEY *pkey = SSL_get_privatekey(ssl);
 
@@ -3261,7 +2887,7 @@ static int ssl_sock_set_tmp_dh(SSL_CTX *ctx, HASSL_DH *dh)
 }
 
 #if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL)
-static void ssl_sock_set_tmp_dh_from_pkey(SSL_CTX *ctx, EVP_PKEY *pkey)
+void ssl_sock_set_tmp_dh_from_pkey(SSL_CTX *ctx, EVP_PKEY *pkey)
 {
        HASSL_DH *dh = NULL;
        if (pkey && (dh = ssl_get_tmp_dh(pkey))) {
@@ -5760,81 +5386,6 @@ void ssl_sock_destroy_bind_conf(struct bind_conf *bind_conf)
        bind_conf->ca_sign_file = NULL;
 }
 
-/* Load CA cert file and private key used to generate certificates */
-int
-ssl_sock_load_ca(struct bind_conf *bind_conf)
-{
-       struct proxy *px = bind_conf->frontend;
-       struct ckch_data *data = NULL;
-       int ret = 0;
-       char *err = NULL;
-
-       if (!(bind_conf->options & BC_O_GENERATE_CERTS))
-               return ret;
-
-#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
-       if (global_ssl.ctx_cache) {
-               ssl_ctx_lru_tree = lru64_new(global_ssl.ctx_cache);
-       }
-       ssl_ctx_lru_seed = (unsigned int)time(NULL);
-       ssl_ctx_serial   = now_ms;
-#endif
-
-       if (!bind_conf->ca_sign_file) {
-               ha_alert("Proxy '%s': cannot enable certificate generation, "
-                        "no CA certificate File configured at [%s:%d].\n",
-                        px->id, bind_conf->file, bind_conf->line);
-               goto failed;
-       }
-
-       /* Allocate cert structure */
-       data = calloc(1, sizeof(*data));
-       if (!data) {
-               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain allocation failure\n",
-                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
-               goto failed;
-       }
-
-       /* Try to parse file */
-       if (ssl_sock_load_files_into_ckch(bind_conf->ca_sign_file, data, &err)) {
-               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain loading failed: %s\n",
-                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line, err);
-               free(err);
-               goto failed;
-       }
-
-       /* Fail if missing cert or pkey */
-       if ((!data->cert) || (!data->key)) {
-               ha_alert("Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. Chain missing certificate or private key\n",
-                       px->id, bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
-               goto failed;
-       }
-
-       /* Final assignment to bind */
-       bind_conf->ca_sign_ckch = data;
-       return ret;
-
- failed:
-       if (data) {
-               ssl_sock_free_cert_key_and_chain_contents(data);
-               free(data);
-       }
-
-       bind_conf->options &= ~BC_O_GENERATE_CERTS;
-       ret++;
-       return ret;
-}
-
-/* Release CA cert and private key used to generate certificated */
-void
-ssl_sock_free_ca(struct bind_conf *bind_conf)
-{
-       if (bind_conf->ca_sign_ckch) {
-               ssl_sock_free_cert_key_and_chain_contents(bind_conf->ca_sign_ckch);
-               ha_free(&bind_conf->ca_sign_ckch);
-       }
-}
-
 /*
  * Try to allocate the BIO and SSL session objects of <conn> connection with <bio> and
  * <ssl> as addresses, <bio_meth> as BIO method and <ssl_ctx> as SSL context inherited settings.
@@ -8082,12 +7633,6 @@ void ssl_free_dh(void) {
 
 static void __ssl_sock_deinit(void)
 {
-#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
-       if (ssl_ctx_lru_tree) {
-               lru64_destroy(ssl_ctx_lru_tree);
-               HA_RWLOCK_DESTROY(&ssl_ctx_lru_rwlock);
-       }
-#endif
 
 #if (HA_OPENSSL_VERSION_NUMBER < 0x10100000L)
         ERR_remove_state(0);