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.
+ */
+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)
+{
+ 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;
+ }
+ }
+
+ /* 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 = arg;
int has_rsa_sig = 0, has_ecdsa_sig = 0;
-
- char *wildp = NULL;
const char *servername;
- struct ebmb_node *node, *n, *node_ecdsa = NULL, *node_rsa = NULL, *node_anonymous = NULL;
+ struct sni_ctx *sni_ctx;
int i;
if (!s) {
}
}
- 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];
- }
+ /* 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);
-
- /* 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, servername);
- 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, servername) == 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 (has_ecdsa_sig && node_ecdsa)
- node = node_ecdsa;
- else if (has_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) {
+ 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 = container_of(node, struct sni_ctx, name)->conf;
- ssl_sock_switchctx_set(ssl, container_of(node, struct sni_ctx, name)->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);
}
#endif
-
#ifndef OPENSSL_NO_DH
static inline HASSL_DH *ssl_new_dh_fromdata(BIGNUM *p, BIGNUM *g)