Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4f8fbd3

Browse files
committed
crypto/x509: add directory name constraints (WIP)
It is still missing tests. Fixes #15196
1 parent e25aa4f commit 4f8fbd3

File tree

2 files changed

+82
-19
lines changed

2 files changed

+82
-19
lines changed

‎src/crypto/x509/verify.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package x509
66

77
import (
88
"bytes"
9+
"crypto/x509/pkix"
10+
"encoding/asn1"
911
"errors"
1012
"fmt"
1113
"net"
@@ -516,6 +518,34 @@ func matchDomainConstraint(domain, constraint string) (bool, error) {
516518
return true, nil
517519
}
518520

521+
func matchDirNameConstraint(dirname pkix.RDNSequence, constraint *pkix.RDNSequence) (bool, error) {
522+
523+
if len(*constraint) > len(dirname) {
524+
return false, nil
525+
}
526+
for i, rdn := range *constraint {
527+
if len(rdn) > len(dirname[i]) {
528+
return false, nil
529+
}
530+
for j, const_tv := range rdn {
531+
dirname_tv := dirname[i][j]
532+
if len(const_tv.Type) != len(dirname_tv.Type) {
533+
return false, nil
534+
}
535+
for k, _ := range const_tv.Type {
536+
if const_tv.Type[k] != dirname_tv.Type[k] {
537+
return false, nil
538+
}
539+
}
540+
if const_tv.Value != dirname_tv.Value {
541+
return false, nil
542+
}
543+
}
544+
}
545+
546+
return true, nil
547+
}
548+
519549
// checkNameConstraints checks that c permits a child certificate to claim the
520550
// given name, of type nameType. The argument parsedName contains the parsed
521551
// form of name, suitable for passing to the match function. The total number
@@ -623,6 +653,24 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
623653
}
624654

625655
checkNameConstraints := (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints()
656+
if checkNameConstraints {
657+
var leafSubject pkix.RDNSequence
658+
659+
// leaf.Subject.ToRDNSequence cannot be used as it ignores unknown RDN
660+
if rest, err := asn1.Unmarshal(leaf.RawSubject, &leafSubject); err != nil {
661+
return err
662+
} else if len(rest) != 0 {
663+
return errors.New("x509: trailing data after X.509 subject")
664+
}
665+
666+
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "directory Name", leaf.Subject.String(), leafSubject,
667+
func(parsedName, constraint interface{}) (bool, error) {
668+
return matchDirNameConstraint(parsedName.(pkix.RDNSequence), constraint.(*pkix.RDNSequence))
669+
}, c.PermittedDirNames, c.ExcludedDirNames); err != nil {
670+
return err
671+
}
672+
}
673+
626674
if checkNameConstraints && leaf.commonNameAsHostname() {
627675
// This is the deprecated, legacy case of depending on the commonName as
628676
// a hostname. We don't enforce name constraints against the CN, but

‎src/crypto/x509/x509.go

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ type Certificate struct {
748748

749749
// Name constraints
750750
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
751+
PermittedDirNames []*pkix.RDNSequence
752+
ExcludedDirNames []*pkix.RDNSequence
751753
PermittedDNSDomains []string
752754
ExcludedDNSDomains []string
753755
PermittedIPRanges []*net.IPNet
@@ -1211,27 +1213,28 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
12111213
return false, errors.New("x509: empty name constraints extension")
12121214
}
12131215

1214-
getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
1216+
getValues := func(subtrees cryptobyte.String) (dirNames []*pkix.RDNSequence, dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
12151217
for !subtrees.Empty() {
12161218
var seq, value cryptobyte.String
12171219
var tag cryptobyte_asn1.Tag
12181220
if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
12191221
!seq.ReadAnyASN1(&value, &tag) {
1220-
return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
1222+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
12211223
}
12221224

12231225
var (
1224-
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
1225-
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
1226-
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
1227-
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
1226+
dirNameTag = cryptobyte_asn1.Tag(4).ContextSpecific().Constructed()
1227+
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
1228+
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
1229+
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
1230+
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
12281231
)
12291232

12301233
switch tag {
12311234
case dnsTag:
12321235
domain := string(value)
12331236
if err := isIA5String(domain); err != nil {
1234-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
1237+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
12351238
}
12361239

12371240
trimmedDomain := domain
@@ -1243,10 +1246,22 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
12431246
trimmedDomain = trimmedDomain[1:]
12441247
}
12451248
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
1246-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
1249+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
12471250
}
12481251
dnsNames = append(dnsNames, domain)
12491252

1253+
case dirNameTag:
1254+
1255+
var dirName pkix.RDNSequence
1256+
1257+
if rest, err := asn1.Unmarshal(value, &dirName); err != nil {
1258+
return nil, nil, nil, nil, nil, err
1259+
} else if len(rest) != 0 {
1260+
return nil, nil, nil, nil, nil, errors.New("x509: trailing data after dirname constraint")
1261+
}
1262+
1263+
dirNames = append(dirNames, &dirName)
1264+
12501265
case ipTag:
12511266
l := len(value)
12521267
var ip, mask []byte
@@ -1261,26 +1276,26 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
12611276
mask = value[16:]
12621277

12631278
default:
1264-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
1279+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
12651280
}
12661281

12671282
if !isValidIPMask(mask) {
1268-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
1283+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
12691284
}
12701285

12711286
ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)})
12721287

12731288
case emailTag:
12741289
constraint := string(value)
12751290
if err := isIA5String(constraint); err != nil {
1276-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
1291+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
12771292
}
12781293

12791294
// If the constraint contains an @ then
12801295
// it specifies an exact mailbox name.
12811296
if strings.Contains(constraint, "@") {
12821297
if _, ok := parseRFC2821Mailbox(constraint); !ok {
1283-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
1298+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
12841299
}
12851300
} else {
12861301
// Otherwise it's a domain name.
@@ -1289,19 +1304,19 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
12891304
domain = domain[1:]
12901305
}
12911306
if _, ok := domainToReverseLabels(domain); !ok {
1292-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
1307+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
12931308
}
12941309
}
12951310
emails = append(emails, constraint)
12961311

12971312
case uriTag:
12981313
domain := string(value)
12991314
if err := isIA5String(domain); err != nil {
1300-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
1315+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
13011316
}
13021317

13031318
if net.ParseIP(domain) != nil {
1304-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
1319+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
13051320
}
13061321

13071322
trimmedDomain := domain
@@ -1313,7 +1328,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
13131328
trimmedDomain = trimmedDomain[1:]
13141329
}
13151330
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
1316-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
1331+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
13171332
}
13181333
uriDomains = append(uriDomains, domain)
13191334

@@ -1322,13 +1337,13 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
13221337
}
13231338
}
13241339

1325-
return dnsNames, ips, emails, uriDomains, nil
1340+
return dirNames, dnsNames, ips, emails, uriDomains, nil
13261341
}
13271342

1328-
if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
1343+
if out.PermittedDirNames, out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
13291344
return false, err
13301345
}
1331-
if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
1346+
if out.ExcludedDirNames, out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
13321347
return false, err
13331348
}
13341349
out.PermittedDNSDomainsCritical = e.Critical

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /