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 56134a2

Browse files
committed
crypto/x509: add directory name constraints
Fixes #15196
1 parent 654b031 commit 56134a2

File tree

5 files changed

+1453
-23
lines changed

5 files changed

+1453
-23
lines changed

‎src/crypto/x509/parser.go

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -504,27 +504,40 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
504504
return false, errors.New("x509: empty name constraints extension")
505505
}
506506

507-
getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
507+
getValues := func(subtrees cryptobyte.String) (dirNames []pkix.RDNSequence, dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
508508
for !subtrees.Empty() {
509509
var seq, value cryptobyte.String
510510
var tag cryptobyte_asn1.Tag
511511
if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
512512
!seq.ReadAnyASN1(&value, &tag) {
513-
return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
513+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
514514
}
515515

516516
var (
517-
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
518-
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
519-
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
520-
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
517+
dirNameTag = cryptobyte_asn1.Tag(4).ContextSpecific().Constructed()
518+
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
519+
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
520+
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
521+
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
521522
)
522523

523524
switch tag {
525+
case dirNameTag:
526+
527+
var dirName pkix.RDNSequence
528+
529+
if rest, err := asn1.Unmarshal(value, &dirName); err != nil {
530+
return nil, nil, nil, nil, nil, err
531+
} else if len(rest) != 0 {
532+
return nil, nil, nil, nil, nil, errors.New("x509: trailing data after dirname constraint")
533+
}
534+
535+
dirNames = append(dirNames, dirName)
536+
524537
case dnsTag:
525538
domain := string(value)
526539
if err := isIA5String(domain); err != nil {
527-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
540+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
528541
}
529542

530543
trimmedDomain := domain
@@ -536,7 +549,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
536549
trimmedDomain = trimmedDomain[1:]
537550
}
538551
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
539-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
552+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
540553
}
541554
dnsNames = append(dnsNames, domain)
542555

@@ -554,26 +567,26 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
554567
mask = value[16:]
555568

556569
default:
557-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
570+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
558571
}
559572

560573
if !isValidIPMask(mask) {
561-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
574+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
562575
}
563576

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

566579
case emailTag:
567580
constraint := string(value)
568581
if err := isIA5String(constraint); err != nil {
569-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
582+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
570583
}
571584

572585
// If the constraint contains an @ then
573586
// it specifies an exact mailbox name.
574587
if strings.Contains(constraint, "@") {
575588
if _, ok := parseRFC2821Mailbox(constraint); !ok {
576-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
589+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
577590
}
578591
} else {
579592
// Otherwise it's a domain name.
@@ -582,19 +595,19 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
582595
domain = domain[1:]
583596
}
584597
if _, ok := domainToReverseLabels(domain); !ok {
585-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
598+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
586599
}
587600
}
588601
emails = append(emails, constraint)
589602

590603
case uriTag:
591604
domain := string(value)
592605
if err := isIA5String(domain); err != nil {
593-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
606+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
594607
}
595608

596609
if net.ParseIP(domain) != nil {
597-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
610+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
598611
}
599612

600613
trimmedDomain := domain
@@ -606,7 +619,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
606619
trimmedDomain = trimmedDomain[1:]
607620
}
608621
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
609-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
622+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
610623
}
611624
uriDomains = append(uriDomains, domain)
612625

@@ -615,13 +628,13 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
615628
}
616629
}
617630

618-
return dnsNames, ips, emails, uriDomains, nil
631+
return dirNames, dnsNames, ips, emails, uriDomains, nil
619632
}
620633

621-
if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
634+
if out.PermittedDirNames, out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
622635
return false, err
623636
}
624-
if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
637+
if out.ExcludedDirNames, out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
625638
return false, err
626639
}
627640
out.PermittedDNSDomainsCritical = e.Critical

‎src/crypto/x509/verify.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bytes"
99
"crypto"
1010
"crypto/x509/pkix"
11+
"encoding/asn1"
1112
"errors"
1213
"fmt"
1314
"net"
@@ -493,6 +494,34 @@ func matchDomainConstraint(domain, constraint string) (bool, error) {
493494
return true, nil
494495
}
495496

497+
func matchDirNameConstraint(dirname pkix.RDNSequence, constraint pkix.RDNSequence) (bool, error) {
498+
499+
if len(constraint) > len(dirname) {
500+
return false, nil
501+
}
502+
for i, rdn := range constraint {
503+
if len(rdn) > len(dirname[i]) {
504+
return false, nil
505+
}
506+
for j, const_tv := range rdn {
507+
dirname_tv := dirname[i][j]
508+
if len(const_tv.Type) != len(dirname_tv.Type) {
509+
return false, nil
510+
}
511+
for k, _ := range const_tv.Type {
512+
if const_tv.Type[k] != dirname_tv.Type[k] {
513+
return false, nil
514+
}
515+
}
516+
if const_tv.Value != dirname_tv.Value {
517+
return false, nil
518+
}
519+
}
520+
}
521+
522+
return true, nil
523+
}
524+
496525
// checkNameConstraints checks that c permits a child certificate to claim the
497526
// given name, of type nameType. The argument parsedName contains the parsed
498527
// form of name, suitable for passing to the match function. The total number
@@ -599,6 +628,26 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
599628
leaf = currentChain[0]
600629
}
601630

631+
if (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() {
632+
for _, cert := range currentChain {
633+
var subject pkix.RDNSequence
634+
635+
// cert.Subject.ToRDNSequence cannot be used as it ignores unknown RDN
636+
if rest, err := asn1.Unmarshal(cert.RawSubject, &subject); err != nil {
637+
return err
638+
} else if len(rest) != 0 {
639+
return errors.New("x509: trailing data after X.509 subject")
640+
}
641+
642+
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "directory Name", cert.Subject.String(), subject,
643+
func(parsedName, constraint interface{}) (bool, error) {
644+
return matchDirNameConstraint(parsedName.(pkix.RDNSequence), constraint.(pkix.RDNSequence))
645+
}, c.PermittedDirNames, c.ExcludedDirNames); err != nil {
646+
return err
647+
}
648+
}
649+
}
650+
602651
if (certType == intermediateCertificate || certType == rootCertificate) &&
603652
c.hasNameConstraints() {
604653
toCheck := []*Certificate{}

0 commit comments

Comments
(0)

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