summaryrefslogtreecommitdiffstats
path: root/src/ssl_sock.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ssl_sock.c844
1 files changed, 249 insertions, 595 deletions
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 96d826e..e6bf3ff 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -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>
@@ -135,9 +136,12 @@ struct global_ssl global_ssl = {
#ifdef HAVE_SSL_KEYLOG
.keylog = 0,
#endif
+ .security_level = -1,
#ifndef OPENSSL_NO_OCSP
.ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
.ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
+ .ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_OFF,
+ .ocsp_update.disable = 0,
#endif
};
@@ -156,7 +160,7 @@ enum {
SSL_ST_STATS_COUNT /* must be the last member of the enum */
};
-static struct name_desc ssl_stats[] = {
+static struct stat_col ssl_stats[] = {
[SSL_ST_SESS] = { .name = "ssl_sess",
.desc = "Total number of ssl sessions established" },
[SSL_ST_REUSED_SESS] = { .name = "ssl_reused_sess",
@@ -171,13 +175,37 @@ static struct ssl_counters {
long long failed_handshake;
} ssl_counters;
-static void ssl_fill_stats(void *data, struct field *stats)
+static int ssl_fill_stats(void *data, struct field *stats, unsigned int *selected_field)
{
struct ssl_counters *counters = data;
+ unsigned int current_field = (selected_field != NULL ? *selected_field : 0);
- stats[SSL_ST_SESS] = mkf_u64(FN_COUNTER, counters->sess);
- stats[SSL_ST_REUSED_SESS] = mkf_u64(FN_COUNTER, counters->reused_sess);
- stats[SSL_ST_FAILED_HANDSHAKE] = mkf_u64(FN_COUNTER, counters->failed_handshake);
+ for (; current_field < SSL_ST_STATS_COUNT; current_field++) {
+ struct field metric = { 0 };
+
+ switch (current_field) {
+ case SSL_ST_SESS:
+ metric = mkf_u64(FN_COUNTER, counters->sess);
+ break;
+ case SSL_ST_REUSED_SESS:
+ metric = mkf_u64(FN_COUNTER, counters->reused_sess);
+ break;
+ case SSL_ST_FAILED_HANDSHAKE:
+ metric = mkf_u64(FN_COUNTER, counters->failed_handshake);
+ break;
+ default:
+ /* not used for frontends. If a specific metric
+ * is requested, return an error. Otherwise continue.
+ */
+ if (selected_field != NULL)
+ return 0;
+ continue;
+ }
+ stats[current_field] = metric;
+ if (selected_field != NULL)
+ break;
+ }
+ return 1;
}
static struct stats_module ssl_stats_module = {
@@ -504,38 +532,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
*/
@@ -1109,40 +1107,40 @@ static int tlskeys_finalize_config(void)
* Returns 1 if no ".ocsp" file found, 0 if OCSP status extension is
* successfully enabled, or -1 in other error case.
*/
-static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *data, STACK_OF(X509) *chain)
+static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_store *store, STACK_OF(X509) *chain)
{
+ struct ckch_data *data = store->data;
X509 *x, *issuer;
int i, ret = -1;
struct certificate_ocsp *ocsp = NULL, *iocsp;
char *warn = NULL;
unsigned char *p;
-#ifndef USE_OPENSSL_WOLFSSL
-#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
- int (*callback) (SSL *, void *);
-#else
- void (*callback) (void);
-#endif
+#ifdef USE_OPENSSL_WOLFSSL
+ /* typedef int(*tlsextStatusCb)(WOLFSSL* ssl, void*); */
+ tlsextStatusCb callback = NULL;
+#elif (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ int (*callback) (SSL *, void *) = NULL;
#else
- tlsextStatusCb callback;
+ void (*callback) (void) = NULL;
#endif
struct buffer *ocsp_uri = get_trash_chunk();
char *err = NULL;
size_t path_len;
+ int inc_refcount_store = 0;
+ int enable_auto_update = (store->conf.ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) ||
+ (store->conf.ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT &&
+ global_ssl.ocsp_update.mode == SSL_SOCK_OCSP_UPDATE_ON);
x = data->cert;
if (!x)
goto out;
ssl_ocsp_get_uri_from_cert(x, ocsp_uri, &err);
- /* We should have an "OCSP URI" field in order for auto update to work. */
- if (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON && b_data(ocsp_uri) == 0)
- goto out;
-
- /* In case of ocsp update mode set to 'on', this function might be
- * called with no known ocsp response. If no ocsp uri can be found in
- * the certificate, nothing needs to be done here. */
if (!data->ocsp_response && !data->ocsp_cid) {
- if (data->ocsp_update_mode != SSL_SOCK_OCSP_UPDATE_ON || b_data(ocsp_uri) == 0) {
+ /* In case of ocsp update mode set to 'on', this function might
+ * be called with no known ocsp response. If no ocsp uri can be
+ * found in the certificate, nothing needs to be done here. */
+ if (!enable_auto_update || b_data(ocsp_uri) == 0) {
ret = 0;
goto out;
}
@@ -1163,8 +1161,10 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
if (!issuer)
goto out;
- if (!data->ocsp_cid)
+ if (!data->ocsp_cid) {
data->ocsp_cid = OCSP_cert_to_id(0, x, issuer);
+ inc_refcount_store = 1;
+ }
if (!data->ocsp_cid)
goto out;
@@ -1185,12 +1185,11 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
if (iocsp == ocsp)
ocsp = NULL;
-#ifndef SSL_CTX_get_tlsext_status_cb
-# define SSL_CTX_get_tlsext_status_cb(ctx, cb) \
- *cb = (void (*) (void))ctx->tlsext_status_cb;
-#endif
SSL_CTX_get_tlsext_status_cb(ctx, &callback);
+ if (inc_refcount_store)
+ iocsp->refcount_store++;
+
if (!callback) {
struct ocsp_cbk_arg *cb_arg;
EVP_PKEY *pkey;
@@ -1282,7 +1281,7 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
*/
memcpy(iocsp->path, path, path_len + 1);
- if (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
+ if (enable_auto_update) {
ssl_ocsp_update_insert(iocsp);
/* If we are during init the update task is not
* scheduled yet so a wakeup won't do anything.
@@ -1294,7 +1293,7 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
if (ocsp_update_task)
task_wakeup(ocsp_update_task, TASK_WOKEN_MSG);
}
- } else if (iocsp->uri && data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
+ } else if (iocsp->uri && enable_auto_update) {
/* This unlikely case can happen if a series of "del ssl
* crt-list" / "add ssl crt-list" commands are made on the CLI.
* In such a case, the OCSP response tree entry will be created
@@ -1910,342 +1909,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;
-}
-
-/* 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;
-
- /* Get the private key of the default certificate and use it */
-#ifdef HAVE_SSL_CTX_get0_privatekey
- pkey = SSL_CTX_get0_privatekey(bind_conf->default_ctx);
-#else
- tmp_ssl = SSL_new(bind_conf->default_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)
@@ -2351,7 +2014,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;
@@ -2365,6 +2028,9 @@ static __maybe_unused struct sni_ctx *ssl_sock_chose_sni_ctx(struct bind_conf *s
break;
}
}
+ /* if the servername is empty look for the default in the wildcard list */
+ if (!*servername)
+ wildp = servername;
/* Look for an ECDSA, RSA and DSA certificate, first in the single
* name and if not found in the wildcard */
@@ -2463,7 +2129,8 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
int has_rsa_sig = 0, has_ecdsa_sig = 0;
struct sni_ctx *sni_ctx;
const char *servername;
- size_t servername_len;
+ size_t servername_len = 0;
+ int default_lookup = 0; /* did we lookup for a default yet? */
int allow_early = 0;
int i;
@@ -2551,14 +2218,16 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
goto allow_early;
}
#endif
- /* without SNI extension, is the default_ctx (need SSL_TLSEXT_ERR_NOACK) */
- if (!s->strict_sni) {
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- ssl_sock_switchctx_set(ssl, s->default_ctx);
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
- }
- goto abort;
+
+ /* no servername field is not compatible with strict-sni */
+ if (s->strict_sni)
+ goto abort;
+
+ /* without servername extension, look for the defaults which is
+ * defined by an empty servername string */
+ servername = "";
+ servername_len = 0;
+ default_lookup = 1;
}
/* extract/check clientHello information */
@@ -2634,14 +2303,14 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
}
}
+sni_lookup:
/* we need to transform this a NULL-ended string in lowecase */
for (i = 0; i < trash.size && i < servername_len; i++)
trash.area[i] = tolower(servername[i]);
trash.area[i] = 0;
- servername = trash.area;
HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- sni_ctx = ssl_sock_chose_sni_ctx(s, servername, has_rsa_sig, has_ecdsa_sig);
+ sni_ctx = ssl_sock_chose_sni_ctx(s, trash.area, has_rsa_sig, has_ecdsa_sig);
if (sni_ctx) {
/* switch ctx */
struct ssl_bind_conf *conf = sni_ctx->conf;
@@ -2658,17 +2327,20 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
#if (!defined SSL_NO_GENERATE_CERTIFICATES)
- if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate(servername, s, ssl)) {
+ if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate(trash.area, s, ssl)) {
/* switch ctx done in ssl_sock_generate_certificate */
goto allow_early;
}
#endif
- if (!s->strict_sni) {
- /* no certificate match, is the default_ctx */
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- ssl_sock_switchctx_set(ssl, s->default_ctx);
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
+
+ if (!s->strict_sni && !default_lookup) {
+ /* we didn't find a SNI, and we didn't look for a default
+ * look again to find a matching default cert */
+ servername = "";
+ servername_len = 0;
+ default_lookup = 1;
+
+ goto sni_lookup;
}
/* We are about to raise an handshake error so the servername extension
@@ -2722,6 +2394,7 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
const char *wildp = NULL;
struct ebmb_node *node, *n;
struct bind_conf *s = priv;
+ int default_lookup = 0; /* did we lookup for a default yet? */
#ifdef USE_QUIC
const uint8_t *extension_data;
size_t extension_len;
@@ -2761,12 +2434,15 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
#endif
if (s->strict_sni)
return SSL_TLSEXT_ERR_ALERT_FATAL;
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- ssl_sock_switchctx_set(ssl, s->default_ctx);
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- return SSL_TLSEXT_ERR_NOACK;
+
+ /* without servername extension, look for the defaults which is
+ * defined by an empty servername string */
+ servername = "";
+ default_lookup = 1;
}
+sni_lookup:
+
for (i = 0; i < trash.size; i++) {
if (!servername[i])
break;
@@ -2775,6 +2451,8 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
wildp = &trash.area[i];
}
trash.area[i] = 0;
+ if(!*trash.area) /* handle the default which in wildcard tree */
+ wildp = trash.area;
HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
node = NULL;
@@ -2804,24 +2482,35 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
return SSL_TLSEXT_ERR_OK;
}
#endif
- if (s->strict_sni) {
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- }
- ssl_sock_switchctx_set(ssl, s->default_ctx);
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- return SSL_TLSEXT_ERR_OK;
+
+ if (!s->strict_sni && !default_lookup) {
+ /* we didn't find a SNI, and we didn't look for a default
+ * look again to find a matching default cert */
+ servername = "";
+ default_lookup = 1;
+
+ goto sni_lookup;
+ }
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
+#if defined(OPENSSL_IS_AWSLC)
+ /* Note that ssl_sock_switchctx_set() calls SSL_set_SSL_CTX() which propagates the
+ * "early data enabled" setting from the SSL_CTX object to the SSL objects.
+ * So enable early data for this SSL_CTX context if configured.
+ */
+ if (s->ssl_conf.early_data)
+ SSL_CTX_set_early_data_enabled(container_of(node, struct sni_ctx, name)->ctx, 1);
+#endif
/* switch ctx */
ssl_sock_switchctx_set(ssl, container_of(node, struct sni_ctx, name)->ctx);
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
return SSL_TLSEXT_ERR_OK;
}
#endif /* (!) OPENSSL_IS_BORINGSSL */
-#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
-#if 0 && defined(USE_OPENSSL_WOLFSSL)
+#if defined(USE_OPENSSL_WOLFSSL)
/* This implement the equivalent of the clientHello Callback but using the cert_cb.
* WolfSSL is able to extract the sigalgs and ciphers of the client byt using the API
* provided in https://github.com/wolfSSL/wolfssl/pull/6963
@@ -2833,6 +2522,7 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
struct bind_conf *s = arg;
int has_rsa_sig = 0, has_ecdsa_sig = 0;
const char *servername;
+ int default_lookup = 0;
struct sni_ctx *sni_ctx;
int i;
@@ -2844,14 +2534,13 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername) {
- /* without SNI extension, is the default_ctx (need SSL_TLSEXT_ERR_NOACK) */
- if (!s->strict_sni) {
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- ssl_sock_switchctx_set(ssl, s->default_ctx);
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
- }
- goto abort;
+ if (s->strict_sni)
+ goto abort;
+
+ /* without servername extension, look for the defaults which is
+ * defined by an empty servername string */
+ servername = "";
+ default_lookup = 1;
}
/* extract sigalgs and ciphers */
@@ -2895,6 +2584,8 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
}
}
+sni_lookup:
+
/* we need to transform this into a NULL-ended string in lowecase */
for (i = 0; i < trash.size && servername[i] != '\0'; i++)
trash.area[i] = tolower(servername[i]);
@@ -2916,12 +2607,13 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
}
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- if (!s->strict_sni) {
- /* no certificate match, is the default_ctx */
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- ssl_sock_switchctx_set(ssl, s->default_ctx);
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
+ if (!s->strict_sni && !default_lookup) {
+ /* we didn't find a SNI, and we didn't look for a default
+ * look again to find a matching default cert */
+ servername = "";
+ default_lookup = 1;
+
+ goto sni_lookup;
}
/* We are about to raise an handshake error so the servername extension
@@ -3224,7 +2916,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);
@@ -3250,7 +2942,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))) {
@@ -3335,7 +3027,7 @@ static int ckch_inst_add_cert_sni(SSL_CTX *ctx, struct ckch_inst *ckch_inst,
struct pkey_info kinfo, char *name, int order)
{
struct sni_ctx *sc;
- int wild = 0, neg = 0;
+ int wild = 0, neg = 0, default_crt = 0;
if (*name == '!') {
neg = 1;
@@ -3344,11 +3036,14 @@ static int ckch_inst_add_cert_sni(SSL_CTX *ctx, struct ckch_inst *ckch_inst,
if (*name == '*') {
wild = 1;
name++;
+ /* if this was only a '*' filter, this is a default cert */
+ if (!*name)
+ default_crt = 1;
}
/* !* filter is a nop */
if (neg && wild)
return order;
- if (*name) {
+ if (*name || default_crt) {
int j, len;
len = strlen(name);
for (j = 0; j < len && j < trash.size; j++)
@@ -3420,14 +3115,6 @@ void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf *bind_
else
ebst_insert(&bind_conf->sni_ctx, &sc0->name);
}
-
- /* replace the default_ctx if required with the instance's ctx. */
- if (ckch_inst->is_default) {
- SSL_CTX_free(bind_conf->default_ctx);
- SSL_CTX_up_ref(ckch_inst->ctx);
- bind_conf->default_ctx = ckch_inst->ctx;
- bind_conf->default_inst = ckch_inst;
- }
}
/*
@@ -3625,9 +3312,10 @@ end:
* The value 0 means there is no error nor warning and
* the operation succeed.
*/
-static int ssl_sock_put_ckch_into_ctx(const char *path, struct ckch_data *data, SSL_CTX *ctx, char **err)
+static int ssl_sock_put_ckch_into_ctx(const char *path, struct ckch_store *store, SSL_CTX *ctx, char **err)
{
int errcode = 0;
+ struct ckch_data *data = store->data;
STACK_OF(X509) *find_chain = NULL;
ERR_clear_error();
@@ -3679,7 +3367,7 @@ static int ssl_sock_put_ckch_into_ctx(const char *path, struct ckch_data *data,
* ocsp tree even if no ocsp_response was known during init, unless the
* frontend's conf disables ocsp update explicitly.
*/
- if (ssl_sock_load_ocsp(path, ctx, data, find_chain) < 0) {
+ if (ssl_sock_load_ocsp(path, ctx, store, find_chain) < 0) {
if (data->ocsp_response)
memprintf(err, "%s '%s.ocsp' is present and activates OCSP but it is impossible to compute the OCSP certificate ID (maybe the issuer could not be found)'.\n",
err && *err ? *err : "", path);
@@ -3744,7 +3432,7 @@ end:
* ERR_WARN if a warning is available into err
*/
int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
- struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, struct ckch_inst **ckchi, char **err)
+ struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, int is_default, struct ckch_inst **ckchi, char **err)
{
SSL_CTX *ctx;
int i;
@@ -3775,7 +3463,10 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
goto error;
}
- errcode |= ssl_sock_put_ckch_into_ctx(path, data, ctx, err);
+ if (global_ssl.security_level > -1)
+ SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
+ errcode |= ssl_sock_put_ckch_into_ctx(path, ckchs, ctx, err);
if (errcode & ERR_CODE)
goto error;
@@ -3857,20 +3548,16 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
* the tree, so it will be discovered and cleaned in time.
*/
-#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if (bind_conf->default_ctx) {
- memprintf(err, "%sthis version of openssl cannot load multiple SSL certificates.\n",
- err && *err ? *err : "");
- errcode |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-#endif
- if (!bind_conf->default_ctx) {
- bind_conf->default_ctx = ctx;
- bind_conf->default_ssl_conf = ssl_conf;
+ if (is_default) {
ckch_inst->is_default = 1;
- SSL_CTX_up_ref(ctx);
- bind_conf->default_inst = ckch_inst;
+
+ /* insert an empty SNI which will be used to lookup default certificate */
+ order = ckch_inst_add_cert_sni(ctx, ckch_inst, bind_conf, ssl_conf, kinfo, "*", order);
+ if (order < 0) {
+ memprintf(err, "%sunable to create a sni context.\n", err && *err ? *err : "");
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto error;
+ }
}
/* Always keep a reference to the newly constructed SSL_CTX in the
@@ -3892,9 +3579,6 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
error:
/* free the allocated sni_ctxs */
if (ckch_inst) {
- if (ckch_inst->is_default)
- SSL_CTX_free(ctx);
-
ckch_inst_free(ckch_inst);
ckch_inst = NULL;
}
@@ -3936,6 +3620,9 @@ int ckch_inst_new_load_srv_store(const char *path, struct ckch_store *ckchs,
goto error;
}
+ if (global_ssl.security_level > -1)
+ SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
errcode |= ssl_sock_put_srv_ckch_into_ctx(path, data, ctx, err);
if (errcode & ERR_CODE)
goto error;
@@ -3967,12 +3654,14 @@ error:
/* Returns a set of ERR_* flags possibly with an error in <err>. */
static int ssl_sock_load_ckchs(const char *path, struct ckch_store *ckchs,
struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
- char **sni_filter, int fcount, struct ckch_inst **ckch_inst, char **err)
+ char **sni_filter, int fcount,
+ int is_default,
+ struct ckch_inst **ckch_inst, char **err)
{
int errcode = 0;
/* we found the ckchs in the tree, we can use it directly */
- errcode |= ckch_inst_new_load_store(path, ckchs, bind_conf, ssl_conf, sni_filter, fcount, ckch_inst, err);
+ errcode |= ckch_inst_new_load_store(path, ckchs, bind_conf, ssl_conf, sni_filter, fcount, is_default, ckch_inst, err);
if (errcode & ERR_CODE)
return errcode;
@@ -4081,9 +3770,17 @@ int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf *bind_con
list_for_each_entry(entry, &crtlist->ord_entries, by_crtlist) {
struct ckch_store *store;
struct ckch_inst *ckch_inst = NULL;
+ int is_default = 0;
store = entry->node.key;
- cfgerr |= ssl_sock_load_ckchs(store->path, store, bind_conf, entry->ssl_conf, entry->filters, entry->fcount, &ckch_inst, err);
+
+ /* if the SNI trees were empty the first "crt" become a default certificate,
+ * it can be applied on multiple certificates if it's a bundle */
+ if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx))
+ is_default = 1;
+
+
+ cfgerr |= ssl_sock_load_ckchs(store->path, store, bind_conf, entry->ssl_conf, entry->filters, entry->fcount, is_default, &ckch_inst, err);
if (cfgerr & ERR_CODE) {
memprintf(err, "error processing line %d in file '%s' : %s", entry->linenum, file, *err);
goto error;
@@ -4125,7 +3822,7 @@ error:
}
/* Returns a set of ERR_* flags possibly with an error in <err>. */
-int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
+int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, int is_default, char **err)
{
struct stat buf;
int cfgerr = 0;
@@ -4133,25 +3830,32 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
struct ckch_inst *ckch_inst = NULL;
int found = 0; /* did we found a file to load ? */
+ /* if the SNI trees were empty the first "crt" become a default certificate,
+ * it can be applied on multiple certificates if it's a bundle */
+ if (is_default == 0) {
+ if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx))
+ is_default = 1;
+ }
+
if ((ckchs = ckchs_lookup(path))) {
- /* we found the ckchs in the tree, we can use it directly */
- cfgerr |= ssl_sock_load_ckchs(path, ckchs, bind_conf, NULL, NULL, 0, &ckch_inst, err);
- /* This certificate has an 'ocsp-update' already set in a
- * previous crt-list so we must raise an error. */
- if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
- memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err: "", path);
- cfgerr |= ERR_ALERT | ERR_FATAL;
- }
+ cfgerr |= ckch_conf_cmp_empty(&ckchs->conf, err);
+ if (cfgerr & ERR_CODE) {
+ memprintf(err, "Can't load '%s', is already defined with incompatible parameters:\n %s", path, err ? *err : "");
+ return cfgerr;
+ }
+
+ /* we found the ckchs in the tree, we can use it directly */
+ cfgerr |= ssl_sock_load_ckchs(path, ckchs, bind_conf, NULL, NULL, 0, is_default, &ckch_inst, err);
found++;
} else if (stat(path, &buf) == 0) {
found++;
if (S_ISDIR(buf.st_mode) == 0) {
- ckchs = ckchs_load_cert_file(path, err);
+ ckchs = ckch_store_new_load_files_path(path, err);
if (!ckchs)
cfgerr |= ERR_ALERT | ERR_FATAL;
- cfgerr |= ssl_sock_load_ckchs(path, ckchs, bind_conf, NULL, NULL, 0, &ckch_inst, err);
+ cfgerr |= ssl_sock_load_ckchs(path, ckchs, bind_conf, NULL, NULL, 0, is_default, &ckch_inst, err);
} else {
cfgerr |= ssl_sock_load_cert_list_file(path, 1, bind_conf, bind_conf->frontend, err);
}
@@ -4171,15 +3875,15 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
continue;
if ((ckchs = ckchs_lookup(fp))) {
- cfgerr |= ssl_sock_load_ckchs(fp, ckchs, bind_conf, NULL, NULL, 0, &ckch_inst, err);
+ cfgerr |= ssl_sock_load_ckchs(fp, ckchs, bind_conf, NULL, NULL, 0, is_default, &ckch_inst, err);
found++;
} else {
if (stat(fp, &buf) == 0) {
found++;
- ckchs = ckchs_load_cert_file(fp, err);
+ ckchs = ckch_store_new_load_files_path(fp, err);
if (!ckchs)
cfgerr |= ERR_ALERT | ERR_FATAL;
- cfgerr |= ssl_sock_load_ckchs(fp, ckchs, bind_conf, NULL, NULL, 0, &ckch_inst, err);
+ cfgerr |= ssl_sock_load_ckchs(fp, ckchs, bind_conf, NULL, NULL, 0, is_default, &ckch_inst, err);
}
}
}
@@ -4229,7 +3933,7 @@ int ssl_sock_load_srv_cert(char *path, struct server *server, int create_if_none
/* We do not manage directories on backend side. */
if (S_ISDIR(buf.st_mode) == 0) {
++found;
- ckchs = ckchs_load_cert_file(path, err);
+ ckchs = ckch_store_new_load_files_path(path, err);
if (!ckchs)
cfgerr |= ERR_ALERT | ERR_FATAL;
cfgerr |= ssl_sock_load_srv_ckchs(path, ckchs, server, &server->ssl_ctx.inst, err);
@@ -4274,6 +3978,9 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
ctx = SSL_CTX_new(SSLv23_server_method());
bind_conf->initial_ctx = ctx;
+ if (global_ssl.security_level > -1)
+ SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
if (conf_ssl_methods->flags && (conf_ssl_methods->min || conf_ssl_methods->max))
ha_warning("Proxy '%s': no-sslv3/no-tlsv1x are ignored for bind '%s' at [%s:%d]. "
"Use only 'ssl-min-ver' and 'ssl-max-ver' to fix.\n",
@@ -4384,7 +4091,7 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
# endif /* ! SSL_OP_NO_ANTI_REPLAY */
SSL_CTX_set_client_hello_cb(ctx, ssl_sock_switchctx_cbk, NULL);
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_sock_switchctx_err_cbk);
-# elif 0 && defined(USE_OPENSSL_WOLFSSL)
+# elif defined(USE_OPENSSL_WOLFSSL)
SSL_CTX_set_cert_cb(ctx, ssl_sock_switchctx_wolfSSL_cbk, bind_conf);
# else
/* ! OPENSSL_IS_BORINGSSL && ! HAVE_SSL_CLIENT_HELLO_CB */
@@ -5270,6 +4977,8 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
cfgerr++;
return cfgerr;
}
+ if (global_ssl.security_level > -1)
+ SSL_CTX_set_security_level(ctx, global_ssl.security_level);
srv->ssl_ctx.ctx = ctx;
}
@@ -5429,6 +5138,16 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx)
cfgerr++;
}
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+ SSL_CTX_set_msg_callback(ctx, ssl_sock_msgcbk);
+#endif
+
+#ifdef HAVE_SSL_KEYLOG
+ /* only activate the keylog callback if it was required to prevent performance loss */
+ if (global_ssl.keylog > 0)
+ SSL_CTX_set_keylog_callback(ctx, SSL_CTX_keylog);
+#endif
+
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
if (srv->ssl_ctx.ciphersuites &&
!SSL_CTX_set_ciphersuites(ctx, srv->ssl_ctx.ciphersuites)) {
@@ -5547,16 +5266,12 @@ int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf)
to initial_ctx in ssl_initial_ctx. */
errcode |= ssl_sock_prep_ctx_and_inst(bind_conf, NULL, bind_conf->initial_ctx, NULL, &errmsg);
}
- if (bind_conf->default_ctx) {
- errcode |= ssl_sock_prep_ctx_and_inst(bind_conf, bind_conf->default_ssl_conf, bind_conf->default_ctx, bind_conf->default_inst, &errmsg);
- }
node = ebmb_first(&bind_conf->sni_ctx);
while (node) {
sni = ebmb_entry(node, struct sni_ctx, name);
- if (!sni->order && sni->ctx != bind_conf->default_ctx) {
- /* only initialize the CTX on its first occurrence and
- if it is not the default_ctx */
+ if (!sni->order) {
+ /* only initialize the CTX on its first occurrence */
errcode |= ssl_sock_prep_ctx_and_inst(bind_conf, sni->conf, sni->ctx, sni->ckch_inst, &errmsg);
}
node = ebmb_next(node);
@@ -5565,9 +5280,8 @@ int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf)
node = ebmb_first(&bind_conf->sni_w_ctx);
while (node) {
sni = ebmb_entry(node, struct sni_ctx, name);
- if (!sni->order && sni->ctx != bind_conf->default_ctx) {
- /* only initialize the CTX on its first occurrence and
- if it is not the default_ctx */
+ if (!sni->order) {
+ /* only initialize the CTX on its first occurrence */
errcode |= ssl_sock_prep_ctx_and_inst(bind_conf, sni->conf, sni->ctx, sni->ckch_inst, &errmsg);
}
node = ebmb_next(node);
@@ -5594,14 +5308,17 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf)
int alloc_ctx;
int err;
+ /* check if some certificates were loaded but no ssl keyword is used */
if (!(bind_conf->options & BC_O_USE_SSL)) {
- if (bind_conf->default_ctx) {
+ if (!eb_is_empty(&bind_conf->sni_ctx) || !eb_is_empty(&bind_conf->sni_w_ctx)) {
ha_warning("Proxy '%s': A certificate was specified but SSL was not enabled on bind '%s' at [%s:%d] (use 'ssl').\n",
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
}
return 0;
}
- if (!bind_conf->default_ctx) {
+
+ /* check if we have certificates */
+ if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx)) {
if (bind_conf->strict_sni && !(bind_conf->options & BC_O_GENERATE_CERTS)) {
ha_warning("Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d], ssl connections will fail (use 'crt').\n",
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
@@ -5612,10 +5329,23 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf)
return -1;
}
}
+
+ if ((bind_conf->options & BC_O_GENERATE_CERTS)) {
+ struct sni_ctx *sni_ctx;
+
+ /* if we use the generate-certificates option, look for the first default cert available */
+ sni_ctx = ssl_sock_chose_sni_ctx(bind_conf, "", 1, 1);
+ if (!sni_ctx) {
+ ha_alert("Proxy '%s': no SSL certificate specified for bind '%s' and 'generate-certificates' option at [%s:%d] (use 'crt').\n",
+ px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+ return -1;
+ }
+ }
+
if (!ssl_shctx && global.tune.sslcachesize) {
alloc_ctx = shctx_init(&ssl_shctx, global.tune.sslcachesize,
sizeof(struct sh_ssl_sess_hdr) + SHSESS_BLOCK_MIN_SIZE, -1,
- sizeof(*sh_ssl_sess_tree));
+ sizeof(*sh_ssl_sess_tree), "ssl cache");
if (alloc_ctx <= 0) {
if (alloc_ctx == SHCTX_E_INIT_LOCK)
ha_alert("Unable to initialize the lock for the shared SSL session cache. You can retry using the global statement 'tune.ssl.force-private-cache' but it could increase CPU usage due to renegotiations if nbproc > 1.\n");
@@ -5713,10 +5443,6 @@ void ssl_sock_free_all_ctx(struct bind_conf *bind_conf)
SSL_CTX_free(bind_conf->initial_ctx);
bind_conf->initial_ctx = NULL;
- SSL_CTX_free(bind_conf->default_ctx);
- bind_conf->default_ctx = NULL;
- bind_conf->default_inst = NULL;
- bind_conf->default_ssl_conf = NULL;
}
@@ -5746,81 +5472,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.
@@ -6060,7 +5711,7 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx)
#ifdef SSL_READ_EARLY_DATA_SUCCESS
if (bc->ssl_conf.early_data) {
- b_alloc(&ctx->early_buf);
+ b_alloc(&ctx->early_buf, DB_MUX_RX);
SSL_set_max_early_data(ctx->ssl,
/* Only allow early data if we managed to allocate
* a buffer.
@@ -6516,19 +6167,26 @@ static int ssl_unsubscribe(struct connection *conn, void *xprt_ctx, int event_ty
* It should be called with the takeover lock for the old thread held.
* Returns 0 on success, and -1 on failure
*/
-static int ssl_takeover(struct connection *conn, void *xprt_ctx, int orig_tid)
+static int ssl_takeover(struct connection *conn, void *xprt_ctx, int orig_tid, int release)
{
struct ssl_sock_ctx *ctx = xprt_ctx;
- struct tasklet *tl = tasklet_new();
+ struct tasklet *tl = NULL;
- if (!tl)
- return -1;
+ if (!release) {
+ tl = tasklet_new();
+ if (!tl)
+ return -1;
+ }
ctx->wait_event.tasklet->context = NULL;
tasklet_wakeup_on(ctx->wait_event.tasklet, orig_tid);
+
ctx->wait_event.tasklet = tl;
- ctx->wait_event.tasklet->process = ssl_sock_io_cb;
- ctx->wait_event.tasklet->context = ctx;
+ if (!release) {
+ ctx->wait_event.tasklet->process = ssl_sock_io_cb;
+ ctx->wait_event.tasklet->context = ctx;
+ }
+
return 0;
}
@@ -6558,7 +6216,7 @@ static void ssl_set_used(struct connection *conn, void *xprt_ctx)
if (!ctx || !ctx->wait_event.tasklet)
return;
- HA_ATOMIC_OR(&ctx->wait_event.tasklet->state, TASK_F_USR1);
+ HA_ATOMIC_AND(&ctx->wait_event.tasklet->state, ~TASK_F_USR1);
if (ctx->xprt)
xprt_set_used(conn, ctx->xprt, ctx->xprt_ctx);
}
@@ -7873,6 +7531,8 @@ static void __ssl_sock_init(void)
xprt_register(XPRT_SSL, &ssl_sock);
#if HA_OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
+#elif HA_OPENSSL_VERSION_NUMBER >= 0x10100000L
+ OPENSSL_init_ssl(0, NULL);
#endif
#if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION))
cm = SSL_COMP_get_compression_methods();
@@ -8068,12 +7728,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);