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 d814809

Browse files
committed
crypto/x509: add directory name constraints
Adam Langley implemented the optional part of name constraints (9e76ce7) left the directory name validation, which is a mandatory part of RFC5280, section 4.2.1.10. Fixes #15196
1 parent 70e0470 commit d814809

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
@@ -515,27 +515,40 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
515515
return false, errors.New("x509: empty name constraints extension")
516516
}
517517

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

527527
var (
528-
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
529-
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
530-
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
531-
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
528+
dirNameTag = cryptobyte_asn1.Tag(4).ContextSpecific().Constructed()
529+
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
530+
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
531+
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
532+
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
532533
)
533534

534535
switch tag {
536+
case dirNameTag:
537+
538+
var dirName pkix.RDNSequence
539+
540+
if rest, err := asn1.Unmarshal(value, &dirName); err != nil {
541+
return nil, nil, nil, nil, nil, err
542+
} else if len(rest) != 0 {
543+
return nil, nil, nil, nil, nil, errors.New("x509: trailing data after dirname constraint")
544+
}
545+
546+
dirNames = append(dirNames, dirName)
547+
535548
case dnsTag:
536549
domain := string(value)
537550
if err := isIA5String(domain); err != nil {
538-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
551+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
539552
}
540553

541554
trimmedDomain := domain
@@ -547,7 +560,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
547560
trimmedDomain = trimmedDomain[1:]
548561
}
549562
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
550-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
563+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
551564
}
552565
dnsNames = append(dnsNames, domain)
553566

@@ -565,26 +578,26 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
565578
mask = value[16:]
566579

567580
default:
568-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
581+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
569582
}
570583

571584
if !isValidIPMask(mask) {
572-
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
585+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
573586
}
574587

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

577590
case emailTag:
578591
constraint := string(value)
579592
if err := isIA5String(constraint); err != nil {
580-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
593+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
581594
}
582595

583596
// If the constraint contains an @ then
584597
// it specifies an exact mailbox name.
585598
if strings.Contains(constraint, "@") {
586599
if _, ok := parseRFC2821Mailbox(constraint); !ok {
587-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
600+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
588601
}
589602
} else {
590603
// Otherwise it's a domain name.
@@ -593,19 +606,19 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
593606
domain = domain[1:]
594607
}
595608
if _, ok := domainToReverseLabels(domain); !ok {
596-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
609+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
597610
}
598611
}
599612
emails = append(emails, constraint)
600613

601614
case uriTag:
602615
domain := string(value)
603616
if err := isIA5String(domain); err != nil {
604-
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
617+
return nil, nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
605618
}
606619

607620
if net.ParseIP(domain) != nil {
608-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
621+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
609622
}
610623

611624
trimmedDomain := domain
@@ -617,7 +630,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
617630
trimmedDomain = trimmedDomain[1:]
618631
}
619632
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
620-
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
633+
return nil, nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
621634
}
622635
uriDomains = append(uriDomains, domain)
623636

@@ -626,13 +639,13 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
626639
}
627640
}
628641

629-
return dnsNames, ips, emails, uriDomains, nil
642+
return dirNames, dnsNames, ips, emails, uriDomains, nil
630643
}
631644

632-
if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
645+
if out.PermittedDirNames, out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
633646
return false, err
634647
}
635-
if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
648+
if out.ExcludedDirNames, out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
636649
return false, err
637650
}
638651
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
@@ -597,6 +626,26 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
597626
}
598627
}
599628

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

0 commit comments

Comments
(0)

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