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 eef1cd3

Browse files
committed
crypto/x509: add directory name constraints
Fixes #15196
1 parent 6097ebe commit eef1cd3

File tree

5 files changed

+1454
-23
lines changed

5 files changed

+1454
-23
lines changed

‎src/crypto/x509/parser.go

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

524-
getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
524+
getValues := func(subtrees cryptobyte.String) (dirNames []pkix.RDNSequence, dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
525525
for !subtrees.Empty() {
526526
var seq, value cryptobyte.String
527527
var tag cryptobyte_asn1.Tag
528528
if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
529529
!seq.ReadAnyASN1(&value, &tag) {
530-
return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
530+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
531531
}
532532

533533
var (
534-
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
535-
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
536-
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
537-
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
534+
dirNameTag = cryptobyte_asn1.Tag(4).ContextSpecific().Constructed()
535+
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
536+
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
537+
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
538+
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
538539
)
539540

540541
switch tag {
542+
case dirNameTag:
543+
544+
var dirName pkix.RDNSequence
545+
546+
if rest, err := asn1.Unmarshal(value, &dirName); err != nil {
547+
return nil, nil, nil, nil, nil, err
548+
} else if len(rest) != 0 {
549+
return nil, nil, nil, nil, nil, errors.New("x509: trailing data after dirname constraint")
550+
}
551+
552+
dirNames = append(dirNames, dirName)
553+
541554
case dnsTag:
542555
domain := string(value)
543556
if err := isIA5String(domain); err != nil {
544-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
557+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
545558
}
546559

547560
trimmedDomain := domain
@@ -553,7 +566,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
553566
trimmedDomain = trimmedDomain[1:]
554567
}
555568
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
556-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
569+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
557570
}
558571
dnsNames = append(dnsNames, domain)
559572

@@ -571,26 +584,26 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
571584
mask = value[16:]
572585

573586
default:
574-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
587+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
575588
}
576589

577590
if !isValidIPMask(mask) {
578-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
591+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
579592
}
580593

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

583596
case emailTag:
584597
constraint := string(value)
585598
if err := isIA5String(constraint); err != nil {
586-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
599+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
587600
}
588601

589602
// If the constraint contains an @ then
590603
// it specifies an exact mailbox name.
591604
if strings.Contains(constraint, "@") {
592605
if _, ok := parseRFC2821Mailbox(constraint); !ok {
593-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
606+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
594607
}
595608
} else {
596609
// Otherwise it's a domain name.
@@ -599,19 +612,19 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
599612
domain = domain[1:]
600613
}
601614
if _, ok := domainToReverseLabels(domain); !ok {
602-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
615+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
603616
}
604617
}
605618
emails = append(emails, constraint)
606619

607620
case uriTag:
608621
domain := string(value)
609622
if err := isIA5String(domain); err != nil {
610-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
623+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
611624
}
612625

613626
if net.ParseIP(domain) != nil {
614-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
627+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
615628
}
616629

617630
trimmedDomain := domain
@@ -623,7 +636,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
623636
trimmedDomain = trimmedDomain[1:]
624637
}
625638
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
626-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
639+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
627640
}
628641
uriDomains = append(uriDomains, domain)
629642

@@ -632,13 +645,13 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
632645
}
633646
}
634647

635-
return dnsNames, ips, emails, uriDomains, nil
648+
return dirNames, dnsNames, ips, emails, uriDomains, nil
636649
}
637650

638-
if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
651+
if out.PermittedDirNames, out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
639652
return false, err
640653
}
641-
if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
654+
if out.ExcludedDirNames, out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
642655
return false, err
643656
}
644657
out.PermittedDNSDomainsCritical = e.Critical

‎src/crypto/x509/verify.go

Lines changed: 50 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"
@@ -491,6 +493,34 @@ func matchDomainConstraint(domain, constraint string) (bool, error) {
491493
return true, nil
492494
}
493495

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

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

0 commit comments

Comments
(0)

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