mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-19 12:10:46 +00:00
MINOR: ssl: move certificate selection in a dedicate function
The certificate selection used in the WolfSSL cert_cb and in the OpenSSL clienthello callback is the same, the function was duplicate to achieve the same. This patch move the selection code to a common function called ssl_sock_chose_sni_ctx(). The servername string is still lowered in the callback, however the search for the first dot in the string (wildp) is done in ssl_sock_chose_sni_ctx() The function uses the same certificate selection algorithm as before, it needs to know if you need rsa or ecdsa, the bind_conf to achieve the lookup, and the servername string. This patch moves the code for WolSSL only.
This commit is contained in:
parent
b900a3533c
commit
9f2e07bf7b
173
src/ssl_sock.c
173
src/ssl_sock.c
@ -2319,6 +2319,94 @@ static void ssl_sock_switchctx_set(SSL *ssl, SSL_CTX *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.
|
||||
*/
|
||||
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)
|
||||
@ -2783,10 +2871,8 @@ 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;
|
||||
|
||||
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) {
|
||||
@ -2848,84 +2934,18 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -2969,7 +2989,6 @@ allow_early:
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
|
||||
static inline HASSL_DH *ssl_new_dh_fromdata(BIGNUM *p, BIGNUM *g)
|
||||
|
Loading…
Reference in New Issue
Block a user