Repository navigation
Linux CheckX509IpAddress processes IP literals in CN on Linux when SAN is also present #131734
Description
Activity
- addedos-linuxLinux OS (any supported distro)Linux OS (any supported distro)
on Aug 3, 2026 - addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Aug 3, 2026 dotnet-policy-service commented
on Aug 3, 2026 ContributorMore actionsTagging subscribers to this area: @bartonjs, @vcsjones, @dotnet/area-system-security
See info in area-owners.md if you want to be subscribed.- changed the title
[-]X509Chain process IP literals in CN on Linux when SAN is also present[/-][+]Linux CheckX509IpAddress processes IP literals in CN on Linux when SAN is also present[/+]on Aug 14, 2026 - removeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Aug 14, 2026 Reproduction: IP address matching with CN and SAN on Windows and Linux
I reproduced the difference described in dotnet/runtime#131734 using actual
SslStreamTLS connections on both platforms.The difference occurs in the tested SANs containing a DNS name: Linux accepts the target IP from CN, while Windows reports a name mismatch. However, an IP-only SAN containing a different IP did not prevent CN fallback on either platform. The latter also reproduced for IPv6.
Environment
Platform Environment Windows OS version 10.0.26300; .NET10.0.12; SDK10.0.401Linux Ubuntu 24.04.5 LTSin Docker; .NET10.0.12; OpenSSL3.0.13Linux image mcr.microsoft.com/dotnet/sdk:10.0Image digest sha256:e70cdb7f80b0348f5cb85f19a8f670fca061f033d57eed12fa003d58b0e06317These tests used installed .NET binaries, not a locally built runtime.
Reproduction method
The same TLS harness ran 11 certificate/target combinations on each platform:
- Generate a self-signed RSA-2048 certificate using
CertificateRequest, SHA-256, and PKCS#1 signature padding. - Set CN to the IP literal listed below. Add SAN IP/DNS entries using
SubjectAlternativeNameBuilder, or omit SAN for the "None" cases. - Export and re-import the certificate as in-memory PKCS#12 using
X509CertificateLoader.LoadPkcs12withDefaultKeySet. This accommodates Windows Schannel, which rejected the originally generated ephemeral private keys. - Establish a client/server TCP connection on loopback and wrap both ends in
SslStream. - Authenticate using TLS 1.2, with the client's
TargetHostset to the target IP literal and revocation checking disabled. - Record the actual
SslPolicyErrorsinRemoteCertificateValidationCallback, then returntruesolely to let the diagnostic connection continue. - Exchange an encrypted client-to-server payload, verify its bytes, and check both streams'
IsAuthenticatedandIsEncryptedproperties.
The target addresses are documentation-range IPs used as identity-check inputs; the TCP connections go to loopback. No certificates were installed in a trust store.
Important: the callback deliberately allows the connections despite certificate errors. Successful handshakes therefore do not demonstrate default certificate acceptance. The results below describe the name-validation errors reported by .NET before that override.
TLS name-validation results
"Match" means
RemoteCertificateNameMismatchwas absent; "Mismatch" means it was present.CN SAN contents Target IP Windows TLS Linux TLS 192.0.2.1None 192.0.2.1Match Match 192.0.2.1IP: 192.0.2.2192.0.2.1Match Match 192.0.2.1IP: 192.0.2.2192.0.2.2Match Match 192.0.2.1IP: 192.0.2.2192.0.2.3Mismatch Mismatch 192.0.2.1DNS: example.test192.0.2.1Mismatch Match 192.0.2.1DNS: example.test; IP:192.0.2.2192.0.2.1Mismatch Match 192.0.2.1DNS: example.test; IP:192.0.2.2192.0.2.2Match Match 192.0.2.1None 192.0.2.2Mismatch Mismatch 2001:db8::1None 2001:db8::1Match Match 2001:db8::1IP: 2001:db8::22001:db8::1Match Match 2001:db8::1IP: 2001:db8::22001:db8::2Match Match All 22 TLS handshakes and encrypted payload exchanges completed under the diagnostic callback.
Every case reported
RemoteCertificateChainErrors, as expected for these untrusted self-signed certificates. Windows additionally reportedRemoteCertificateNameMismatchin four cases; Linux reported it in two cases.Representative recorded output for CN
192.0.2.1, SAN DNSexample.test, target192.0.2.1:Windows: TLS-name-match=False TLS-errors=RemoteCertificateNameMismatch, RemoteCertificateChainErrors protocol=Tls12; encrypted-data=True Linux: TLS-name-match=True TLS-errors=RemoteCertificateChainErrors protocol=Tls12; encrypted-data=TrueIndependent native checks
The TLS results agreed with native name-validation probes for all 11 combinations on each platform:
- Windows:
CertVerifyCertificateChainPolicywithCERT_CHAIN_POLICY_SSL,AUTHTYPE_SERVER, the target IP aspwszServerName, and policy flags0xFBF(ignore other policy errors, retain name checking). Matches returneddwError = 0; mismatches returned0x800B010F(CERT_E_CN_NO_MATCH). - Linux: the installed .NET native library's
CryptoNative_CheckX509IpAddress, with the target IP bytes and literal string. Matches returned1; mismatches returned0.
The inspected Linux source checks SAN IP entries first, then checks CN whenever
successremains false, without restricting fallback based on SAN presence:CryptoNative_CheckX509IpAddress, inspected revision.
The Windows native probe follows the parameters in:
CertificateValidation.Windows.cs, inspected revision.
These source links describe the inspected checkout; the executed binaries were .NET
10.0.12.Standards interpretation
Windows compatibility and strict standards-based IP identity matching are different targets here.
RFC 5280 section 4.2.1.6 defines SAN identity representation and IP encoding, but does not specify a client's blanket SAN-over-CN precedence algorithm. Its requirement that SAN identities be verified by the CA concerns issuance, not client target-name matching.
For HTTPS, RFC 2818 section 3.1 explicitly states:
In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI.
The current TLS service-identity specification, RFC 9525, which obsoletes RFC 6125, states in section 2:
The Common Name RDN MUST NOT be used to identify a service because it is not strongly typed (it is essentially free-form text) and therefore suffers from ambiguities in interpretation.
And section 6.4 specifies:
Matching of an IP-ID is based on an octet-for-octet comparison of the bytes of the reference identity with the bytes contained in the iPAddress subjectAltName.
For the direct IP targets tested here, this means a matching IP SAN is required: CN-only certificates and certificates with a matching CN but only a conflicting SAN IP should fail the identity check.
Consequently, neither tested platform fully follows that strict IP-identity rule. Windows rejects the two DNS-containing SAN cases that Linux accepts, but both still accept CN-only IP identities and CN fallback with conflicting IP-only SANs.
These observations are limited to the versions and combinations above. Default rejection behavior was not tested because the diagnostic callback deliberately accepted the connections.
Additional Windows reproduction: numeric DNS SANs and wildcards
The original 11-case reproduction above did not include wildcard tests. A later Windows run expanded the TLS harness to 22 cases. The following results come from that additional reproduction, not from the original suite.
This run used Windows OS
10.0.26300and installed .NET10.0.12. No additional installed-runtime Linux results are included in this section.CN SAN contents Target IP Windows TLS 192.0.2.1DNS: 192.0.2.1192.0.2.1Match other.testDNS: 192.0.2.1192.0.2.1Match 192.0.2.1DNS: *.0.2.1192.0.2.1Mismatch *.0.2.1None 192.0.2.1Mismatch 2001:db8::1DNS: 2001:db8::12001:db8::1Match other.testDNS: 2001:db8::12001:db8::1Match Recorded Windows wildcard results:
CN=192.0.2.1; SAN-DNS=*.0.2.1; target=192.0.2.1 TLS-name-match=False TLS-errors=RemoteCertificateNameMismatch, RemoteCertificateChainErrors protocol=Tls12; encrypted-data=True; verified=True CN=*.0.2.1; SAN-DNS=; target=192.0.2.1 TLS-name-match=False TLS-errors=RemoteCertificateNameMismatch, RemoteCertificateChainErrors protocol=Tls12; encrypted-data=True; verified=TrueThe expanded Windows run completed 22 TLS checks and 22 encrypted payload exchanges with zero harness assertion failures. It did not execute independent native probes.
These two IPv4 wildcard cases demonstrate rejection of the particular wildcard identities tested; they do not establish the behavior of every possible wildcard pattern or Windows' internal implementation. As in the original harness, the callback deliberately accepted certificate errors so the encrypted exchange could complete.
Note
This report and its test harnesses were generated with GitHub Copilot. The reported results were obtained by executing native probes and actual TLS tests on Windows and in a Linux Docker container.
- Generate a self-signed RSA-2048 certificate using
Traditionally, one can put IP address to CN and have that validated agains actual IP address.
However, when
SubjectAlternativeNameis present it should take precedence:https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
The behavior is Linux specific and it works as expected when same validation runs on Windows.