SSL_LDFLAGS := $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
endif
USE_SSL := $(if $(USE_SSL:0=),$(USE_SSL:0=),implicit)
- OPTIONS_OBJS += src/ssl_sock.o src/ssl_ckch.o src/ssl_ocsp.o src/ssl_crtlist.o src/ssl_sample.o src/cfgparse-ssl.o src/ssl_gencert.o src/ssl_utils.o src/jwt.o
+ OPTIONS_OBJS += src/ssl_sock.o src/ssl_ckch.o src/ssl_ocsp.o src/ssl_crtlist.o src/ssl_sample.o src/cfgparse-ssl.o src/ssl_gencert.o src/ssl_utils.o src/jwt.o src/ssl_clienthello.o
endif
ifneq ($(USE_ENGINE:0=),)
#define SSL_SOCK_NUM_KEYTYPES 3
+extern struct pool_head *ssl_sock_client_sni_pool;
+
#endif /* USE_OPENSSL */
#endif /* _HAPROXY_SSL_SOCK_T_H */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* Note: do NOT include openssl/xxx.h here, do it in openssl-compat.h */
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <import/ebpttree.h>
+#include <import/ebsttree.h>
+
+#include <haproxy/openssl-compat.h>
+#include <haproxy/proto_tcp.h>
+#include <haproxy/quic_conn.h>
+#include <haproxy/quic_openssl_compat.h>
+#include <haproxy/quic_tp.h>
+#include <haproxy/ssl_ckch.h>
+#include <haproxy/ssl_gencert.h>
+#include <haproxy/ssl_sock.h>
+
+static void ssl_sock_switchctx_set(SSL *ssl, SSL_CTX *ctx)
+{
+ SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx), ssl_sock_bind_verifycbk);
+ SSL_set_client_CA_list(ssl, SSL_dup_CA_list(SSL_CTX_get_client_CA_list(ctx)));
+ SSL_set_SSL_CTX(ssl, ctx);
+}
+
+/*
+ * Return the right sni_ctx for a <bind_conf> and a chosen <servername> (must be in lowercase)
+ * RSA <have_rsa_sig> and ECDSA <have_ecdsa_sig> capabilities of the client can also be used.
+ *
+ * This function does a lookup in the bind_conf sni tree so the caller should lock its tree.
+ */
+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;
+ const char *wildp = NULL;
+ int i;
+
+ /* look for the first dot for wildcard search */
+ for (i = 0; servername[i] != '\0'; i++) {
+ if (servername[i] == '.') {
+ wildp = &servername[i];
+ 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 */
+ for (i = 0; i < 2; i++) {
+ if (i == 0) /* lookup in full qualified names */
+ node = ebst_lookup(&s->sni_ctx, trash.area);
+ else if (i == 1 && wildp) /* lookup in wildcards names */
+ node = ebst_lookup(&s->sni_w_ctx, wildp);
+ else
+ break;
+
+ for (n = node; n; n = ebmb_next_dup(n)) {
+
+ /* lookup a not neg filter */
+ if (!container_of(n, struct sni_ctx, name)->neg) {
+ struct sni_ctx *sni, *sni_tmp;
+ int skip = 0;
+
+ if (i == 1 && wildp) { /* wildcard */
+ /* If this is a wildcard, look for an exclusion on the same crt-list line */
+ sni = container_of(n, struct sni_ctx, name);
+ list_for_each_entry(sni_tmp, &sni->ckch_inst->sni_ctx, by_ckch_inst) {
+ if (sni_tmp->neg && (strcmp((const char *)sni_tmp->name.key, trash.area) == 0)) {
+ skip = 1;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+ }
+
+ switch(container_of(n, struct sni_ctx, name)->kinfo.sig) {
+ case TLSEXT_signature_ecdsa:
+ if (!node_ecdsa)
+ node_ecdsa = n;
+ break;
+ case TLSEXT_signature_rsa:
+ if (!node_rsa)
+ node_rsa = n;
+ break;
+ default: /* TLSEXT_signature_anonymous|dsa */
+ if (!node_anonymous)
+ node_anonymous = n;
+ break;
+ }
+ }
+ }
+ }
+ /* Once the certificates are found, select them depending on what is
+ * supported in the client and by key_signature priority order: EDSA >
+ * RSA > DSA */
+ if (have_ecdsa_sig && node_ecdsa)
+ node = node_ecdsa;
+ else if (have_rsa_sig && node_rsa)
+ node = node_rsa;
+ else if (node_anonymous)
+ node = node_anonymous;
+ else if (node_ecdsa)
+ node = node_ecdsa; /* no ecdsa signature case (< TLSv1.2) */
+ else
+ node = node_rsa; /* no rsa signature case (far far away) */
+
+ if (node)
+ return container_of(node, struct sni_ctx, name);
+
+ return NULL;
+}
+
+#ifdef HAVE_SSL_CLIENT_HELLO_CB
+
+int ssl_sock_switchctx_err_cbk(SSL *ssl, int *al, void *priv)
+{
+ struct bind_conf *s = priv;
+ (void)al; /* shut gcc stupid warning */
+
+ if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) || (s->options & BC_O_GENERATE_CERTS))
+ return SSL_TLSEXT_ERR_OK;
+ return SSL_TLSEXT_ERR_NOACK;
+}
+
+#ifdef OPENSSL_IS_BORINGSSL
+int ssl_sock_switchctx_cbk(const struct ssl_early_callback_ctx *ctx)
+{
+ SSL *ssl = ctx->ssl;
+#else
+int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
+{
+#endif
+ struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
+#ifdef USE_QUIC
+ struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
+#endif /* USE_QUIC */
+ struct bind_conf *s = NULL;
+ const uint8_t *extension_data;
+ size_t extension_len;
+ int has_rsa_sig = 0, has_ecdsa_sig = 0;
+ struct sni_ctx *sni_ctx;
+ const char *servername;
+ size_t servername_len = 0;
+ int default_lookup = 0; /* did we lookup for a default yet? */
+ int allow_early = 0;
+ int i;
+
+ if (conn)
+ s = __objt_listener(conn->target)->bind_conf;
+#ifdef USE_QUIC
+ else if (qc)
+ s = qc->li->bind_conf;
+#endif /* USE_QUIC */
+
+ if (!s) {
+ /* must never happen */
+ ABORT_NOW();
+ return 0;
+ }
+
+#ifdef USE_QUIC
+ if (qc) {
+ /* Look for the QUIC transport parameters. */
+#ifdef OPENSSL_IS_BORINGSSL
+ if (!SSL_early_callback_ctx_extension_get(ctx, qc->tps_tls_ext,
+ &extension_data, &extension_len))
+#else
+ if (!SSL_client_hello_get0_ext(ssl, qc->tps_tls_ext,
+ &extension_data, &extension_len))
+#endif
+ {
+ /* This is not redundant. It we only return 0 without setting
+ * <*al>, this has as side effect to generate another TLS alert
+ * which would be set after calling quic_set_tls_alert().
+ */
+ *al = SSL_AD_MISSING_EXTENSION;
+ quic_set_tls_alert(qc, SSL_AD_MISSING_EXTENSION);
+ return 0;
+ }
+
+ if (!quic_transport_params_store(qc, 0, extension_data,
+ extension_data + extension_len))
+ goto abort;
+
+ qc->flags |= QUIC_FL_CONN_TX_TP_RECEIVED;
+ }
+#endif /* USE_QUIC */
+
+ if (s->ssl_conf.early_data)
+ allow_early = 1;
+#ifdef OPENSSL_IS_BORINGSSL
+ if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name,
+ &extension_data, &extension_len)) {
+#else
+ if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &extension_data, &extension_len)) {
+#endif
+ /*
+ * The server_name extension was given too much extensibility when it
+ * was written, so parsing the normal case is a bit complex.
+ */
+ size_t len;
+ if (extension_len <= 2)
+ goto abort;
+ /* Extract the length of the supplied list of names. */
+ len = (*extension_data++) << 8;
+ len |= *extension_data++;
+ if (len + 2 != extension_len)
+ goto abort;
+ /*
+ * The list in practice only has a single element, so we only consider
+ * the first one.
+ */
+ if (len == 0 || *extension_data++ != TLSEXT_NAMETYPE_host_name)
+ goto abort;
+ extension_len = len - 1;
+ /* Now we can finally pull out the byte array with the actual hostname. */
+ if (extension_len <= 2)
+ goto abort;
+ len = (*extension_data++) << 8;
+ len |= *extension_data++;
+ if (len == 0 || len + 2 > extension_len || len > TLSEXT_MAXLEN_host_name
+ || memchr(extension_data, 0, len) != NULL)
+ goto abort;
+ servername = (char *)extension_data;
+ servername_len = len;
+ } else {
+#if (!defined SSL_NO_GENERATE_CERTIFICATES)
+ if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate_from_conn(s, ssl)) {
+ goto allow_early;
+ }
+#endif
+
+ /* 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 */
+#ifdef OPENSSL_IS_BORINGSSL
+ if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_signature_algorithms, &extension_data, &extension_len)) {
+#else
+ if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_signature_algorithms, &extension_data, &extension_len)) {
+#endif
+ uint8_t sign;
+ size_t len;
+ if (extension_len < 2)
+ goto abort;
+ len = (*extension_data++) << 8;
+ len |= *extension_data++;
+ if (len + 2 != extension_len)
+ goto abort;
+ if (len % 2 != 0)
+ goto abort;
+ for (; len > 0; len -= 2) {
+ extension_data++; /* hash */
+ sign = *extension_data++;
+ switch (sign) {
+ case TLSEXT_signature_rsa:
+ has_rsa_sig = 1;
+ break;
+ case TLSEXT_signature_ecdsa:
+ has_ecdsa_sig = 1;
+ break;
+ default:
+ continue;
+ }
+ if (has_ecdsa_sig && has_rsa_sig)
+ break;
+ }
+ } else {
+ /* without TLSEXT_TYPE_signature_algorithms extension (< TLSv1.2) */
+ has_rsa_sig = 1;
+ }
+ if (has_ecdsa_sig) { /* in very rare case: has ecdsa sign but not a ECDSA cipher */
+ const SSL_CIPHER *cipher;
+ STACK_OF(SSL_CIPHER) *ha_ciphers; /* haproxy side ciphers */
+ uint32_t cipher_id;
+ size_t len;
+ const uint8_t *cipher_suites;
+
+ ha_ciphers = SSL_get_ciphers(ssl);
+ has_ecdsa_sig = 0;
+
+#ifdef OPENSSL_IS_BORINGSSL
+ len = ctx->cipher_suites_len;
+ cipher_suites = ctx->cipher_suites;
+#else
+ len = SSL_client_hello_get0_ciphers(ssl, &cipher_suites);
+#endif
+ if (len % 2 != 0)
+ goto abort;
+ for (; len != 0; len -= 2, cipher_suites += 2) {
+#ifdef OPENSSL_IS_BORINGSSL
+ uint16_t cipher_suite = (cipher_suites[0] << 8) | cipher_suites[1];
+ cipher = SSL_get_cipher_by_value(cipher_suite);
+#else
+ cipher = SSL_CIPHER_find(ssl, cipher_suites);
+#endif
+ if (!cipher)
+ continue;
+
+ /* check if this cipher is available in haproxy configuration */
+ if (sk_SSL_CIPHER_find(ha_ciphers, cipher) == -1)
+ continue;
+
+ cipher_id = SSL_CIPHER_get_id(cipher);
+ /* skip the SCSV "fake" signaling ciphersuites because they are NID_auth_any (RFC 7507) */
+ if (cipher_id == SSL3_CK_SCSV || cipher_id == SSL3_CK_FALLBACK_SCSV)
+ continue;
+
+ if (SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa
+ || SSL_CIPHER_get_auth_nid(cipher) == NID_auth_any) {
+ has_ecdsa_sig = 1;
+ break;
+ }
+ }
+ }
+
+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;
+
+ HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
+ 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;
+ ssl_sock_switchctx_set(ssl, sni_ctx->ctx);
+ if (conf) {
+ methodVersions[conf->ssl_methods.min].ssl_set_version(ssl, SET_MIN);
+ methodVersions[conf->ssl_methods.max].ssl_set_version(ssl, SET_MAX);
+ if (conf->early_data)
+ allow_early = 1;
+ }
+ HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
+ goto allow_early;
+ }
+
+ 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(trash.area, s, ssl)) {
+ /* switch ctx done in ssl_sock_generate_certificate */
+ goto allow_early;
+ }
+#endif
+
+ 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
+ * callback will never be called and the SNI will never be stored in the
+ * SSL context. In order for the ssl_fc_sni sample fetch to still work
+ * in such a case, we store the SNI ourselves as an ex_data information
+ * in the SSL context.
+ */
+ {
+ char *client_sni = pool_alloc(ssl_sock_client_sni_pool);
+ if (client_sni) {
+ strncpy(client_sni, servername, TLSEXT_MAXLEN_host_name);
+ client_sni[TLSEXT_MAXLEN_host_name] = '\0';
+ SSL_set_ex_data(ssl, ssl_client_sni_index, client_sni);
+ }
+ }
+
+ /* other cases fallback on abort, if strict-sni is set but no node was found */
+
+ abort:
+ /* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
+ if (conn)
+ conn->err_code = CO_ER_SSL_HANDSHAKE;
+#ifdef OPENSSL_IS_BORINGSSL
+ return ssl_select_cert_error;
+#else
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+#endif
+
+allow_early:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (allow_early)
+ SSL_set_early_data_enabled(ssl, 1);
+#else
+ if (!allow_early)
+ SSL_set_max_early_data(ssl, 0);
+#endif
+ return 1;
+}
+
+#else /* ! HAVE_SSL_CLIENT_HELLO_CB */
+
+/* Sets the SSL ctx of <ssl> to match the advertised server name. Returns a
+ * warning when no match is found, which implies the default (first) cert
+ * will keep being used.
+ */
+int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
+{
+ const char *servername;
+ 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;
+ struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
+#endif /* USE_QUIC */
+ int i;
+ (void)al; /* shut gcc stupid warning */
+
+#ifdef USE_QUIC
+ if (qc) {
+
+ /* Look for the QUIC transport parameters. */
+ SSL_get_peer_quic_transport_params(ssl, &extension_data, &extension_len);
+ if (extension_len == 0) {
+ /* This is not redundant. It we only return 0 without setting
+ * <*al>, this has as side effect to generate another TLS alert
+ * which would be set after calling quic_set_tls_alert().
+ */
+ *al = SSL_AD_MISSING_EXTENSION;
+ quic_set_tls_alert(qc, SSL_AD_MISSING_EXTENSION);
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ if (!quic_transport_params_store(qc, 0, extension_data,
+ extension_data + extension_len))
+ return SSL_TLSEXT_ERR_NOACK;
+
+ qc->flags |= QUIC_FL_CONN_TX_TP_RECEIVED;
+ }
+#endif /* USE_QUIC */
+
+ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (!servername) {
+#if (!defined SSL_NO_GENERATE_CERTIFICATES)
+ if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate_from_conn(s, ssl))
+ return SSL_TLSEXT_ERR_OK;
+#endif
+ if (s->strict_sni)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ /* 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;
+ trash.area[i] = tolower((unsigned char)servername[i]);
+ if (!wildp && (trash.area[i] == '.'))
+ 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;
+ /* lookup in full qualified names */
+ for (n = ebst_lookup(&s->sni_ctx, trash.area); n; n = ebmb_next_dup(n)) {
+ /* lookup a not neg filter */
+ if (!container_of(n, struct sni_ctx, name)->neg) {
+ node = n;
+ break;
+ }
+ }
+ if (!node && wildp) {
+ /* lookup in wildcards names */
+ for (n = ebst_lookup(&s->sni_w_ctx, wildp); n; n = ebmb_next_dup(n)) {
+ /* lookup a not neg filter */
+ if (!container_of(n, struct sni_ctx, name)->neg) {
+ node = n;
+ break;
+ }
+ }
+ }
+ if (!node) {
+#if (!defined SSL_NO_GENERATE_CERTIFICATES)
+ if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate(servername, s, ssl)) {
+ /* switch ctx done in ssl_sock_generate_certificate */
+ HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
+ return SSL_TLSEXT_ERR_OK;
+ }
+#endif
+ HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
+
+ 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 */
+
+#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
+ *
+ * Not activated for now since the PR is not merged.
+ */
+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;
+
+ if (!s) {
+ /* must never happen */
+ ABORT_NOW();
+ return 0;
+ }
+
+ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (!servername) {
+ 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 */
+ {
+ const byte* suites = NULL;
+ word16 suiteSz = 0;
+ const byte* hashSigAlgo = NULL;
+ word16 hashSigAlgoSz = 0;
+ word16 idx = 0;
+
+ wolfSSL_get_client_suites_sigalgs(ssl, &suites, &suiteSz, &hashSigAlgo, &hashSigAlgoSz);
+ if (suites == NULL || suiteSz == 0 || hashSigAlgo == NULL || hashSigAlgoSz == 0)
+ return 0;
+
+ if (SSL_version(ssl) != TLS1_3_VERSION) {
+
+ /* with TLS <= 1.2, we must use the auth which is provided by the cipher, but we don't need to
+ * consider the auth provided by the signature algorithms */
+
+ for (idx = 0; idx < suiteSz; idx += 2) {
+ WOLFSSL_CIPHERSUITE_INFO info;
+ info = wolfSSL_get_ciphersuite_info(suites[idx], suites[idx+1]);
+ if (info.rsaAuth)
+ has_rsa_sig = 1;
+ else if (info.eccAuth)
+ has_ecdsa_sig = 1;
+ }
+ } else {
+ /* with TLS >= 1.3, we must use the auth which is provided by the signature algorithms because
+ * the ciphers does not provide the auth */
+
+ for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
+ int hashAlgo;
+ int sigAlgo;
+
+ wolfSSL_get_sigalg_info(hashSigAlgo[idx+0], hashSigAlgo[idx+1], &hashAlgo, &sigAlgo);
+
+ if (sigAlgo == RSAk || sigAlgo == RSAPSSk)
+ has_rsa_sig = 1;
+ else if (sigAlgo == ECDSAk)
+ has_ecdsa_sig = 1;
+
+ }
+ }
+ }
+
+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]);
+ 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);
+ if (sni_ctx) {
+ /* switch ctx */
+ struct ssl_bind_conf *conf = sni_ctx->conf;
+ ssl_sock_switchctx_set(ssl, sni_ctx->ctx);
+ if (conf) {
+ methodVersions[conf->ssl_methods.min].ssl_set_version(ssl, SET_MIN);
+ methodVersions[conf->ssl_methods.max].ssl_set_version(ssl, SET_MAX);
+ }
+ HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
+ goto allow_early;
+ }
+
+ HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
+ 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
+ * callback will never be called and the SNI will never be stored in the
+ * SSL context. In order for the ssl_fc_sni sample fetch to still work
+ * in such a case, we store the SNI ourselves as an ex_data information
+ * in the SSL context.
+ */
+ {
+ char *client_sni = pool_alloc(ssl_sock_client_sni_pool);
+ if (client_sni) {
+ strncpy(client_sni, servername, TLSEXT_MAXLEN_host_name);
+ client_sni[TLSEXT_MAXLEN_host_name] = '\0';
+ SSL_set_ex_data(ssl, ssl_client_sni_index, client_sni);
+ }
+ }
+
+ /* other cases fallback on abort, if strict-sni is set but no node was found */
+
+ abort:
+ /* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
+ return 0;
+
+allow_early:
+ return 1;
+}
+#endif
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ */
DECLARE_STATIC_POOL(ssl_sock_ctx_pool, "ssl_sock_ctx", sizeof(struct ssl_sock_ctx));
-DECLARE_STATIC_POOL(ssl_sock_client_sni_pool, "ssl_sock_client_sni", TLSEXT_MAXLEN_host_name + 1);
+DECLARE_POOL(ssl_sock_client_sni_pool, "ssl_sock_client_sni", TLSEXT_MAXLEN_host_name + 1);
/* ssl stats module */
enum {
{SSL_OP_NO_TLSv1_3, MC_SSL_O_NO_TLSV13, ctx_set_TLSv13_func, ssl_set_TLSv13_func, "TLSv1.3"}, /* CONF_TLSV13 */
};
-static void ssl_sock_switchctx_set(SSL *ssl, SSL_CTX *ctx)
-{
- SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx), ssl_sock_bind_verifycbk);
- SSL_set_client_CA_list(ssl, SSL_dup_CA_list(SSL_CTX_get_client_CA_list(ctx)));
- SSL_set_SSL_CTX(ssl, ctx);
-}
-
-/*
- * Return the right sni_ctx for a <bind_conf> and a chosen <servername> (must be in lowercase)
- * RSA <have_rsa_sig> and ECDSA <have_ecdsa_sig> capabilities of the client can also be used.
- *
- * This function does a lookup in the bind_conf sni tree so the caller should lock its tree.
- */
-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;
- const char *wildp = NULL;
- int i;
-
- /* look for the first dot for wildcard search */
- for (i = 0; servername[i] != '\0'; i++) {
- if (servername[i] == '.') {
- wildp = &servername[i];
- 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 */
- for (i = 0; i < 2; i++) {
- if (i == 0) /* lookup in full qualified names */
- node = ebst_lookup(&s->sni_ctx, trash.area);
- else if (i == 1 && wildp) /* lookup in wildcards names */
- node = ebst_lookup(&s->sni_w_ctx, wildp);
- else
- break;
-
- for (n = node; n; n = ebmb_next_dup(n)) {
-
- /* lookup a not neg filter */
- if (!container_of(n, struct sni_ctx, name)->neg) {
- struct sni_ctx *sni, *sni_tmp;
- int skip = 0;
-
- if (i == 1 && wildp) { /* wildcard */
- /* If this is a wildcard, look for an exclusion on the same crt-list line */
- sni = container_of(n, struct sni_ctx, name);
- list_for_each_entry(sni_tmp, &sni->ckch_inst->sni_ctx, by_ckch_inst) {
- if (sni_tmp->neg && (strcmp((const char *)sni_tmp->name.key, trash.area) == 0)) {
- skip = 1;
- break;
- }
- }
- if (skip)
- continue;
- }
-
- switch(container_of(n, struct sni_ctx, name)->kinfo.sig) {
- case TLSEXT_signature_ecdsa:
- if (!node_ecdsa)
- node_ecdsa = n;
- break;
- case TLSEXT_signature_rsa:
- if (!node_rsa)
- node_rsa = n;
- break;
- default: /* TLSEXT_signature_anonymous|dsa */
- if (!node_anonymous)
- node_anonymous = n;
- break;
- }
- }
- }
- }
- /* Once the certificates are found, select them depending on what is
- * supported in the client and by key_signature priority order: EDSA >
- * RSA > DSA */
- if (have_ecdsa_sig && node_ecdsa)
- node = node_ecdsa;
- else if (have_rsa_sig && node_rsa)
- node = node_rsa;
- else if (node_anonymous)
- node = node_anonymous;
- else if (node_ecdsa)
- node = node_ecdsa; /* no ecdsa signature case (< TLSv1.2) */
- else
- node = node_rsa; /* no rsa signature case (far far away) */
-
- if (node)
- return container_of(node, struct sni_ctx, name);
-
- return NULL;
-}
-
-#ifdef HAVE_SSL_CLIENT_HELLO_CB
-
-int ssl_sock_switchctx_err_cbk(SSL *ssl, int *al, void *priv)
-{
- struct bind_conf *s = priv;
- (void)al; /* shut gcc stupid warning */
-
- if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) || (s->options & BC_O_GENERATE_CERTS))
- return SSL_TLSEXT_ERR_OK;
- return SSL_TLSEXT_ERR_NOACK;
-}
-
-#ifdef OPENSSL_IS_BORINGSSL
-int ssl_sock_switchctx_cbk(const struct ssl_early_callback_ctx *ctx)
-{
- SSL *ssl = ctx->ssl;
-#else
-int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
-{
-#endif
- struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
-#ifdef USE_QUIC
- struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
-#endif /* USE_QUIC */
- struct bind_conf *s = NULL;
- const uint8_t *extension_data;
- size_t extension_len;
- int has_rsa_sig = 0, has_ecdsa_sig = 0;
- struct sni_ctx *sni_ctx;
- const char *servername;
- size_t servername_len = 0;
- int default_lookup = 0; /* did we lookup for a default yet? */
- int allow_early = 0;
- int i;
-
- if (conn)
- s = __objt_listener(conn->target)->bind_conf;
-#ifdef USE_QUIC
- else if (qc)
- s = qc->li->bind_conf;
-#endif /* USE_QUIC */
-
- if (!s) {
- /* must never happen */
- ABORT_NOW();
- return 0;
- }
-
-#ifdef USE_QUIC
- if (qc) {
- /* Look for the QUIC transport parameters. */
-#ifdef OPENSSL_IS_BORINGSSL
- if (!SSL_early_callback_ctx_extension_get(ctx, qc->tps_tls_ext,
- &extension_data, &extension_len))
-#else
- if (!SSL_client_hello_get0_ext(ssl, qc->tps_tls_ext,
- &extension_data, &extension_len))
-#endif
- {
- /* This is not redundant. It we only return 0 without setting
- * <*al>, this has as side effect to generate another TLS alert
- * which would be set after calling quic_set_tls_alert().
- */
- *al = SSL_AD_MISSING_EXTENSION;
- quic_set_tls_alert(qc, SSL_AD_MISSING_EXTENSION);
- return 0;
- }
-
- if (!quic_transport_params_store(qc, 0, extension_data,
- extension_data + extension_len))
- goto abort;
-
- qc->flags |= QUIC_FL_CONN_TX_TP_RECEIVED;
- }
-#endif /* USE_QUIC */
-
- if (s->ssl_conf.early_data)
- allow_early = 1;
-#ifdef OPENSSL_IS_BORINGSSL
- if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name,
- &extension_data, &extension_len)) {
-#else
- if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &extension_data, &extension_len)) {
-#endif
- /*
- * The server_name extension was given too much extensibility when it
- * was written, so parsing the normal case is a bit complex.
- */
- size_t len;
- if (extension_len <= 2)
- goto abort;
- /* Extract the length of the supplied list of names. */
- len = (*extension_data++) << 8;
- len |= *extension_data++;
- if (len + 2 != extension_len)
- goto abort;
- /*
- * The list in practice only has a single element, so we only consider
- * the first one.
- */
- if (len == 0 || *extension_data++ != TLSEXT_NAMETYPE_host_name)
- goto abort;
- extension_len = len - 1;
- /* Now we can finally pull out the byte array with the actual hostname. */
- if (extension_len <= 2)
- goto abort;
- len = (*extension_data++) << 8;
- len |= *extension_data++;
- if (len == 0 || len + 2 > extension_len || len > TLSEXT_MAXLEN_host_name
- || memchr(extension_data, 0, len) != NULL)
- goto abort;
- servername = (char *)extension_data;
- servername_len = len;
- } else {
-#if (!defined SSL_NO_GENERATE_CERTIFICATES)
- if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate_from_conn(s, ssl)) {
- goto allow_early;
- }
-#endif
-
- /* 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 */
-#ifdef OPENSSL_IS_BORINGSSL
- if (SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_signature_algorithms, &extension_data, &extension_len)) {
-#else
- if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_signature_algorithms, &extension_data, &extension_len)) {
-#endif
- uint8_t sign;
- size_t len;
- if (extension_len < 2)
- goto abort;
- len = (*extension_data++) << 8;
- len |= *extension_data++;
- if (len + 2 != extension_len)
- goto abort;
- if (len % 2 != 0)
- goto abort;
- for (; len > 0; len -= 2) {
- extension_data++; /* hash */
- sign = *extension_data++;
- switch (sign) {
- case TLSEXT_signature_rsa:
- has_rsa_sig = 1;
- break;
- case TLSEXT_signature_ecdsa:
- has_ecdsa_sig = 1;
- break;
- default:
- continue;
- }
- if (has_ecdsa_sig && has_rsa_sig)
- break;
- }
- } else {
- /* without TLSEXT_TYPE_signature_algorithms extension (< TLSv1.2) */
- has_rsa_sig = 1;
- }
- if (has_ecdsa_sig) { /* in very rare case: has ecdsa sign but not a ECDSA cipher */
- const SSL_CIPHER *cipher;
- STACK_OF(SSL_CIPHER) *ha_ciphers; /* haproxy side ciphers */
- uint32_t cipher_id;
- size_t len;
- const uint8_t *cipher_suites;
-
- ha_ciphers = SSL_get_ciphers(ssl);
- has_ecdsa_sig = 0;
-
-#ifdef OPENSSL_IS_BORINGSSL
- len = ctx->cipher_suites_len;
- cipher_suites = ctx->cipher_suites;
-#else
- len = SSL_client_hello_get0_ciphers(ssl, &cipher_suites);
-#endif
- if (len % 2 != 0)
- goto abort;
- for (; len != 0; len -= 2, cipher_suites += 2) {
-#ifdef OPENSSL_IS_BORINGSSL
- uint16_t cipher_suite = (cipher_suites[0] << 8) | cipher_suites[1];
- cipher = SSL_get_cipher_by_value(cipher_suite);
-#else
- cipher = SSL_CIPHER_find(ssl, cipher_suites);
-#endif
- if (!cipher)
- continue;
-
- /* check if this cipher is available in haproxy configuration */
- if (sk_SSL_CIPHER_find(ha_ciphers, cipher) == -1)
- continue;
-
- cipher_id = SSL_CIPHER_get_id(cipher);
- /* skip the SCSV "fake" signaling ciphersuites because they are NID_auth_any (RFC 7507) */
- if (cipher_id == SSL3_CK_SCSV || cipher_id == SSL3_CK_FALLBACK_SCSV)
- continue;
-
- if (SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa
- || SSL_CIPHER_get_auth_nid(cipher) == NID_auth_any) {
- has_ecdsa_sig = 1;
- break;
- }
- }
- }
-
-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;
-
- HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
- 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;
- ssl_sock_switchctx_set(ssl, sni_ctx->ctx);
- if (conf) {
- methodVersions[conf->ssl_methods.min].ssl_set_version(ssl, SET_MIN);
- methodVersions[conf->ssl_methods.max].ssl_set_version(ssl, SET_MAX);
- if (conf->early_data)
- allow_early = 1;
- }
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
- }
-
- 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(trash.area, s, ssl)) {
- /* switch ctx done in ssl_sock_generate_certificate */
- goto allow_early;
- }
-#endif
-
- 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
- * callback will never be called and the SNI will never be stored in the
- * SSL context. In order for the ssl_fc_sni sample fetch to still work
- * in such a case, we store the SNI ourselves as an ex_data information
- * in the SSL context.
- */
- {
- char *client_sni = pool_alloc(ssl_sock_client_sni_pool);
- if (client_sni) {
- strncpy(client_sni, servername, TLSEXT_MAXLEN_host_name);
- client_sni[TLSEXT_MAXLEN_host_name] = '\0';
- SSL_set_ex_data(ssl, ssl_client_sni_index, client_sni);
- }
- }
-
- /* other cases fallback on abort, if strict-sni is set but no node was found */
-
- abort:
- /* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
- if (conn)
- conn->err_code = CO_ER_SSL_HANDSHAKE;
-#ifdef OPENSSL_IS_BORINGSSL
- return ssl_select_cert_error;
-#else
- *al = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
-#endif
-
-allow_early:
-#ifdef OPENSSL_IS_BORINGSSL
- if (allow_early)
- SSL_set_early_data_enabled(ssl, 1);
-#else
- if (!allow_early)
- SSL_set_max_early_data(ssl, 0);
-#endif
- return 1;
-}
-
-#else /* ! HAVE_SSL_CLIENT_HELLO_CB */
-
-/* Sets the SSL ctx of <ssl> to match the advertised server name. Returns a
- * warning when no match is found, which implies the default (first) cert
- * will keep being used.
- */
-int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
-{
- const char *servername;
- 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;
- struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
-#endif /* USE_QUIC */
- int i;
- (void)al; /* shut gcc stupid warning */
-
-#ifdef USE_QUIC
- if (qc) {
-
- /* Look for the QUIC transport parameters. */
- SSL_get_peer_quic_transport_params(ssl, &extension_data, &extension_len);
- if (extension_len == 0) {
- /* This is not redundant. It we only return 0 without setting
- * <*al>, this has as side effect to generate another TLS alert
- * which would be set after calling quic_set_tls_alert().
- */
- *al = SSL_AD_MISSING_EXTENSION;
- quic_set_tls_alert(qc, SSL_AD_MISSING_EXTENSION);
- return SSL_TLSEXT_ERR_NOACK;
- }
-
- if (!quic_transport_params_store(qc, 0, extension_data,
- extension_data + extension_len))
- return SSL_TLSEXT_ERR_NOACK;
-
- qc->flags |= QUIC_FL_CONN_TX_TP_RECEIVED;
- }
-#endif /* USE_QUIC */
-
- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
- if (!servername) {
-#if (!defined SSL_NO_GENERATE_CERTIFICATES)
- if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate_from_conn(s, ssl))
- return SSL_TLSEXT_ERR_OK;
-#endif
- if (s->strict_sni)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- /* 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;
- trash.area[i] = tolower((unsigned char)servername[i]);
- if (!wildp && (trash.area[i] == '.'))
- 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;
- /* lookup in full qualified names */
- for (n = ebst_lookup(&s->sni_ctx, trash.area); n; n = ebmb_next_dup(n)) {
- /* lookup a not neg filter */
- if (!container_of(n, struct sni_ctx, name)->neg) {
- node = n;
- break;
- }
- }
- if (!node && wildp) {
- /* lookup in wildcards names */
- for (n = ebst_lookup(&s->sni_w_ctx, wildp); n; n = ebmb_next_dup(n)) {
- /* lookup a not neg filter */
- if (!container_of(n, struct sni_ctx, name)->neg) {
- node = n;
- break;
- }
- }
- }
- if (!node) {
-#if (!defined SSL_NO_GENERATE_CERTIFICATES)
- if (s->options & BC_O_GENERATE_CERTS && ssl_sock_generate_certificate(servername, s, ssl)) {
- /* switch ctx done in ssl_sock_generate_certificate */
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- return SSL_TLSEXT_ERR_OK;
- }
-#endif
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
-
- 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 */
-
-#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
- *
- * Not activated for now since the PR is not merged.
- */
-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;
-
- if (!s) {
- /* must never happen */
- ABORT_NOW();
- return 0;
- }
-
- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
- if (!servername) {
- 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 */
- {
- const byte* suites = NULL;
- word16 suiteSz = 0;
- const byte* hashSigAlgo = NULL;
- word16 hashSigAlgoSz = 0;
- word16 idx = 0;
-
- wolfSSL_get_client_suites_sigalgs(ssl, &suites, &suiteSz, &hashSigAlgo, &hashSigAlgoSz);
- if (suites == NULL || suiteSz == 0 || hashSigAlgo == NULL || hashSigAlgoSz == 0)
- return 0;
-
- if (SSL_version(ssl) != TLS1_3_VERSION) {
-
- /* with TLS <= 1.2, we must use the auth which is provided by the cipher, but we don't need to
- * consider the auth provided by the signature algorithms */
-
- for (idx = 0; idx < suiteSz; idx += 2) {
- WOLFSSL_CIPHERSUITE_INFO info;
- info = wolfSSL_get_ciphersuite_info(suites[idx], suites[idx+1]);
- if (info.rsaAuth)
- has_rsa_sig = 1;
- else if (info.eccAuth)
- has_ecdsa_sig = 1;
- }
- } else {
- /* with TLS >= 1.3, we must use the auth which is provided by the signature algorithms because
- * the ciphers does not provide the auth */
-
- for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
- int hashAlgo;
- int sigAlgo;
-
- wolfSSL_get_sigalg_info(hashSigAlgo[idx+0], hashSigAlgo[idx+1], &hashAlgo, &sigAlgo);
-
- if (sigAlgo == RSAk || sigAlgo == RSAPSSk)
- has_rsa_sig = 1;
- else if (sigAlgo == ECDSAk)
- has_ecdsa_sig = 1;
-
- }
- }
- }
-
-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]);
- 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);
- if (sni_ctx) {
- /* switch ctx */
- struct ssl_bind_conf *conf = sni_ctx->conf;
- ssl_sock_switchctx_set(ssl, sni_ctx->ctx);
- if (conf) {
- methodVersions[conf->ssl_methods.min].ssl_set_version(ssl, SET_MIN);
- methodVersions[conf->ssl_methods.max].ssl_set_version(ssl, SET_MAX);
- }
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- goto allow_early;
- }
-
- HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
- 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
- * callback will never be called and the SNI will never be stored in the
- * SSL context. In order for the ssl_fc_sni sample fetch to still work
- * in such a case, we store the SNI ourselves as an ex_data information
- * in the SSL context.
- */
- {
- char *client_sni = pool_alloc(ssl_sock_client_sni_pool);
- if (client_sni) {
- strncpy(client_sni, servername, TLSEXT_MAXLEN_host_name);
- client_sni[TLSEXT_MAXLEN_host_name] = '\0';
- SSL_set_ex_data(ssl, ssl_client_sni_index, client_sni);
- }
- }
-
- /* other cases fallback on abort, if strict-sni is set but no node was found */
-
- abort:
- /* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
- return 0;
-
-allow_early:
- return 1;
-}
-#endif
-
#ifndef OPENSSL_NO_DH
static inline HASSL_DH *ssl_new_dh_fromdata(BIGNUM *p, BIGNUM *g)