Skip to content

crypto/x509: single-label excluded DNS name constraints incorrectly match all wildcard SANs #76935

Description

@zcayou

Summary

The fix for CVE-2025-61727 (commit 287017a) introduced a regression where a single-label excluded DNS name constraint (e.g. a TLD) incorrectly causes all wildcard SANs to be rejected.

Go Version

go version go1.25.5 linux/amd64

Environment

This occurs in environments using TLS-inspecting proxies with CA certificates that have Name Constraints excluding TLDs. This is common in TLD-owning entities where PKI hierarchies exclude .<tld> domains to prevent the proxy CA from issuing certificates for that entity.

What did you do?

Attempted to validate a certificate chain where:

  1. An intermediate CA has X509v3 Name Constraints with Excluded: DNS:<tld>
  2. The leaf certificate has wildcard SANs such as *.aiplatform-notebook.cloud.google.com

Minimal reproduction:

package main

import (
	"crypto/tls"
	"fmt"
)

func main() {
	conf := &tls.Config{ServerName: "sum.golang.org"}
	conn, err := tls.Dial("tcp", "sum.golang.org:443", conf)
	if err != nil {
		fmt.Println("tls.Dial error:", err)
		return
	}
	defer conn.Close()
	fmt.Println("Handshake OK")
}

The above fails when the system trust store includes a CA chain where an intermediate has single-label excluded DNS constraints.

        X509v3 extensions:
            X509v3 Name Constraints: critical
                Excluded:
                  DNS:<tld>

What did you expect to see?

Certificate validation should succeed, or at least not fail due to the TLD's name constraints.

What did you see instead?

tls.Dial error: tls: failed to verify certificate: x509: a root or intermediate certificate is not authorized to sign for this name: DNS name "*.aiplatform-notebook.cloud.google.com" is excluded by constraint "<tld>"

Root Cause Analysis

The bug is in matchDomainConstraint() in src/crypto/x509/verify.go. The CVE-2025-61727 fix in 287017a added logic to handle wildcard SANs against excluded subdomain constraints:

if excluded && wildcardDomain && len(domainLabels) > 1 && len(constraintLabels) > 0 {
    domainLabels = domainLabels[:len(domainLabels)-1]
    constraintLabels = constraintLabels[:len(constraintLabels)-1]
}

This logic causes all wildcard SANs to incorrectly match single-label constraints by turning constraintLabels into a zero-length slice, bypassing the subsequent matching loop.

for i, constraintLabel := range constraintLabels {
	if !strings.EqualFold(constraintLabel, domainLabels[i]) {
		return false, nil
	}
}

return true, nil

Related Issues

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.Security

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions