From: Emmanuel Hocdet Date: Fri, 13 May 2016 09:14:06 +0000 (+0200) Subject: MEDIUM: ssl: support SNI filters with multicerts X-Git-Tag: v1.7-dev4~67 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d294aea605f825801ab254abf9422d0b2cf237b7;p=thirdparty%2Fhaproxy.git MEDIUM: ssl: support SNI filters with multicerts SNI filters used to be ignored with multicerts (eg: those providing ECDSA and RSA at the same time). This patch makes them work like other certs. Note: most of the changes in this patch are due to an extra level of indent, read it with "git show -b". --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 00da5dfbcc..8b35a02338 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -9932,8 +9932,8 @@ crt-list the 'strict-sni' option may be used. Multi-cert bundling (see "crt") is supported with crt-list, as long as only - the base name is given in the crt-list. Due to the nature of bundling, all SNI - filters given to a multi-cert bundle entry are ignored. + the base name is given in the crt-list. SNI filter will do the same work on + all bundled certificates. defer-accept Is an optional keyword which is supported only on certain Linux kernels. It diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 378fddc1c4..957bc9790a 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -1934,7 +1934,7 @@ static void ssl_sock_populate_sni_keytypes_hplr(const char *str, struct eb_root * 0 on success * 1 on failure */ -static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, char **err) +static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, int fcount, char **err) { char fp[MAXPATHLEN+1] = {0}; int n = 0; @@ -1978,37 +1978,42 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con if (!ssl_sock_is_ckch_valid(&certs_and_keys[n])) continue; - /* A lot of the following code is OpenSSL boilerplate for processing CN's and SAN's, - * so the line that contains logic is marked via comments - */ - xname = X509_get_subject_name(certs_and_keys[n].cert); - i = -1; - while ((i = X509_NAME_get_index_by_NID(xname, NID_commonName, i)) != -1) { - X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i); + if (fcount) { + for (i = 0; i < fcount, i++) + ssl_sock_populate_sni_keytypes_hplr(sni_filter[i], &sni_keytypes_map, n); + } else { + /* A lot of the following code is OpenSSL boilerplate for processing CN's and SAN's, + * so the line that contains logic is marked via comments + */ + xname = X509_get_subject_name(certs_and_keys[n].cert); + i = -1; + while ((i = X509_NAME_get_index_by_NID(xname, NID_commonName, i)) != -1) { + X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i); - if (ASN1_STRING_to_UTF8((unsigned char **)&str, entry->value) >= 0) { - /* Important line is here */ - ssl_sock_populate_sni_keytypes_hplr(str, &sni_keytypes_map, n); + if (ASN1_STRING_to_UTF8((unsigned char **)&str, entry->value) >= 0) { + /* Important line is here */ + ssl_sock_populate_sni_keytypes_hplr(str, &sni_keytypes_map, n); - OPENSSL_free(str); - str = NULL; + OPENSSL_free(str); + str = NULL; + } } - } - /* Do the above logic for each SAN */ + /* Do the above logic for each SAN */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - names = X509_get_ext_d2i(certs_and_keys[n].cert, NID_subject_alt_name, NULL, NULL); - if (names) { - for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { - GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i); - - if (name->type == GEN_DNS) { - if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) { - /* Important line is here */ - ssl_sock_populate_sni_keytypes_hplr(str, &sni_keytypes_map, n); - - OPENSSL_free(str); - str = NULL; + names = X509_get_ext_d2i(certs_and_keys[n].cert, NID_subject_alt_name, NULL, NULL); + if (names) { + for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { + GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i); + + if (name->type == GEN_DNS) { + if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) { + /* Important line is here */ + ssl_sock_populate_sni_keytypes_hplr(str, &sni_keytypes_map, n); + + OPENSSL_free(str); + str = NULL; + } } } } @@ -2101,7 +2106,7 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con } /* Update SNI Tree */ - ssl_sock_add_cert_sni(cur_ctx, bind_conf, str, key_combos[i-1].order++); + key_combos[i-1].order = ssl_sock_add_cert_sni(cur_ctx, bind_conf, str, key_combos[i-1].order); node = ebmb_next(node); } @@ -2135,7 +2140,7 @@ end: } #else /* This is a dummy, that just logs an error and returns error */ -static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, char **err) +static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, int fcount, char **err) { memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n", err && *err ? *err : "", path, strerror(errno)); @@ -2400,7 +2405,7 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, struct proxy *cu } snprintf(fp, sizeof(fp), "%s/%s", path, dp); - ssl_sock_load_multi_cert(fp, bind_conf, curproxy, NULL, err); + ssl_sock_load_multi_cert(fp, bind_conf, curproxy, NULL, 0, err); /* Successfully processed the bundle */ goto ignore_entry; @@ -2418,7 +2423,7 @@ ignore_entry: return cfgerr; } - cfgerr = ssl_sock_load_multi_cert(path, bind_conf, curproxy, NULL, err); + cfgerr = ssl_sock_load_multi_cert(path, bind_conf, curproxy, NULL, 0, err); return cfgerr; } @@ -2505,7 +2510,7 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, struct if (stat(args[0], &buf) == 0) { cfgerr = ssl_sock_load_cert_file(args[0], bind_conf, curproxy, &args[1], arg-1, err); } else { - cfgerr = ssl_sock_load_multi_cert(args[0], bind_conf, curproxy, NULL, err); + cfgerr = ssl_sock_load_multi_cert(args[0], bind_conf, curproxy, &args[1], arg-1, err); } if (cfgerr) {