@@ -58,11 +58,11 @@ import (
5858// of nameConstraintsSet, to handle constraints which define full email
5959// addresses (i.e. 'test@example.com'). For bare domain constraints, we use the
6060// dnsConstraints type described above, querying the domain portion of the email
61- // address. For full email addresses, we also hold a map of email addresses that
62- // map the local portion of the email to the domain. When querying full email
63- // addresses we then check if the local portion of the email is present in the
64- // map, and if so case insensitively compare the domain portion of the
65- // email.
61+ // address. For full email addresses, we also hold a map of email addresses with
62+ // the domain portion of the email lowercased, since it is case insensitive. When
63+ // looking up an email address in the constraint set, we first check the full
64+ // email address map, and if we don't find anything, we check the domain portion
65+ // of the email address against the dnsConstraints .
6666
6767type nameConstraintsSet [T * net.IPNet | string , V net.IP | string ] struct {
6868 set []T
@@ -375,7 +375,7 @@ func (dnc *dnsConstraints) query(s string) (string, bool) {
375375 return constraint , true
376376 }
377377
378- if ! dnc .permitted && s [0 ] == '*' {
378+ if ! dnc .permitted && len ( s ) > 0 && s [0 ] == '*' {
379379 trimmed := trimFirstLabel (s )
380380 if constraint , found := dnc .parentConstraints [trimmed ]; found {
381381 return constraint , true
@@ -387,16 +387,22 @@ func (dnc *dnsConstraints) query(s string) (string, bool) {
387387type emailConstraints struct {
388388 dnsConstraints interface { query (string ) (string , bool ) }
389389
390- fullEmails map [string ]string
390+ // fullEmails is map of rfc2821Mailboxs that are fully specified in the
391+ // constraints, which we need to check for separately since they don't
392+ // follow the same matching rules as the domain-based constraints. The
393+ // domain portion of the rfc2821Mailbox has been lowercased, since the
394+ // domain portion is case insensitive. When checking the map for an email,
395+ // the domain portion of the query should also be lowercased.
396+ fullEmails map [rfc2821Mailbox ]struct {}
391397}
392398
393399func newEmailConstraints (l []string , permitted bool ) interface {
394- query (parsedEmail ) (string , bool )
400+ query (rfc2821Mailbox ) (string , bool )
395401} {
396402 if len (l ) == 0 {
397403 return nil
398404 }
399- exactMap := map [string ] string {}
405+ exactMap := map [rfc2821Mailbox ] struct {} {}
400406 var domains []string
401407 for _ , c := range l {
402408 if ! strings .ContainsRune (c , '@' ) {
@@ -411,7 +417,8 @@ func newEmailConstraints(l []string, permitted bool) interface {
411417 // certificate since parsing.
412418 continue
413419 }
414- exactMap [parsed .local ] = parsed .domain
420+ parsed .domain = strings .ToLower (parsed .domain )
421+ exactMap [parsed ] = struct {}{}
415422 }
416423 ec := & emailConstraints {
417424 fullEmails : exactMap ,
@@ -422,16 +429,16 @@ func newEmailConstraints(l []string, permitted bool) interface {
422429 return ec
423430}
424431
425- func (ec * emailConstraints ) query (s parsedEmail ) (string , bool ) {
426- if len (ec .fullEmails ) > 0 && strings . ContainsRune ( s . email , '@' ) {
427- if domain , ok := ec .fullEmails [s . mailbox . local ]; ok && strings . EqualFold ( domain , s . mailbox . domain ) {
428- return ec . fullEmails [ s . email ] + "@" + s .mailbox . domain , true
432+ func (ec * emailConstraints ) query (s rfc2821Mailbox ) (string , bool ) {
433+ if len (ec .fullEmails ) > 0 {
434+ if _ , ok := ec .fullEmails [s ]; ok {
435+ return fmt . Sprintf ( "%s@%s" , s . local , s .domain ) , true
429436 }
430437 }
431438 if ec .dnsConstraints == nil {
432439 return "" , false
433440 }
434- constraint , found := ec .dnsConstraints .query (s .mailbox . domain )
441+ constraint , found := ec .dnsConstraints .query (s .domain )
435442 return constraint , found
436443}
437444
@@ -441,7 +448,7 @@ type constraints[T any, V any] struct {
441448 excluded interface { query (V ) (T , bool ) }
442449}
443450
444- func checkConstraints [T string | * net.IPNet , V any , P string | net.IP | parsedURI | parsedEmail ](c constraints [T , V ], s V , p P ) error {
451+ func checkConstraints [T string | * net.IPNet , V any , P string | net.IP | parsedURI | rfc2821Mailbox ](c constraints [T , V ], s V , p P ) error {
445452 if c .permitted != nil {
446453 if _ , found := c .permitted .query (s ); ! found {
447454 return fmt .Errorf ("%s %q is not permitted by any constraint" , c .constraintType , p )
@@ -459,13 +466,13 @@ type chainConstraints struct {
459466 ip constraints [* net.IPNet , net.IP ]
460467 dns constraints [string , string ]
461468 uri constraints [string , string ]
462- email constraints [string , parsedEmail ]
469+ email constraints [string , rfc2821Mailbox ]
463470
464471 index int
465472 next * chainConstraints
466473}
467474
468- func (cc * chainConstraints ) check (dns []string , uris []parsedURI , emails []parsedEmail , ips []net.IP ) error {
475+ func (cc * chainConstraints ) check (dns []string , uris []parsedURI , emails []rfc2821Mailbox , ips []net.IP ) error {
469476 for _ , ip := range ips {
470477 if err := checkConstraints (cc .ip , ip , ip ); err != nil {
471478 return err
@@ -488,8 +495,8 @@ func (cc *chainConstraints) check(dns []string, uris []parsedURI, emails []parse
488495 }
489496 }
490497 for _ , e := range emails {
491- if ! domainNameValid (e .mailbox . domain , false ) {
492- return fmt .Errorf ("x509: cannot parse rfc822Name %q" , e . mailbox )
498+ if ! domainNameValid (e .domain , false ) {
499+ return fmt .Errorf ("x509: cannot parse rfc822Name %q" , e )
493500 }
494501 if err := checkConstraints (cc .email , e , e ); err != nil {
495502 return err
@@ -509,7 +516,7 @@ func checkChainConstraints(chain []*Certificate) error {
509516 ip : constraints [* net.IPNet , net.IP ]{"IP address" , newIPNetConstraints (c .PermittedIPRanges ), newIPNetConstraints (c .ExcludedIPRanges )},
510517 dns : constraints [string , string ]{"DNS name" , newDNSConstraints (c .PermittedDNSDomains , true ), newDNSConstraints (c .ExcludedDNSDomains , false )},
511518 uri : constraints [string , string ]{"URI" , newDNSConstraints (c .PermittedURIDomains , true ), newDNSConstraints (c .ExcludedURIDomains , false )},
512- email : constraints [string , parsedEmail ]{"email address" , newEmailConstraints (c .PermittedEmailAddresses , true ), newEmailConstraints (c .ExcludedEmailAddresses , false )},
519+ email : constraints [string , rfc2821Mailbox ]{"email address" , newEmailConstraints (c .PermittedEmailAddresses , true ), newEmailConstraints (c .ExcludedEmailAddresses , false )},
513520 index : i ,
514521 }
515522 if currentConstraints == nil {
@@ -592,24 +599,15 @@ func parseURIs(uris []*url.URL) ([]parsedURI, error) {
592599 return parsed , nil
593600}
594601
595- type parsedEmail struct {
596- email string
597- mailbox * rfc2821Mailbox
598- }
599-
600- func (e parsedEmail ) String () string {
601- return e .mailbox .local + "@" + e .mailbox .domain
602- }
603-
604- func parseMailboxes (emails []string ) ([]parsedEmail , error ) {
605- parsed := make ([]parsedEmail , 0 , len (emails ))
602+ func parseMailboxes (emails []string ) ([]rfc2821Mailbox , error ) {
603+ parsed := make ([]rfc2821Mailbox , 0 , len (emails ))
606604 for _ , email := range emails {
607605 mailbox , ok := parseRFC2821Mailbox (email )
608606 if ! ok {
609607 return nil , fmt .Errorf ("cannot parse rfc822Name %q" , email )
610608 }
611609 mailbox .domain = strings .ToLower (mailbox .domain )
612- parsed = append (parsed , parsedEmail { strings . ToLower ( email ), & mailbox } )
610+ parsed = append (parsed , mailbox )
613611 }
614612 return parsed , nil
615613}
0 commit comments