• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "name_constraints.h"
6 
7 #include <limits.h>
8 
9 #include <memory>
10 
11 #include "cert_errors.h"
12 #include "common_cert_errors.h"
13 #include "general_names.h"
14 #include "ip_util.h"
15 #include "string_util.h"
16 #include "verify_name_match.h"
17 #include "input.h"
18 #include "parser.h"
19 #include "tag.h"
20 #include <optional>
21 #include <openssl/base.h>
22 
23 namespace bssl {
24 
25 namespace {
26 
27 // The name types of GeneralName that are fully supported in name constraints.
28 //
29 // (The other types will have the minimal checking described by RFC 5280
30 // section 4.2.1.10: If a name constraints extension that is marked as critical
31 // imposes constraints on a particular name form, and an instance of
32 // that name form appears in the subject field or subjectAltName
33 // extension of a subsequent certificate, then the application MUST
34 // either process the constraint or reject the certificate.)
35 const int kSupportedNameTypes =
36     GENERAL_NAME_RFC822_NAME | GENERAL_NAME_DNS_NAME |
37     GENERAL_NAME_DIRECTORY_NAME | GENERAL_NAME_IP_ADDRESS;
38 
39 // Controls wildcard handling of DNSNameMatches.
40 // If WildcardMatchType is WILDCARD_PARTIAL_MATCH "*.bar.com" is considered to
41 // match the constraint "foo.bar.com". If it is WILDCARD_FULL_MATCH, "*.bar.com"
42 // will match "bar.com" but not "foo.bar.com".
43 enum WildcardMatchType { WILDCARD_PARTIAL_MATCH, WILDCARD_FULL_MATCH };
44 
45 // Returns true if |name| falls in the subtree defined by |dns_constraint|.
46 // RFC 5280 section 4.2.1.10:
47 // DNS name restrictions are expressed as host.example.com. Any DNS
48 // name that can be constructed by simply adding zero or more labels
49 // to the left-hand side of the name satisfies the name constraint. For
50 // example, www.host.example.com would satisfy the constraint but
51 // host1.example.com would not.
52 //
53 // |wildcard_matching| controls handling of wildcard names (|name| starts with
54 // "*."). Wildcard handling is not specified by RFC 5280, but certificate
55 // verification allows it, name constraints must check it similarly.
DNSNameMatches(std::string_view name,std::string_view dns_constraint,WildcardMatchType wildcard_matching)56 bool DNSNameMatches(std::string_view name,
57                     std::string_view dns_constraint,
58                     WildcardMatchType wildcard_matching) {
59   // Everything matches the empty DNS name constraint.
60   if (dns_constraint.empty())
61     return true;
62 
63   // Normalize absolute DNS names by removing the trailing dot, if any.
64   if (!name.empty() && *name.rbegin() == '.')
65     name.remove_suffix(1);
66   if (!dns_constraint.empty() && *dns_constraint.rbegin() == '.')
67     dns_constraint.remove_suffix(1);
68 
69   // Wildcard partial-match handling ("*.bar.com" matching name constraint
70   // "foo.bar.com"). This only handles the case where the the dnsname and the
71   // constraint match after removing the leftmost label, otherwise it is handled
72   // by falling through to the check of whether the dnsname is fully within or
73   // fully outside of the constraint.
74   if (wildcard_matching == WILDCARD_PARTIAL_MATCH && name.size() > 2 &&
75       name[0] == '*' && name[1] == '.') {
76     size_t dns_constraint_dot_pos = dns_constraint.find('.');
77     if (dns_constraint_dot_pos != std::string::npos) {
78       std::string_view dns_constraint_domain =
79           dns_constraint.substr(dns_constraint_dot_pos + 1);
80       std::string_view wildcard_domain = name.substr(2);
81       if (bssl::string_util::IsEqualNoCase(wildcard_domain,
82                                           dns_constraint_domain)) {
83         return true;
84       }
85     }
86   }
87 
88   if (!bssl::string_util::EndsWithNoCase(name, dns_constraint)) {
89     return false;
90   }
91 
92   // Exact match.
93   if (name.size() == dns_constraint.size())
94     return true;
95   // If dNSName constraint starts with a dot, only subdomains should match.
96   // (e.g., "foo.bar.com" matches constraint ".bar.com", but "bar.com" doesn't.)
97   // RFC 5280 is ambiguous, but this matches the behavior of other platforms.
98   if (!dns_constraint.empty() && dns_constraint[0] == '.')
99     dns_constraint.remove_prefix(1);
100   // Subtree match.
101   if (name.size() > dns_constraint.size() &&
102       name[name.size() - dns_constraint.size() - 1] == '.') {
103     return true;
104   }
105   // Trailing text matches, but not in a subtree (e.g., "foobar.com" is not a
106   // match for "bar.com").
107   return false;
108 }
109 
110 // Parses a GeneralSubtrees |value| and store the contents in |subtrees|.
111 // The individual values stored into |subtrees| are not validated by this
112 // function.
113 // NOTE: |subtrees| is not pre-initialized by the function(it is expected to be
114 // a default initialized object), and it will be modified regardless of the
115 // return value.
ParseGeneralSubtrees(const der::Input & value,GeneralNames * subtrees,CertErrors * errors)116 [[nodiscard]] bool ParseGeneralSubtrees(const der::Input& value,
117                                         GeneralNames* subtrees,
118                                         CertErrors* errors) {
119   BSSL_CHECK(errors);
120 
121   // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
122   //
123   // GeneralSubtree ::= SEQUENCE {
124   //      base                    GeneralName,
125   //      minimum         [0]     BaseDistance DEFAULT 0,
126   //      maximum         [1]     BaseDistance OPTIONAL }
127   //
128   // BaseDistance ::= INTEGER (0..MAX)
129   der::Parser sequence_parser(value);
130   // The GeneralSubtrees sequence should have at least 1 element.
131   if (!sequence_parser.HasMore())
132     return false;
133   while (sequence_parser.HasMore()) {
134     der::Parser subtree_sequence;
135     if (!sequence_parser.ReadSequence(&subtree_sequence))
136       return false;
137 
138     der::Input raw_general_name;
139     if (!subtree_sequence.ReadRawTLV(&raw_general_name))
140       return false;
141 
142     if (!ParseGeneralName(raw_general_name,
143                           GeneralNames::IP_ADDRESS_AND_NETMASK, subtrees,
144                           errors)) {
145       errors->AddError(kFailedParsingGeneralName);
146       return false;
147     }
148 
149     // RFC 5280 section 4.2.1.10:
150     // Within this profile, the minimum and maximum fields are not used with any
151     // name forms, thus, the minimum MUST be zero, and maximum MUST be absent.
152     // However, if an application encounters a critical name constraints
153     // extension that specifies other values for minimum or maximum for a name
154     // form that appears in a subsequent certificate, the application MUST
155     // either process these fields or reject the certificate.
156 
157     // Note that technically failing here isn't required: rather only need to
158     // fail if a name of this type actually appears in a subsequent cert and
159     // this extension was marked critical. However the minimum and maximum
160     // fields appear uncommon enough that implementing that isn't useful.
161     if (subtree_sequence.HasMore())
162       return false;
163   }
164   return true;
165 }
166 
IsAlphaDigit(char c)167 bool IsAlphaDigit(char c) {
168   return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
169          (c >= 'A' && c <= 'Z');
170 }
171 
172 // Returns true if 'local_part' contains only characters that are valid in a
173 // non-quoted mailbox local-part. Does not check any other part of the syntax
174 // requirements. Does not allow whitespace.
IsAllowedRfc822LocalPart(std::string_view local_part)175 bool IsAllowedRfc822LocalPart(std::string_view local_part) {
176   if (local_part.empty()) {
177     return false;
178   }
179   for (char c : local_part) {
180     if (!(IsAlphaDigit(c) || c == '!' || c == '#' || c == '$' || c == '%' ||
181           c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' ||
182           c == '/' || c == '=' || c == '?' || c == '^' || c == '_' ||
183           c == '`' || c == '{' || c == '|' || c == '}' || c == '~' ||
184           c == '.')) {
185       return false;
186     }
187   }
188   return true;
189 }
190 
191 // Returns true if 'domain' contains only characters that are valid in a
192 // mailbox domain. Does not check any other part of the syntax
193 // requirements. Does not allow IPv6-address-literal as text IPv6 addresses are
194 // non-unique. Does not allow other address literals either as how to handle
195 // them with domain/subdomain matching isn't specified/possible.
IsAllowedRfc822Domain(std::string_view domain)196 bool IsAllowedRfc822Domain(std::string_view domain) {
197   if (domain.empty()) {
198     return false;
199   }
200   for (char c : domain) {
201     if (!(IsAlphaDigit(c) || c == '-' || c == '.')) {
202       return false;
203     }
204   }
205   return true;
206 }
207 
208 enum class Rfc822NameMatchType { kPermitted, kExcluded };
Rfc822NameMatches(std::string_view local_part,std::string_view domain,std::string_view rfc822_constraint,Rfc822NameMatchType match_type,bool case_insensitive_local_part)209 bool Rfc822NameMatches(std::string_view local_part,
210                        std::string_view domain,
211                        std::string_view rfc822_constraint,
212                        Rfc822NameMatchType match_type,
213                        bool case_insensitive_local_part) {
214   // In case of parsing errors, return a value that will cause the name to not
215   // be permitted.
216   const bool error_value =
217       match_type == Rfc822NameMatchType::kPermitted ? false : true;
218 
219   std::vector<std::string_view> constraint_components =
220       bssl::string_util::SplitString(rfc822_constraint, '@');
221   std::string_view constraint_local_part;
222   std::string_view constraint_domain;
223   if (constraint_components.size() == 1) {
224     constraint_domain = constraint_components[0];
225   } else if (constraint_components.size() == 2) {
226     constraint_local_part = constraint_components[0];
227     if (!IsAllowedRfc822LocalPart(constraint_local_part)) {
228       return error_value;
229     }
230     constraint_domain = constraint_components[1];
231   } else {
232     // If we did the full parsing then it is possible for a @ to be in a quoted
233     // local-part of the name, but we don't do that, so just error if @ appears
234     // more than once.
235     return error_value;
236   }
237   if (!IsAllowedRfc822Domain(constraint_domain)) {
238     return error_value;
239   }
240 
241   // RFC 5280 section 4.2.1.10:
242   // To indicate a particular mailbox, the constraint is the complete mail
243   // address.  For example, "root@example.com" indicates the root mailbox on
244   // the host "example.com".
245   if (!constraint_local_part.empty()) {
246     return (case_insensitive_local_part
247                 ? string_util::IsEqualNoCase(local_part, constraint_local_part)
248                 : local_part == constraint_local_part) &&
249            string_util::IsEqualNoCase(domain, constraint_domain);
250   }
251 
252   // RFC 5280 section 4.2.1.10:
253   // To specify any address within a domain, the constraint is specified with a
254   // leading period (as with URIs).  For example, ".example.com" indicates all
255   // the Internet mail addresses in the domain "example.com", but not Internet
256   // mail addresses on the host "example.com".
257   if (!constraint_domain.empty() && constraint_domain[0] == '.') {
258     return string_util::EndsWithNoCase(domain, constraint_domain);
259   }
260 
261   // RFC 5280 section 4.2.1.10:
262   // To indicate all Internet mail addresses on a particular host, the
263   // constraint is specified as the host name.  For example, the constraint
264   // "example.com" is satisfied by any mail address at the host "example.com".
265   return string_util::IsEqualNoCase(domain, constraint_domain);
266 }
267 
268 }  // namespace
269 
270 NameConstraints::~NameConstraints() = default;
271 
272 // static
Create(const der::Input & extension_value,bool is_critical,CertErrors * errors)273 std::unique_ptr<NameConstraints> NameConstraints::Create(
274     const der::Input& extension_value,
275     bool is_critical,
276     CertErrors* errors) {
277   BSSL_CHECK(errors);
278 
279   auto name_constraints = std::make_unique<NameConstraints>();
280   if (!name_constraints->Parse(extension_value, is_critical, errors))
281     return nullptr;
282   return name_constraints;
283 }
284 
Parse(const der::Input & extension_value,bool is_critical,CertErrors * errors)285 bool NameConstraints::Parse(const der::Input& extension_value,
286                             bool is_critical,
287                             CertErrors* errors) {
288   BSSL_CHECK(errors);
289 
290   der::Parser extension_parser(extension_value);
291   der::Parser sequence_parser;
292 
293   // NameConstraints ::= SEQUENCE {
294   //      permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
295   //      excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
296   if (!extension_parser.ReadSequence(&sequence_parser))
297     return false;
298   if (extension_parser.HasMore())
299     return false;
300 
301   std::optional<der::Input> permitted_subtrees_value;
302   if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
303                                        &permitted_subtrees_value)) {
304     return false;
305   }
306   if (permitted_subtrees_value &&
307       !ParseGeneralSubtrees(permitted_subtrees_value.value(),
308                             &permitted_subtrees_, errors)) {
309     return false;
310   }
311   constrained_name_types_ |=
312       permitted_subtrees_.present_name_types &
313       (is_critical ? GENERAL_NAME_ALL_TYPES : kSupportedNameTypes);
314 
315   std::optional<der::Input> excluded_subtrees_value;
316   if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
317                                        &excluded_subtrees_value)) {
318     return false;
319   }
320   if (excluded_subtrees_value &&
321       !ParseGeneralSubtrees(excluded_subtrees_value.value(),
322                             &excluded_subtrees_, errors)) {
323     return false;
324   }
325   constrained_name_types_ |=
326       excluded_subtrees_.present_name_types &
327       (is_critical ? GENERAL_NAME_ALL_TYPES : kSupportedNameTypes);
328 
329   // RFC 5280 section 4.2.1.10:
330   // Conforming CAs MUST NOT issue certificates where name constraints is an
331   // empty sequence. That is, either the permittedSubtrees field or the
332   // excludedSubtrees MUST be present.
333   if (!permitted_subtrees_value && !excluded_subtrees_value)
334     return false;
335 
336   if (sequence_parser.HasMore())
337     return false;
338 
339   return true;
340 }
341 
IsPermittedCert(const der::Input & subject_rdn_sequence,const GeneralNames * subject_alt_names,CertErrors * errors) const342 void NameConstraints::IsPermittedCert(const der::Input& subject_rdn_sequence,
343                                       const GeneralNames* subject_alt_names,
344                                       CertErrors* errors) const {
345   // Checking NameConstraints is O(number_of_names * number_of_constraints).
346   // Impose a hard limit to mitigate the use of name constraints as a DoS
347   // mechanism. This mimics the similar check in BoringSSL x509/v_ncons.c
348   // TODO(bbe): make both name constraint mechanisms subquadratic and remove
349   // this check.
350 
351   const size_t kMaxChecks = 1048576;  // 1 << 20
352 
353   // Names all come from a certificate, which is bound by size_t, so adding them
354   // up can not overflow a size_t.
355   size_t name_count = 0;
356   // Constraints all come from a certificate, which is bound by a size_t, so
357   // adding them up can not overflow a size_t.
358   size_t constraint_count = 0;
359   if (subject_alt_names) {
360     name_count = subject_alt_names->rfc822_names.size() +
361                  subject_alt_names->dns_names.size() +
362                  subject_alt_names->directory_names.size() +
363                  subject_alt_names->ip_addresses.size();
364     constraint_count = excluded_subtrees_.rfc822_names.size() +
365                        permitted_subtrees_.rfc822_names.size() +
366                        excluded_subtrees_.dns_names.size() +
367                        permitted_subtrees_.dns_names.size() +
368                        excluded_subtrees_.directory_names.size() +
369                        permitted_subtrees_.directory_names.size() +
370                        excluded_subtrees_.ip_address_ranges.size() +
371                        permitted_subtrees_.ip_address_ranges.size();
372   } else {
373     constraint_count += excluded_subtrees_.directory_names.size() +
374                         permitted_subtrees_.directory_names.size();
375     name_count = subject_rdn_sequence.Length();
376   }
377   // Upper bound the number of possible checks, checking for overflow.
378   size_t check_count = constraint_count * name_count;
379   if ((constraint_count > 0 && check_count / constraint_count != name_count) ||
380       check_count > kMaxChecks) {
381     errors->AddError(cert_errors::kTooManyNameConstraintChecks);
382     return;
383   }
384 
385   std::vector<std::string> subject_email_addresses_to_check;
386   if (!subject_alt_names &&
387       (constrained_name_types() & GENERAL_NAME_RFC822_NAME)) {
388     if (!FindEmailAddressesInName(subject_rdn_sequence,
389                                   &subject_email_addresses_to_check)) {
390       // Error parsing |subject_rdn_sequence|.
391       errors->AddError(cert_errors::kNotPermittedByNameConstraints);
392       return;
393     }
394   }
395 
396   // Subject Alternative Name handling:
397   //
398   // RFC 5280 section 4.2.1.6:
399   // id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
400   //
401   // SubjectAltName ::= GeneralNames
402   //
403   // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
404 
405   if (subject_alt_names) {
406     // Check unsupported name types:
407     // constrained_name_types() for the unsupported types will only be true if
408     // that type of name was present in a name constraint that was marked
409     // critical.
410     //
411     // RFC 5280 section 4.2.1.10:
412     // If a name constraints extension that is marked as critical
413     // imposes constraints on a particular name form, and an instance of
414     // that name form appears in the subject field or subjectAltName
415     // extension of a subsequent certificate, then the application MUST
416     // either process the constraint or reject the certificate.
417     if (constrained_name_types() & subject_alt_names->present_name_types &
418         ~kSupportedNameTypes) {
419       errors->AddError(cert_errors::kNotPermittedByNameConstraints);
420       return;
421     }
422 
423     // Check supported name types:
424 
425     // Only check rfc822 SANs if any rfc822 constraints are present, since we
426     // might fail if there are email addresses we don't know how to parse but
427     // are technically correct.
428     if (constrained_name_types() & GENERAL_NAME_RFC822_NAME) {
429       for (const auto& rfc822_name : subject_alt_names->rfc822_names) {
430         if (!IsPermittedRfc822Name(
431                 rfc822_name, /*case_insensitive_exclude_localpart=*/false)) {
432           errors->AddError(cert_errors::kNotPermittedByNameConstraints);
433           return;
434         }
435       }
436     }
437 
438     for (const auto& dns_name : subject_alt_names->dns_names) {
439       if (!IsPermittedDNSName(dns_name)) {
440         errors->AddError(cert_errors::kNotPermittedByNameConstraints);
441         return;
442       }
443     }
444 
445     for (const auto& directory_name : subject_alt_names->directory_names) {
446       if (!IsPermittedDirectoryName(directory_name)) {
447         errors->AddError(cert_errors::kNotPermittedByNameConstraints);
448         return;
449       }
450     }
451 
452     for (const auto& ip_address : subject_alt_names->ip_addresses) {
453       if (!IsPermittedIP(ip_address)) {
454         errors->AddError(cert_errors::kNotPermittedByNameConstraints);
455         return;
456       }
457     }
458   }
459 
460   // Subject handling:
461 
462   // RFC 5280 section 4.2.1.10:
463   // Legacy implementations exist where an electronic mail address is embedded
464   // in the subject distinguished name in an attribute of type emailAddress
465   // (Section 4.1.2.6). When constraints are imposed on the rfc822Name name
466   // form, but the certificate does not include a subject alternative name, the
467   // rfc822Name constraint MUST be applied to the attribute of type emailAddress
468   // in the subject distinguished name.
469   for (const auto& rfc822_name : subject_email_addresses_to_check) {
470     // Whether local_part should be matched case-sensitive or not is somewhat
471     // unclear. RFC 2821 says that it should be case-sensitive. RFC 2985 says
472     // that emailAddress attributes in a Name are fully case-insensitive.
473     // Some other verifier implementations always do local-part comparison
474     // case-sensitive, while some always do it case-insensitive. Many but not
475     // all SMTP servers interpret addresses as case-insensitive.
476     //
477     // Give how poorly specified this is, and the conflicting implementations
478     // in the wild, this implementation will do case-insensitive match for
479     // excluded names from the subject to avoid potentially allowing
480     // something that wasn't expected.
481     if (!IsPermittedRfc822Name(rfc822_name,
482                                /*case_insensitive_exclude_localpart=*/true)) {
483       errors->AddError(cert_errors::kNotPermittedByNameConstraints);
484       return;
485     }
486   }
487 
488   // RFC 5280 4.1.2.6:
489   // If subject naming information is present only in the subjectAltName
490   // extension (e.g., a key bound only to an email address or URI), then the
491   // subject name MUST be an empty sequence and the subjectAltName extension
492   // MUST be critical.
493   // This code assumes that criticality condition is checked by the caller, and
494   // therefore only needs to avoid the IsPermittedDirectoryName check against an
495   // empty subject in such a case.
496   if (subject_alt_names && subject_rdn_sequence.Length() == 0)
497     return;
498 
499   if (!IsPermittedDirectoryName(subject_rdn_sequence)) {
500     errors->AddError(cert_errors::kNotPermittedByNameConstraints);
501     return;
502   }
503 }
504 
IsPermittedRfc822Name(std::string_view name,bool case_insensitive_exclude_localpart) const505 bool NameConstraints::IsPermittedRfc822Name(
506     std::string_view name,
507     bool case_insensitive_exclude_localpart) const {
508   // RFC 5280 4.2.1.6.  Subject Alternative Name
509   //
510   // When the subjectAltName extension contains an Internet mail address,
511   // the address MUST be stored in the rfc822Name.  The format of an
512   // rfc822Name is a "Mailbox" as defined in Section 4.1.2 of [RFC2821].
513   // A Mailbox has the form "Local-part@Domain".  Note that a Mailbox has
514   // no phrase (such as a common name) before it, has no comment (text
515   // surrounded in parentheses) after it, and is not surrounded by "<" and
516   // ">".  Rules for encoding Internet mail addresses that include
517   // internationalized domain names are specified in Section 7.5.
518 
519   // Relevant parts from RFC 2821 & RFC 2822
520   //
521   // Mailbox = Local-part "@" Domain
522   // Local-part = Dot-string / Quoted-string
523   //       ; MAY be case-sensitive
524   //
525   // Dot-string = Atom *("." Atom)
526   // Atom = 1*atext
527   // Quoted-string = DQUOTE *qcontent DQUOTE
528   //
529   //
530   // atext           =       ALPHA / DIGIT / ; Any character except controls,
531   //                         "!" / "#" /     ;  SP, and specials.
532   //                         "$" / "%" /     ;  Used for atoms
533   //                         "&" / "'" /
534   //                         "*" / "+" /
535   //                         "-" / "/" /
536   //                         "=" / "?" /
537   //                         "^" / "_" /
538   //                         "`" / "{" /
539   //                         "|" / "}" /
540   //                         "~"
541   //
542   // atom            =       [CFWS] 1*atext [CFWS]
543   //
544   //
545   // qtext           =       NO-WS-CTL /     ; Non white space controls
546   //                         %d33 /          ; The rest of the US-ASCII
547   //                         %d35-91 /       ;  characters not including "\"
548   //                         %d93-126        ;  or the quote character
549   //
550   // quoted-pair     =       ("\" text) / obs-qp
551   // qcontent        =       qtext / quoted-pair
552   //
553   //
554   // Domain = (sub-domain 1*("." sub-domain)) / address-literal
555   // sub-domain = Let-dig [Ldh-str]
556   //
557   // Let-dig = ALPHA / DIGIT
558   // Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
559   //
560   // address-literal = "[" IPv4-address-literal /
561   //                       IPv6-address-literal /
562   //                       General-address-literal "]"
563   //       ; See section 4.1.3
564 
565   // However, no one actually implements all that. Known implementations just
566   // do string comparisons, but that is technically incorrect. (Ex: a
567   // constraint excluding |foo@example.com| should exclude a SAN of
568   // |"foo"@example.com|, while a naive direct comparison will allow it.)
569   //
570   // We don't implement all that either, but do something a bit more fail-safe
571   // by rejecting any addresses that contain characters that are not allowed in
572   // the non-quoted formats.
573 
574   std::vector<std::string_view> name_components =
575       bssl::string_util::SplitString(name, '@');
576   if (name_components.size() != 2) {
577     // If we did the full parsing then it is possible for a @ to be in a quoted
578     // local-part of the name, but we don't do that, so just fail if @ appears
579     // more than once.
580     return false;
581   }
582   if (!IsAllowedRfc822LocalPart(name_components[0]) ||
583       !IsAllowedRfc822Domain(name_components[1])) {
584     return false;
585   }
586 
587   for (const auto& excluded_name : excluded_subtrees_.rfc822_names) {
588     if (Rfc822NameMatches(name_components[0], name_components[1], excluded_name,
589                           Rfc822NameMatchType::kExcluded,
590                           case_insensitive_exclude_localpart)) {
591       return false;
592     }
593   }
594 
595   // If permitted subtrees are not constrained, any name that is not excluded is
596   // allowed.
597   if (!(permitted_subtrees_.present_name_types & GENERAL_NAME_RFC822_NAME)) {
598     return true;
599   }
600 
601   for (const auto& permitted_name : permitted_subtrees_.rfc822_names) {
602     if (Rfc822NameMatches(name_components[0], name_components[1],
603                           permitted_name, Rfc822NameMatchType::kPermitted,
604                           /*case_insenitive_local_part=*/false)) {
605       return true;
606     }
607   }
608 
609   return false;
610 }
611 
IsPermittedDNSName(std::string_view name) const612 bool NameConstraints::IsPermittedDNSName(std::string_view name) const {
613   for (const auto& excluded_name : excluded_subtrees_.dns_names) {
614     // When matching wildcard hosts against excluded subtrees, consider it a
615     // match if the constraint would match any expansion of the wildcard. Eg,
616     // *.bar.com should match a constraint of foo.bar.com.
617     if (DNSNameMatches(name, excluded_name, WILDCARD_PARTIAL_MATCH))
618       return false;
619   }
620 
621   // If permitted subtrees are not constrained, any name that is not excluded is
622   // allowed.
623   if (!(permitted_subtrees_.present_name_types & GENERAL_NAME_DNS_NAME))
624     return true;
625 
626   for (const auto& permitted_name : permitted_subtrees_.dns_names) {
627     // When matching wildcard hosts against permitted subtrees, consider it a
628     // match only if the constraint would match all expansions of the wildcard.
629     // Eg, *.bar.com should match a constraint of bar.com, but not foo.bar.com.
630     if (DNSNameMatches(name, permitted_name, WILDCARD_FULL_MATCH))
631       return true;
632   }
633 
634   return false;
635 }
636 
IsPermittedDirectoryName(const der::Input & name_rdn_sequence) const637 bool NameConstraints::IsPermittedDirectoryName(
638     const der::Input& name_rdn_sequence) const {
639   for (const auto& excluded_name : excluded_subtrees_.directory_names) {
640     if (VerifyNameInSubtree(name_rdn_sequence, excluded_name))
641       return false;
642   }
643 
644   // If permitted subtrees are not constrained, any name that is not excluded is
645   // allowed.
646   if (!(permitted_subtrees_.present_name_types & GENERAL_NAME_DIRECTORY_NAME))
647     return true;
648 
649   for (const auto& permitted_name : permitted_subtrees_.directory_names) {
650     if (VerifyNameInSubtree(name_rdn_sequence, permitted_name))
651       return true;
652   }
653 
654   return false;
655 }
656 
IsPermittedIP(const der::Input & ip) const657 bool NameConstraints::IsPermittedIP(const der::Input& ip) const {
658   for (const auto& excluded_ip : excluded_subtrees_.ip_address_ranges) {
659     if (IPAddressMatchesWithNetmask(ip, excluded_ip.first,
660                                     excluded_ip.second)) {
661       return false;
662     }
663   }
664 
665   // If permitted subtrees are not constrained, any name that is not excluded is
666   // allowed.
667   if (!(permitted_subtrees_.present_name_types & GENERAL_NAME_IP_ADDRESS)) {
668     return true;
669   }
670 
671   for (const auto& permitted_ip : permitted_subtrees_.ip_address_ranges) {
672     if (IPAddressMatchesWithNetmask(ip, permitted_ip.first,
673                                     permitted_ip.second)) {
674       return true;
675     }
676   }
677 
678   return false;
679 }
680 
681 }  // namespace net
682