@@ -379,10 +379,14 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string
379379 if err := isIA5String (email ); err != nil {
380380 return errors .New ("x509: SAN rfc822Name is malformed" )
381381 }
382+ parsed , ok := parseRFC2821Mailbox (email )
383+ if ! ok || (ok && ! domainNameValid (parsed .domain , false )) {
384+ return errors .New ("x509: SAN rfc822Name is malformed" )
385+ }
382386 emailAddresses = append (emailAddresses , email )
383387 case nameTypeDNS :
384388 name := string (data )
385- if err := isIA5String (name ); err != nil {
389+ if err := isIA5String (name ); err != nil || ( err == nil && ! domainNameValid ( name , false )) {
386390 return errors .New ("x509: SAN dNSName is malformed" )
387391 }
388392 dnsNames = append (dnsNames , string (name ))
@@ -392,14 +396,9 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string
392396 return errors .New ("x509: SAN uniformResourceIdentifier is malformed" )
393397 }
394398 uri , err := url .Parse (uriStr )
395- if err != nil {
399+ if err != nil || ( err == nil && uri . Host != "" && ! domainNameValid ( uri . Host , false )) {
396400 return fmt .Errorf ("x509: cannot parse URI %q: %s" , uriStr , err )
397401 }
398- if len (uri .Host ) > 0 {
399- if _ , ok := domainToReverseLabels (uri .Host ); ! ok {
400- return fmt .Errorf ("x509: cannot parse URI %q: invalid domain" , uriStr )
401- }
402- }
403402 uris = append (uris , uri )
404403 case nameTypeIP :
405404 switch len (data ) {
@@ -559,15 +558,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
559558 return nil , nil , nil , nil , errors .New ("x509: invalid constraint value: " + err .Error ())
560559 }
561560
562- trimmedDomain := domain
563- if len (trimmedDomain ) > 0 && trimmedDomain [0 ] == '.' {
564- // constraints can have a leading
565- // period to exclude the domain
566- // itself, but that's not valid in a
567- // normal domain name.
568- trimmedDomain = trimmedDomain [1 :]
569- }
570- if _ , ok := domainToReverseLabels (trimmedDomain ); ! ok {
561+ if ! domainNameValid (domain , true ) {
571562 return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse dnsName constraint %q" , domain )
572563 }
573564 dnsNames = append (dnsNames , domain )
@@ -608,12 +599,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
608599 return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse rfc822Name constraint %q" , constraint )
609600 }
610601 } else {
611- // Otherwise it's a domain name.
612- domain := constraint
613- if len (domain ) > 0 && domain [0 ] == '.' {
614- domain = domain [1 :]
615- }
616- if _ , ok := domainToReverseLabels (domain ); ! ok {
602+ if ! domainNameValid (constraint , true ) {
617603 return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse rfc822Name constraint %q" , constraint )
618604 }
619605 }
@@ -629,15 +615,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
629615 return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse URI constraint %q: cannot be IP address" , domain )
630616 }
631617
632- trimmedDomain := domain
633- if len (trimmedDomain ) > 0 && trimmedDomain [0 ] == '.' {
634- // constraints can have a leading
635- // period to exclude the domain itself,
636- // but that's not valid in a normal
637- // domain name.
638- trimmedDomain = trimmedDomain [1 :]
639- }
640- if _ , ok := domainToReverseLabels (trimmedDomain ); ! ok {
618+ if ! domainNameValid (domain , true ) {
641619 return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse URI constraint %q" , domain )
642620 }
643621 uriDomains = append (uriDomains , domain )
@@ -1229,3 +1207,40 @@ func ParseRevocationList(der []byte) (*RevocationList, error) {
12291207
12301208 return rl , nil
12311209}
1210+
1211+ // domainNameValid does minimal domain name validity checking. In particular it
1212+ // enforces the following properties:
1213+ // - names cannot have the trailing period
1214+ // - names can only have a leading period if constraint is true
1215+ // - names must be <= 253 characters
1216+ // - names cannot have empty labels
1217+ // - names cannot labels that are longer than 63 characters
1218+ //
1219+ // Note that this does not enforce the LDH requirements for domain names.
1220+ func domainNameValid (s string , constraint bool ) bool {
1221+ if len (s ) == 0 && constraint {
1222+ return true
1223+ }
1224+ if len (s ) == 0 || (! constraint && s [0 ] == '.' ) || s [len (s )- 1 ] == '.' || len (s ) > 253 {
1225+ return false
1226+ }
1227+ lastDot := - 1
1228+ if constraint && s [0 ] == '.' {
1229+ s = s [1 :]
1230+ }
1231+
1232+ for i := 0 ; i <= len (s ); i ++ {
1233+ if i == len (s ) || s [i ] == '.' {
1234+ labelLen := i
1235+ if lastDot >= 0 {
1236+ labelLen -= lastDot + 1
1237+ }
1238+ if labelLen == 0 || labelLen > 63 {
1239+ return false
1240+ }
1241+ lastDot = i
1242+ }
1243+ }
1244+
1245+ return true
1246+ }
0 commit comments