requestedEKUs []ExtKeyUsage
expectedError string
noOpenSSL bool
+ ignoreCN bool
}
type constraintsSpec struct {
type leafSpec struct {
sans []string
ekus []string
+ cn string
}
var nameConstraintsTests = []nameConstraintsTest{
},
},
- // #30: without SANs, a certificate is rejected in a constrained chain.
+ // #30: without SANs, a certificate with a CN is rejected in a constrained chain.
nameConstraintsTest{
roots: []constraintsSpec{
constraintsSpec{
},
leaf: leafSpec{
sans: []string{},
+ cn: "foo.com",
},
expectedError: "leaf doesn't have a SAN extension",
- noOpenSSL: true, // OpenSSL doesn't require SANs in this case.
},
// #31: IPv6 addresses work in constraints: roots can permit them as
ekus: []string{"email", "serverAuth"},
},
},
+
+ // #82: a certificate without SANs and CN is accepted in a constrained chain.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{},
+ },
+ },
+
+ // #83: a certificate without SANs and with a CN that does not parse as a
+ // hostname is accepted in a constrained chain.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{},
+ cn: "foo,bar",
+ },
+ },
+
+ // #84: a certificate with SANs and CN is accepted in a constrained chain.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com"},
+ 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) {
template := &Certificate{
SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
Subject: pkix.Name{
- // Don't set a CommonName because OpenSSL (at least) will try to
- // match it against name constraints.
OrganizationalUnit: []string{"Leaf"},
+ CommonName: leaf.cn,
},
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(2000, 0),
}
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)
t.Fatalf("#%d: cannot create leaf: %s", i, err)
}
- if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL {
+ // Skip tests with CommonName set because OpenSSL will try to match it
+ // against name constraints, while we ignore it when it's not hostname-looking.
+ if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
output, err := testChainAgainstOpenSSL(leafCert, intermediatePool, rootPool)
if err == nil && len(test.expectedError) > 0 {
t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i)
if _, ok := err.(*exec.ExitError); !ok {
t.Errorf("#%d: OpenSSL failed to run: %s", i, err)
} else if len(test.expectedError) == 0 {
- t.Errorf("#%d: OpenSSL unexpectedly failed: %q", i, output)
+ t.Errorf("#%d: OpenSSL unexpectedly failed: %v", i, output)
if debugOpenSSLFailure {
return
}
}
}
+ ignoreCN = test.ignoreCN
verifyOpts := VerifyOptions{
Roots: rootPool,
Intermediates: intermediatePool,
certAsPEM := func(cert *Certificate) string {
var buf bytes.Buffer
pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
- return string(buf.Bytes())
+ return buf.String()
}
t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0]))
t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert))
cmd.Stderr = &output
err := cmd.Run()
- return string(output.Bytes()), err
+ return output.String(), err
}
var rfc2821Tests = []struct {