[PATCH 2 of 2] SSL: support for iPAddress subjectAltName in certificates
Maxim Dounin
mdounin at mdounin.ru
Mon Aug 18 16:39:26 UTC 2025
Hello!
On Thu, Aug 14, 2025 at 06:52:02PM +0300, Maxim Dounin wrote:
> # HG changeset patch
> # User Maxim Dounin <mdounin at mdounin.ru>
> # Date 1755133582 -10800
> # Thu Aug 14 04:06:22 2025 +0300
> # Node ID 870dfc16d381d90644b08159dd84d1ee391cf630
> # Parent 51d23ff6f109765f4c382d449d7ea0cea13ea220
> SSL: support for iPAddress subjectAltName in certificates.
>
> Known public services with iPAddress subject altnames include 1.1.1.1
> and 8.8.8.8. IP address certificates from Let's Encrypt are expected
> to be available soon:
>
> https://letsencrypt.org/2025/07/01/issuing-our-first-ip-address-certificate
>
> diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
> --- a/src/event/ngx_event_openssl.c
> +++ b/src/event/ngx_event_openssl.c
> @@ -4901,19 +4901,63 @@ ngx_ssl_cleanup_ctx(void *data)
> ngx_int_t
> ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name)
> {
> - X509 *cert;
> + X509 *cert;
> + u_char *addr, addr6[16];
> + size_t alen;
> + in_addr_t addr4;
>
> cert = SSL_get_peer_certificate(c->ssl->connection);
> if (cert == NULL) {
> return NGX_ERROR;
> }
>
> + if (name->len == 0) {
> + goto failed;
> + }
> +
> + addr4 = ngx_inet_addr(name->data, name->len);
> +
> + if (addr4 != INADDR_NONE) {
> + addr = (u_char *) &addr4;
> + alen = 4;
> +
> +#if (NGX_HAVE_INET6)
> + } else if (name->data[0] == '[') {
> +
> + if (name->data[name->len - 1] != ']') {
> + goto failed;
> + }
> +
> + if (ngx_inet6_addr(name->data + 1, name->len - 2, &addr6[0])
> + != NGX_OK)
> + {
> + goto failed;
> + }
> +
> + addr = &addr6[0];
> + alen = 16;
> +
> +#endif
> + } else {
> + addr = NULL;
> + alen = 0;
> + }
> +
> +
> #ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
>
> /* X509_check_host() is only available in OpenSSL 1.0.2+ */
>
> - if (name->len == 0) {
> - goto failed;
> + if (addr) {
> + if (X509_check_ip(cert, addr, alen, 0) != 1) {
> + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "X509_check_ip(): no match");
> + goto failed;
> + }
> +
> + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "X509_check_ip(): match");
> + goto found;
> }
>
> if (X509_check_host(cert, (char *) name->data, name->len, 0, NULL) != 1) {
> @@ -4924,12 +4968,13 @@ ngx_ssl_check_host(ngx_connection_t *c,
>
> ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> "X509_check_host(): match");
> -
> goto found;
>
> #else
> {
> int n, i;
> + size_t dlen;
> + u_char *data;
> X509_NAME *sname;
> ASN1_STRING *str;
> X509_NAME_ENTRY *entry;
> @@ -4949,22 +4994,63 @@ ngx_ssl_check_host(ngx_connection_t *c,
> for (i = 0; i < n; i++) {
> altname = sk_GENERAL_NAME_value(altnames, i);
>
> - if (altname->type != GEN_DNS) {
> - continue;
> - }
> -
> - str = altname->d.dNSName;
> -
> - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
> - "SSL subjectAltName: \"%*s\"",
> - (size_t) ASN1_STRING_length(str),
> - ASN1_STRING_data(str));
> -
> - if (ngx_ssl_check_name(name, str) == NGX_OK) {
> - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> - "SSL subjectAltName: match");
> - GENERAL_NAMES_free(altnames);
> - goto found;
> + if (altname->type == GEN_IPADD) {
> +
> + str = altname->d.iPAddress;
> + data = ASN1_STRING_data(str);
> + dlen = ASN1_STRING_length(str);
> +
> +#if (NGX_DEBUG)
> + {
> + size_t al;
> + u_char at[NGX_INET6_ADDRSTRLEN];
> +
> + if (dlen == 4) {
> + al = ngx_inet_ntop(AF_INET, data, at,
> + NGX_INET6_ADDRSTRLEN);
> +
> +#if (NGX_HAVE_INET6)
> + } else if (dlen == 16) {
> + al = ngx_inet_ntop(AF_INET6, data, at,
> + NGX_INET6_ADDRSTRLEN);
> +
> +#endif
> + } else {
> + al = ngx_cpymem(at, "<invalid>", sizeof("<invalid>") - 1)
> + - at;
> + }
> +
> + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "SSL subjectAltName: %*s",
> + al, at);
> + }
> +#endif
> +
> + if (addr
> + && alen == dlen
> + && ngx_memcmp(addr, data, dlen) == 0)
> + {
> + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "SSL subjectAltName: match");
> + GENERAL_NAMES_free(altnames);
> + goto found;
> + }
> +
> + } else if (altname->type == GEN_DNS) {
> +
> + str = altname->d.dNSName;
> +
> + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "SSL subjectAltName: \"%*s\"",
> + (size_t) ASN1_STRING_length(str),
> + ASN1_STRING_data(str));
> +
> + if (ngx_ssl_check_name(name, str) == NGX_OK) {
> + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
> + "SSL subjectAltName: match");
> + GENERAL_NAMES_free(altnames);
> + goto found;
> + }
> }
> }
>
>
Amended with the following patch, to provide more natural order of
altname->type handling:
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -4994,7 +4994,23 @@ ngx_ssl_check_host(ngx_connection_t *c,
for (i = 0; i < n; i++) {
altname = sk_GENERAL_NAME_value(altnames, i);
- if (altname->type == GEN_IPADD) {
+ if (altname->type == GEN_DNS) {
+
+ str = altname->d.dNSName;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL subjectAltName: \"%*s\"",
+ (size_t) ASN1_STRING_length(str),
+ ASN1_STRING_data(str));
+
+ if (ngx_ssl_check_name(name, str) == NGX_OK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL subjectAltName: match");
+ GENERAL_NAMES_free(altnames);
+ goto found;
+ }
+
+ } else if (altname->type == GEN_IPADD) {
str = altname->d.iPAddress;
data = ASN1_STRING_data(str);
@@ -5035,22 +5051,6 @@ ngx_ssl_check_host(ngx_connection_t *c,
GENERAL_NAMES_free(altnames);
goto found;
}
-
- } else if (altname->type == GEN_DNS) {
-
- str = altname->d.dNSName;
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "SSL subjectAltName: \"%*s\"",
- (size_t) ASN1_STRING_length(str),
- ASN1_STRING_data(str));
-
- if (ngx_ssl_check_name(name, str) == NGX_OK) {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "SSL subjectAltName: match");
- GENERAL_NAMES_free(altnames);
- goto found;
- }
}
}
--
Maxim Dounin
http://mdounin.ru/
More information about the nginx-devel
mailing list