mirror of
https://github.com/haproxy/haproxy.git
synced 2026-05-27 20:02:17 -04:00
BUG/MINOR: ssl-gencert: validate SNI characters to prevent SAN certificate injection
ssl_sock_add_san_ext() builds the Subject Alternative Name extension by concatenating "DNS:" + servername and passing the result to X509V3_EXT_nconf_nid(). OpenSSL's nconf parser splits the value string on commas into multiple type:value SAN entries. The SNI comes from unauthenticated TLS ClientHello data -- an attacker can embed commas and colons (e.g., "host,dns:internal.corp,ip:10.0.0.1") to inject arbitrary GENERAL_NAME entries into certificates signed by HAProxy's configured CA. This is a CA issuance-policy violation: the operator expects one certificate per SNI hostname, but an attacker can obtain certificates containing additional hostnames/IPs/emails without access to the CA private key. Fix by adding ssl_sock_sni_is_valid() that validates the SNI contains only DNS-label-legal characters (alphanumeric, hyphens, dots). The check is performed at the start of ssl_sock_do_create_cert() before any allocation. Commas, colons, spaces, and other special characters cause certificate generation to fail, preventing SAN injection while allowing all valid hostname values. Must be backported in every maintained branches.
This commit is contained in:
parent
31cd3d13aa
commit
85a833feba
1 changed files with 31 additions and 0 deletions
|
|
@ -44,6 +44,29 @@ __decl_rwlock(ssl_ctx_lru_rwlock);
|
|||
|
||||
#ifndef SSL_NO_GENERATE_CERTIFICATES
|
||||
|
||||
/* Validate that <servername> contains only DNS-label-legal characters
|
||||
* (letters, digits, hyphens, dots). Rejects commas, colons, and other
|
||||
* characters that OpenSSL's nconf parser would interpret as SAN entry
|
||||
* separators or type prefixes, preventing certificate injection. */
|
||||
static int ssl_sock_sni_is_valid(const char *s)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!s || !*s)
|
||||
return 0;
|
||||
for (i = 0; s[i]; i++) {
|
||||
unsigned char c = (unsigned char)s[i];
|
||||
if (!(
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '.'
|
||||
))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
|
@ -100,6 +123,14 @@ static SSL_CTX *ssl_sock_do_create_cert(const char *servername, struct bind_conf
|
|||
int key_type;
|
||||
struct sni_ctx *sni_ctx;
|
||||
|
||||
/* Reject SNI values containing characters that OpenSSL's nconf
|
||||
* parser would interpret as SAN entry separators (commas), type
|
||||
* prefixes (colons), or other special constructs. This prevents
|
||||
* attackers from injecting arbitrary GENERAL_NAME entries into
|
||||
* certificates signed by HAProxy's configured CA. */
|
||||
if (!ssl_sock_sni_is_valid(servername))
|
||||
goto mkcert_error;
|
||||
|
||||
sni_ctx = ssl_sock_choose_sni_ctx(bind_conf, NULL, "", 1, 1);
|
||||
if (!sni_ctx)
|
||||
goto mkcert_error;
|
||||
|
|
|
|||
Loading…
Reference in a new issue