mirror of https://github.com/golang/go.git
crypto/x509: add GODEBUG option x509ignoreCN=1
When x509ignoreCN=1 is present in GODEBUG, ignore the deprecated Common Name field. This will let people test a behavior we might make the default in the future, and lets a final class of certificates avoid the NameConstraintsWithoutSANs error. Updates #24151 Change-Id: I1c397aa1fa23777b9251c311d02558f9a5bdefc0 Reviewed-on: https://go-review.googlesource.com/123695 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
parent
4f9ec2c756
commit
0852a104fd
|
|
@ -46,6 +46,7 @@ type nameConstraintsTest struct {
|
|||
requestedEKUs []ExtKeyUsage
|
||||
expectedError string
|
||||
noOpenSSL bool
|
||||
ignoreCN bool
|
||||
}
|
||||
|
||||
type constraintsSpec struct {
|
||||
|
|
@ -1635,6 +1636,26 @@ var nameConstraintsTests = []nameConstraintsTest{
|
|||
cn: "foo.bar",
|
||||
},
|
||||
},
|
||||
|
||||
// #85: without SANs, a certificate with a valid CN is accepted in a
|
||||
// constrained chain if x509ignoreCN is set.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
ok: []string{"dns:foo.com", "dns:.foo.com"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{},
|
||||
cn: "foo.com",
|
||||
},
|
||||
ignoreCN: true,
|
||||
},
|
||||
}
|
||||
|
||||
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
|
||||
|
|
@ -1885,6 +1906,10 @@ func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIden
|
|||
}
|
||||
|
||||
func TestConstraintCases(t *testing.T) {
|
||||
defer func(savedIgnoreCN bool) {
|
||||
ignoreCN = savedIgnoreCN
|
||||
}(ignoreCN)
|
||||
|
||||
privateKeys := sync.Pool{
|
||||
New: func() interface{} {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
|
@ -1976,6 +2001,7 @@ func TestConstraintCases(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
ignoreCN = test.ignoreCN
|
||||
verifyOpts := VerifyOptions{
|
||||
Roots: rootPool,
|
||||
Intermediates: intermediatePool,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
@ -17,6 +18,9 @@ import (
|
|||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// ignoreCN disables interpreting Common Name as a hostname. See issue 24151.
|
||||
var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1")
|
||||
|
||||
type InvalidReason int
|
||||
|
||||
const (
|
||||
|
|
@ -43,6 +47,10 @@ const (
|
|||
// contain a Subject Alternative Name extension, but a CA certificate
|
||||
// contains name constraints, and the Common Name can be interpreted as
|
||||
// a hostname.
|
||||
//
|
||||
// You can avoid this error by setting the experimental GODEBUG environment
|
||||
// variable to "x509ignoreCN=1", disabling Common Name matching entirely.
|
||||
// This behavior might become the default in the future.
|
||||
NameConstraintsWithoutSANs
|
||||
// UnconstrainedName results when a CA certificate contains permitted
|
||||
// name constraints, but leaf certificate contains a name of an
|
||||
|
|
@ -907,7 +915,7 @@ func validHostname(host string) bool {
|
|||
// constraints if there is no risk the CN would be matched as a hostname.
|
||||
// See NameConstraintsWithoutSANs and issue 24151.
|
||||
func (c *Certificate) commonNameAsHostname() bool {
|
||||
return !c.hasSANExtension() && validHostname(c.Subject.CommonName)
|
||||
return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName)
|
||||
}
|
||||
|
||||
func matchHostnames(pattern, host string) bool {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ type verifyTest struct {
|
|||
keyUsages []ExtKeyUsage
|
||||
testSystemRootsError bool
|
||||
sha2 bool
|
||||
ignoreCN bool
|
||||
|
||||
errorCallback func(*testing.T, int, error) bool
|
||||
expectedChains [][]string
|
||||
|
|
@ -349,6 +350,37 @@ var verifyTests = []verifyTest{
|
|||
{"foo.example.com", "Test root"},
|
||||
},
|
||||
},
|
||||
// Replicate CN tests with ignoreCN = true
|
||||
{
|
||||
leaf: ignoreCNWithSANLeaf,
|
||||
dnsName: "foo.example.com",
|
||||
roots: []string{ignoreCNWithSANRoot},
|
||||
currentTime: 1486684488,
|
||||
systemSkip: true,
|
||||
ignoreCN: true,
|
||||
|
||||
errorCallback: expectHostnameError("certificate is not valid for any names"),
|
||||
},
|
||||
{
|
||||
leaf: invalidCNWithoutSAN,
|
||||
dnsName: "foo,invalid",
|
||||
roots: []string{invalidCNRoot},
|
||||
currentTime: 1540000000,
|
||||
systemSkip: true,
|
||||
ignoreCN: true,
|
||||
|
||||
errorCallback: expectHostnameError("Common Name is not a valid hostname"),
|
||||
},
|
||||
{
|
||||
leaf: validCNWithoutSAN,
|
||||
dnsName: "foo.example.com",
|
||||
roots: []string{invalidCNRoot},
|
||||
currentTime: 1540000000,
|
||||
systemSkip: true,
|
||||
ignoreCN: true,
|
||||
|
||||
errorCallback: expectHostnameError("not valid for any names"),
|
||||
},
|
||||
}
|
||||
|
||||
func expectHostnameError(msg string) func(*testing.T, int, error) bool {
|
||||
|
|
@ -454,6 +486,9 @@ func certificateFromPEM(pemBytes string) (*Certificate, error) {
|
|||
}
|
||||
|
||||
func testVerify(t *testing.T, useSystemRoots bool) {
|
||||
defer func(savedIgnoreCN bool) {
|
||||
ignoreCN = savedIgnoreCN
|
||||
}(ignoreCN)
|
||||
for i, test := range verifyTests {
|
||||
if useSystemRoots && test.systemSkip {
|
||||
continue
|
||||
|
|
@ -462,6 +497,7 @@ func testVerify(t *testing.T, useSystemRoots bool) {
|
|||
continue
|
||||
}
|
||||
|
||||
ignoreCN = test.ignoreCN
|
||||
opts := VerifyOptions{
|
||||
Intermediates: NewCertPool(),
|
||||
DNSName: test.dnsName,
|
||||
|
|
|
|||
Loading…
Reference in New Issue