Skip to content

Commit b8c62b1

Browse files
aglandybons
authored andcommitted
[release-branch.go1.10] crypto/x509: parse invalid DNS names and email addresses.
Go 1.10 requires that SANs in certificates are valid. However, a non-trivial number of (generally non-WebPKI) certificates have invalid strings in dnsName fields and some have even put those dnsName SANs in CA certificates. This change defers validity checking until name constraints are checked. Fixes #23995, #23711. Change-Id: I2e0ebb0898c047874a3547226b71e3029333b7f1 Reviewed-on: https://go-review.googlesource.com/96378 Run-TryBot: Adam Langley <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-on: https://go-review.googlesource.com/102783 Run-TryBot: Andrew Bonventre <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]>
1 parent 176900a commit b8c62b1

File tree

3 files changed

+82
-18
lines changed

3 files changed

+82
-18
lines changed

src/crypto/x509/name_constraints_test.go

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"crypto/rand"
1212
"crypto/x509/pkix"
1313
"encoding/asn1"
14+
"encoding/hex"
1415
"encoding/pem"
1516
"fmt"
1617
"io/ioutil"
@@ -1482,6 +1483,64 @@ var nameConstraintsTests = []nameConstraintsTest{
14821483
},
14831484
requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
14841485
},
1486+
1487+
// An invalid DNS SAN should be detected only at validation time so
1488+
// that we can process CA certificates in the wild that have invalid SANs.
1489+
// See https://github.com/golang/go/issues/23995
1490+
1491+
// #77: an invalid DNS or mail SAN will not be detected if name constaint
1492+
// checking is not triggered.
1493+
nameConstraintsTest{
1494+
roots: []constraintsSpec{
1495+
constraintsSpec{},
1496+
},
1497+
intermediates: [][]constraintsSpec{
1498+
[]constraintsSpec{
1499+
constraintsSpec{},
1500+
},
1501+
},
1502+
leaf: leafSpec{
1503+
sans: []string{"dns:this is invalid", "email:this @ is invalid"},
1504+
},
1505+
},
1506+
1507+
// #78: an invalid DNS SAN will be detected if any name constraint checking
1508+
// is triggered.
1509+
nameConstraintsTest{
1510+
roots: []constraintsSpec{
1511+
constraintsSpec{
1512+
bad: []string{"uri:"},
1513+
},
1514+
},
1515+
intermediates: [][]constraintsSpec{
1516+
[]constraintsSpec{
1517+
constraintsSpec{},
1518+
},
1519+
},
1520+
leaf: leafSpec{
1521+
sans: []string{"dns:this is invalid"},
1522+
},
1523+
expectedError: "cannot parse dnsName",
1524+
},
1525+
1526+
// #79: an invalid email SAN will be detected if any name constraint
1527+
// checking is triggered.
1528+
nameConstraintsTest{
1529+
roots: []constraintsSpec{
1530+
constraintsSpec{
1531+
bad: []string{"uri:"},
1532+
},
1533+
},
1534+
intermediates: [][]constraintsSpec{
1535+
[]constraintsSpec{
1536+
constraintsSpec{},
1537+
},
1538+
},
1539+
leaf: leafSpec{
1540+
sans: []string{"email:this @ is invalid"},
1541+
},
1542+
expectedError: "cannot parse rfc822Name",
1543+
},
14851544
}
14861545

14871546
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
@@ -1550,6 +1609,13 @@ func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certi
15501609
}
15511610
template.IPAddresses = append(template.IPAddresses, ip)
15521611

1612+
case strings.HasPrefix(name, "invalidip:"):
1613+
ipBytes, err := hex.DecodeString(name[10:])
1614+
if err != nil {
1615+
return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
1616+
}
1617+
template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
1618+
15531619
case strings.HasPrefix(name, "email:"):
15541620
template.EmailAddresses = append(template.EmailAddresses, name[6:])
15551621

@@ -2011,12 +2077,13 @@ func TestBadNamesInConstraints(t *testing.T) {
20112077
}
20122078

20132079
func TestBadNamesInSANs(t *testing.T) {
2014-
// Bad names in SANs should not parse.
2080+
// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
2081+
// will parse and are tested in name constraint tests at the top of this
2082+
// file.
20152083
badNames := []string{
2016-
"dns:foo.com.",
2017-
2018-
"email:foo.com.",
20192084
"uri:https://example.com./dsf",
2085+
"invalidip:0102",
2086+
"invalidip:0102030405",
20202087
}
20212088

20222089
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

src/crypto/x509/verify.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
640640
name := string(data)
641641
mailbox, ok := parseRFC2821Mailbox(name)
642642
if !ok {
643-
// This certificate should not have parsed.
644-
return errors.New("x509: internal error: rfc822Name SAN failed to parse")
643+
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
645644
}
646645

647646
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
@@ -653,6 +652,10 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
653652

654653
case nameTypeDNS:
655654
name := string(data)
655+
if _, ok := domainToReverseLabels(name); !ok {
656+
return fmt.Errorf("x509: cannot parse dnsName %q", name)
657+
}
658+
656659
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
657660
func(parsedName, constraint interface{}) (bool, error) {
658661
return matchDomainConstraint(parsedName.(string), constraint.(string))

src/crypto/x509/x509.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,9 @@ type Certificate struct {
706706
OCSPServer []string
707707
IssuingCertificateURL []string
708708

709-
// Subject Alternate Name values
709+
// Subject Alternate Name values. (Note that these values may not be valid
710+
// if invalid values were contained within a parsed certificate. For
711+
// example, an element of DNSNames may not be a valid DNS domain name.)
710712
DNSNames []string
711713
EmailAddresses []string
712714
IPAddresses []net.IP
@@ -1126,17 +1128,9 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
11261128
err = forEachSAN(value, func(tag int, data []byte) error {
11271129
switch tag {
11281130
case nameTypeEmail:
1129-
mailbox := string(data)
1130-
if _, ok := parseRFC2821Mailbox(mailbox); !ok {
1131-
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
1132-
}
1133-
emailAddresses = append(emailAddresses, mailbox)
1131+
emailAddresses = append(emailAddresses, string(data))
11341132
case nameTypeDNS:
1135-
domain := string(data)
1136-
if _, ok := domainToReverseLabels(domain); !ok {
1137-
return fmt.Errorf("x509: cannot parse dnsName %q", string(data))
1138-
}
1139-
dnsNames = append(dnsNames, domain)
1133+
dnsNames = append(dnsNames, string(data))
11401134
case nameTypeURI:
11411135
uri, err := url.Parse(string(data))
11421136
if err != nil {
@@ -1153,7 +1147,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
11531147
case net.IPv4len, net.IPv6len:
11541148
ipAddresses = append(ipAddresses, data)
11551149
default:
1156-
return errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(data)))
1150+
return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
11571151
}
11581152
}
11591153

0 commit comments

Comments
 (0)