Skip to content

Security: do not derive TLS server identity from reverse DNS - #361

Merged
vincent-richard merged 2 commits into
masterfrom
getpeername-no-reverse-dns
Oct 12, 2026
Merged

vincent-richard merged 2 commits into
masterfrom
getpeername-no-reverse-dns

Conversation

@vincent-richard

Copy link
Copy Markdown
Member

When connecting to a numeric address (e.g. 203.0.113.5), getPeerName() performed a reverse DNS (PTR) lookup and returned the resulting host name. This name is used both for SNI and as the reference identity when verifying the server certificate.

PTR responses are not authenticated. An on-path attacker could intercept the connection, answer the PTR query with a domain they control, and present a valid certificate for that domain: vmime would accept it, and the user's credentials would be sent to the attacker. RFC 6125/9525 forbid deriving the reference identity from an unsecured DNS lookup.

Affected configurations (only when connecting to a numeric address; host names are not affected):

  • Windows: always.
  • POSIX: since VMIME_HAVE_GETNAMEINFO template #353, which enabled the getnameinfo() code path. Before that, the gethostbyaddr() fallback never succeeded, so the numeric address was used.

Thanks to @jengelh: #353 made this code path reachable on POSIX, which is how the issue was found (#357 fixed the IPv6 buffer over-read it exposed).

Changes:

  • getPeerName() now returns the name as specified when connecting, without any reverse DNS lookup (POSIX and Windows). VMIME_HAVE_GETNAMEINFO is no longer needed and has been removed.
  • OpenSSL: verifyHostName() now matches IP addresses against IP subject alternative names, using X509_check_ip_asc(). GnuTLS already does this in gnutls_x509_crt_check_hostname().
  • SNI is no longer sent when the server is an IP address (RFC 6066). Both GnuTLS and OpenSSL would otherwise put the IP address in the ClientHello. Added a TLSSocket::isIPAddress() helper.

Behavior change: connecting to a numeric address with TLS now requires the server certificate to contain that IP address in its subject alternative names. If the certificate was issued for a host name, connect using the host name (or install a custom certificateVerifier).

When connecting to a numeric address, getPeerName() returned the host name obtained by a reverse DNS lookup. This name is used for SNI and to verify the server certificate, so an attacker able to spoof the PTR response could make vmime accept a valid certificate for a domain they control.

getPeerName() now returns the name as specified when connecting. Certificates are verified against IP addresses in subject alternative names (OpenSSL backend; GnuTLS already does it), and SNI is not sent for IP addresses (RFC 6066).
@vincent-richard
vincent-richard merged commit 63ddb3b into master Oct 12, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant