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