details: http://freenginx.org/hg/nginx/rev/5e23335edf67 branches: changeset: 9411:5e23335edf67 user: Maxim Dounin <[email protected]> date: Thu Aug 21 04:41:27 2025 +0300 description: 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 diffstat: src/event/ngx_event_openssl.c | 126 +++++++++++++++++++++++++++++++++++------ 1 files changed, 106 insertions(+), 20 deletions(-) diffs (165 lines): 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_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); + 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; + } } }
