In Go 1.19, Certificate.Verify was changed to also enforce name constraints on non-leaf certificates. https://tip.golang.org/doc/go1.19#crypto/x509
However, as per the source code, this is enforced by saying that if certificate X has a name constraint, then it gets enforced on both (and only) the leaf and certificate X. This violates RFC 5280 section 4.2.1.10:
The name constraints extension, which MUST be used only in a CA
certificate, indicates a name space within which all subject names in
subsequent certificates in a certification path MUST be located.
Restrictions apply to the subject distinguished name and apply to
subject alternative names. Restrictions apply only when the
specified name form is present. If no name of the type is in the
certificate, the certificate is acceptable.
Note that the RFC clearly says "subsequent certificates", which means that enforcing a certificate's name constraints on itself is incorrect. In addition, Go is not enforcing the name constraints on the subsequent intermediate certificates in the chain, which also violates the RFC.
As an example, here we have a root certificate with a name constraint for "example.com", an intermediate certificate with a SAN of "www.sample.com", and a leaf certificate with a SAN of "www.example.com". This should be rejected due to the invalid intermediate SAN, but is accepted. https://go.dev/play/p/Ozj9G8lZaD6
In this example, we have a root certificate with a name constraint for "example.com" and a SAN of "foobar.com", an intermediate certificate with no SANs, and a leaf certificate with a SAN of "www.example.com". This should be accepted because the root name constraint is not supposed to apply to itself, but is rejected. https://go.dev/play/p/eeq2mE4Dzby
Note that OpenSSL properly follows the RFC in both cases. (That is, it properly rejects the first example, and properly accepts the second example.)
In Go 1.19,
Certificate.Verifywas changed to also enforce name constraints on non-leaf certificates. https://tip.golang.org/doc/go1.19#crypto/x509However, as per the source code, this is enforced by saying that if certificate X has a name constraint, then it gets enforced on both (and only) the leaf and certificate X. This violates RFC 5280 section 4.2.1.10:
Note that the RFC clearly says "subsequent certificates", which means that enforcing a certificate's name constraints on itself is incorrect. In addition, Go is not enforcing the name constraints on the subsequent intermediate certificates in the chain, which also violates the RFC.
As an example, here we have a root certificate with a name constraint for "example.com", an intermediate certificate with a SAN of "www.sample.com", and a leaf certificate with a SAN of "www.example.com". This should be rejected due to the invalid intermediate SAN, but is accepted. https://go.dev/play/p/Ozj9G8lZaD6
In this example, we have a root certificate with a name constraint for "example.com" and a SAN of "foobar.com", an intermediate certificate with no SANs, and a leaf certificate with a SAN of "www.example.com". This should be accepted because the root name constraint is not supposed to apply to itself, but is rejected. https://go.dev/play/p/eeq2mE4Dzby
Note that OpenSSL properly follows the RFC in both cases. (That is, it properly rejects the first example, and properly accepts the second example.)