{"record":{"id":"f0a5ba988155476f","repo":"grpc/grpc-go","slug":"xds-received-dns-sans-v-do-not-match-the-sni","errorCode":null,"errorMessage":"xds: received DNS SANs: %v do not match the SNI: %s","messagePattern":"xds: received DNS SANs: (.+?) do not match the SNI: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/xds/handshake_info.go","lineNumber":311,"sourceCode":"\t\t} else {\n\t\t\topts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}\n\t\t}\n\t\tif _, err := certs[0].Verify(opts); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// If XDSSNIEnabled and AutoSNISANValidation are both true and the SNI is\n\t\t// non-empty, validate only DNS SANs against the SNI. Otherwise, fallback to\n\t\t// validating all received SANs against the control plane provided SAN\n\t\t// matchers.\n\t\tif envconfig.XDSSNIEnabled && hi.validateSANUsingSNI && sni != \"\" {\n\t\t\t// Verify SAN of leaf certificate with SNI using exact DNS matcher.\n\t\t\tfor _, san := range certs[0].DNSNames {\n\t\t\t\tif dnsMatch(sni, san) {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"xds: received DNS SANs: %v do not match the SNI: %s\", certs[0].DNSNames, sni)\n\t\t}\n\t\t// The SANs sent by the xDS control plane are encoded as SPIFFE IDs. We need to\n\t\t// only look at the SANs on the leaf cert.\n\t\tif cert := certs[0]; !hi.MatchingSANExists(cert) {\n\t\t\t// TODO: Print the complete certificate once the x509 package\n\t\t\t// supports a String() method on the Certificate type.\n\t\t\treturn fmt.Errorf(\"xds: received SANs {DNSNames: %v, EmailAddresses: %v, IPAddresses: %v, URIs: %v} do not match any of the accepted SANs\", cert.DNSNames, cert.EmailAddresses, cert.IPAddresses, cert.URIs)\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// serverSideTLSConfigInternal constructs a tls.Config to be used in a\n// server-side handshake based on the contents of the HandshakeInfo.\nfunc (hi *HandshakeInfo) serverSideTLSConfigInternal(ctx context.Context) (*tls.Config, error) {\n\tcfg := &tls.Config{\n\t\tClientAuth: tls.NoClientCert,\n\t\tNextProtos: []string{\"h2\"},","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/credentials/xds/handshake_info.go#L293-L329","documentation":"Returned by the peer verifier when SNI-based SAN validation is enabled (envconfig.XDSSNIEnabled && hi.validateSANUsingSNI && sni != \"\") and none of the leaf cert's DNS SANs match the SNI value via dnsMatch. dnsMatch supports exact and single-label wildcard matching; if every DNS SAN fails, the connection is rejected. This protects against a server presenting a cert valid for a different hostname than the one requested.","triggerScenarios":"buildVerifyFunc at handshake_info.go:304-311: the client connected with SNI=foo.example.com but the server cert's DNS SANs are only [bar.example.com] or [*.other.com]. AutoHostSNI substituted the endpoint hostname as SNI, and that hostname is not covered by the cert.","commonSituations":"AutoHostSNI enabled with a load balancer whose cert SANs don't include the per-endpoint hostname; cert renewed with a narrower SAN set; connecting by IP or short name that's not in the cert; SNI propagation broken by a proxy.","solutions":["Issue a server certificate whose DNS SANs include the hostname(s) clients connect by (or a covering wildcard).","Disable useAutoHostSNI so the control-plane SNI value is used and matches the cert.","Connect via a hostname that is actually present in the server cert's DNS SANs.","Re-check the xDS Cluster configuration for the intended SNI vs. the certificate served by the endpoint."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func certCoversSNI(c *x509.Certificate, sni string) bool {\n    for _, san := range c.DNSNames {\n        if dnsMatch(sni, san) { return true }\n    }\n    return false\n}\n\nfunc dnsMatch(host, san string) bool {\n    host = strings.ToLower(strings.TrimSuffix(host, \".\") + \".\")\n    san = strings.ToLower(strings.TrimSuffix(san, \".\") + \".\")\n    if !strings.Contains(san, \"*\") { return host == san }\n    if san == \"*.\" || !strings.HasPrefix(san, \"*.\") || strings.Contains(san[1:], \"*\") { return false }\n    if len(host) < len(san) || !strings.HasSuffix(host, san[1:]) { return false }\n    return !strings.Contains(strings.TrimSuffix(host, san[1:]), \".\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Issue server certs whose DNS SANs cover every hostname clients (or AutoHostSNI) will use.","Audit cert SAN sets after renewal against the configured SNI.","Avoid enabling useAutoHostSNI against endpoints whose certs cover only a wildcard-free name."],"tags":["grpc","xds","tls","sni","san","certificate","client"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}