Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: net/cert/internal/name_constraints.cc

Issue 1214933009: Class for parsing and evaluating RFC 5280 NameConstraints. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@compare_DN2
Patch Set: win compile fix Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
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 "net/cert/internal/name_constraints.h"
6
7 #include "base/strings/string_util.h"
8 #include "net/cert/internal/verify_name_match.h"
9 #include "net/der/input.h"
10 #include "net/der/parser.h"
11 #include "net/der/tag.h"
12
13 namespace net {
14
15 namespace {
16
17 // The name types of GeneralName that are fully supported in name constraints.
18 //
19 // (The other types will have the minimal checking described by RFC 5280
20 // section 4.2.1.10: If a name constraints extension that is marked as critical
21 // imposes constraints on a particular name form, and an instance of
22 // that name form appears in the subject field or subjectAltName
23 // extension of a subsequent certificate, then the application MUST
24 // either process the constraint or reject the certificate.)
25 const int kSupportedNameTypes = GENERAL_NAME_DNS_NAME |
26 GENERAL_NAME_DIRECTORY_NAME |
27 GENERAL_NAME_IP_ADDRESS;
28
29 enum WildcardMatchType { WILDCARD_PARTIAL_MATCH, WILDCARD_FULL_MATCH };
Ryan Sleevi 2015/09/24 22:06:18 Document
mattm 2015/09/30 04:52:31 Done.
30
31 // Returns true if |name| falls in the subtree defined by |name_space|.
Ryan Sleevi 2015/09/24 22:06:19 From reading this comment alone, I'm confused as t
mattm 2015/09/30 04:52:30 renamed to dns_constraint
32 // RFC 5280 section 4.2.1.10:
33 // DNS name restrictions are expressed as host.example.com. Any DNS
34 // name that can be constructed by simply adding zero or more labels
35 // to the left-hand side of the name satisfies the name constraint. For
36 // example, www.host.example.com would satisfy the constraint but
37 // host1.example.com would not.
38 //
39 // Also handles wildcard names (|name| starts with "*.").
40 // If |wildcard_matching| 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 // Wildcard handling is not specified by RFC 5280, but since Chrome's
44 // certificate verification allows it, name constraints must check it similarly.
45 bool DNSNameMatches(base::StringPiece name,
46 base::StringPiece name_space,
47 WildcardMatchType wildcard_matching) {
48 // Everything matches the empty name space.
49 if (name_space.empty())
50 return true;
51
52 // Normalize absolute DNS names by removing the trailing dot to match Chrome's
53 // certificate verification behavior.
Ryan Sleevi 2015/09/24 22:06:19 Documentation bug: You shouldn't be talking about
mattm 2015/09/30 04:52:31 Done.
54 if (!name.empty() && *name.rbegin() == '.')
55 name.remove_suffix(1);
56 if (!name_space.empty() && *name_space.rbegin() == '.')
57 name_space.remove_suffix(1);
58
59 // Wildcard partial-match handling ("*.bar.com" matching name space
60 // "foo.bar.com").
61 if (wildcard_matching == WILDCARD_PARTIAL_MATCH && name.size() > 2 &&
62 name[0] == '*' && name[1] == '.') {
63 size_t name_space_dot_pos = name_space.find('.');
Ryan Sleevi 2015/09/24 22:06:18 If there is no wildcard match, what's supposed to
mattm 2015/09/30 04:52:30 expanded on the comment.
64 if (name_space_dot_pos != std::string::npos) {
65 base::StringPiece name_space_domain(
66 name_space.begin() + name_space_dot_pos + 1,
67 name_space.size() - name_space_dot_pos - 1);
68 base::StringPiece wildcard_domain(name.begin() + 2, name.size() - 2);
69 if (base::EqualsCaseInsensitiveASCII(wildcard_domain, name_space_domain))
70 return true;
71 }
72 }
73
74 if (!base::EndsWith(name, name_space, base::CompareCase::INSENSITIVE_ASCII))
75 return false;
76 // Exact match.
77 if (name.size() == name_space.size())
78 return true;
79 // Subtree match.
80 if (name.size() > name_space.size() &&
81 name[name.size() - name_space.size() - 1] == '.') {
82 return true;
83 }
84 // Trailing text matches, but not in a subtree (e.g., "foobar.com" is not a
85 // match for "bar.com").
86 return false;
87 }
88
89 // Returns true if |ip| matches the ip/netmask pair |ip_constraint|.
90 // RFC 5280 section 4.2.1.10:
91 // The syntax of iPAddress MUST be as described in Section 4.2.1.6 with
92 // the following additions specifically for name constraints. For IPv4
93 // addresses, the iPAddress field of GeneralName MUST contain eight (8)
94 // octets, encoded in the style of RFC 4632 (CIDR) to represent an
95 // address range [RFC4632]. For IPv6 addresses, the iPAddress field
96 // MUST contain 32 octets similarly encoded. For example, a name
97 // constraint for "class C" subnet 192.0.2.0 is represented as the
98 // octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
99 // 192.0.2.0/24 (mask 255.255.255.0).
100 bool VerifyIPMatchesConstraint(const IPAddressNumber& ip,
101 const std::vector<uint8_t>& ip_constraint) {
102 DCHECK(ip.size() == kIPv4AddressSize || ip.size() == kIPv6AddressSize);
103 DCHECK(ip_constraint.size() == kIPv4AddressSize * 2 ||
104 ip_constraint.size() == kIPv6AddressSize * 2);
105
106 if (ip_constraint.size() != ip.size() * 2)
Ryan Sleevi 2015/09/24 22:06:19 No need for the DCHECK on lines 103-104 then, espe
mattm 2015/09/30 04:52:31 The intent was that this if condition is for not t
107 return false;
108
109 std::vector<uint8_t>::const_iterator prefix_iter = ip_constraint.begin();
110 std::vector<uint8_t>::const_iterator netmask_iter =
111 ip_constraint.begin() + ip_constraint.size() / 2;
112 IPAddressNumber::const_iterator ip_iter = ip.begin();
113 for (; ip_iter != ip.end(); ++ip_iter, ++prefix_iter, ++netmask_iter) {
114 // This assumes that any non-masked bits of the prefix are 0, as required by
115 // RFC 4632 section 3.1.
116 if ((*ip_iter & *netmask_iter) != *prefix_iter)
117 return false;
118 }
Ryan Sleevi 2015/09/24 22:06:18 We have net::IPNumberMatchesPrefix() and net::Mask
mattm 2015/09/30 04:52:31 Is there any guarantee the constraint netmask will
Ryan Sleevi 2015/10/01 23:52:23 Define guarantee ;) RFC 1878 covers the v4 subnet
mattm 2015/10/06 21:55:07 Done.
119 return true;
120 }
121
122 enum ParseGeneralNameUnsupportedTypeBehavior {
123 RECORD_UNSUPPORTED,
124 IGNORE_UNSUPPORTED,
125 };
Ryan Sleevi 2015/09/24 22:06:19 Document
mattm 2015/09/30 04:52:31 Done.
126 enum ParseGeneralNameIPAddressType {
Ryan Sleevi 2015/09/24 22:06:19 newline
mattm 2015/09/30 04:52:30 Done.
127 IP_ADDRESS_ONLY,
128 IP_ADDRESS_AND_NETMASK,
129 };
130
Ryan Sleevi 2015/09/24 22:06:18 Document
mattm 2015/09/30 04:52:30 Done.
131 // Parses a GeneralName value and adds it to |subtrees|.
132 WARN_UNUSED_RESULT bool ParseGeneralName(
133 const der::Input& input,
134 ParseGeneralNameUnsupportedTypeBehavior on_unsupported_types,
Ryan Sleevi 2015/09/24 22:06:18 naming: "on_unsupported_types" doesn't seem like i
mattm 2015/09/30 04:52:30 renamed to "unsupported_type_behavior"
135 ParseGeneralNameIPAddressType ip_address_type,
136 NameConstraints::GeneralNames* subtrees) {
137 der::Parser parser(input);
138 der::Tag tag;
139 der::Input value;
140 if (!parser.ReadTagAndValue(&tag, &value))
141 return false;
142 if ((tag & der::kTagClassMask) != der::kTagContextSpecific)
Ryan Sleevi 2015/09/24 22:06:19 Another place where a helper function might help (
mattm 2015/09/30 04:52:30 Done.
143 return false;
144 int tag_class = tag & ~der::kTagClassMask;
Ryan Sleevi 2015/09/24 22:06:19 BUG: Why are you using a signed-type, when der::Ta
mattm 2015/09/30 04:52:31 fixed.
145 int name_type = 0;
Ryan Sleevi 2015/09/24 22:06:19 Is int the right type, since you're using the enum
mattm 2015/09/30 04:52:31 done (though still with present_name_types as an i
146 // GeneralName ::= CHOICE {
147 switch (tag_class) {
148 // otherName [0] OtherName,
149 case 0 + der::kTagConstructed:
Ryan Sleevi 2015/09/24 22:06:19 ? This is a bit surprising/confusing. COuld you ex
mattm 2015/09/30 04:52:30 Since I was only excluding the kTagClassMask (kTag
150 name_type = GENERAL_NAME_OTHER_NAME;
151 break;
152 // rfc822Name [1] IA5String,
153 case 1:
154 name_type = GENERAL_NAME_RFC822_NAME;
155 break;
156 // dNSName [2] IA5String,
157 case 2: {
158 name_type = GENERAL_NAME_DNS_NAME;
159 const std::string s = value.AsString();
160 if (!base::IsStringASCII(s))
161 return false;
162 subtrees->dns_names.push_back(s);
163 break;
164 }
165 // x400Address [3] ORAddress,
166 case 3 + der::kTagConstructed:
167 name_type = GENERAL_NAME_X400_ADDRESS;
168 break;
169 // directoryName [4] Name,
170 case 4 + der::kTagConstructed:
171 name_type = GENERAL_NAME_DIRECTORY_NAME;
172 subtrees->directory_names.push_back(std::vector<uint8_t>(
173 value.UnsafeData(), value.UnsafeData() + value.Length()));
174 break;
175 // ediPartyName [5] EDIPartyName,
176 case 5 + der::kTagConstructed:
177 name_type = GENERAL_NAME_EDI_PARTY_NAME;
178 break;
179 // uniformResourceIdentifier [6] IA5String,
180 case 6:
181 name_type = GENERAL_NAME_UNIFORM_RESOURCE_IDENTIFIER;
182 break;
183 // iPAddress [7] OCTET STRING,
184 case 7:
185 name_type = GENERAL_NAME_IP_ADDRESS;
186 if ((ip_address_type == IP_ADDRESS_ONLY &&
187 (value.Length() != kIPv4AddressSize &&
188 value.Length() != kIPv6AddressSize)) ||
189 (ip_address_type == IP_ADDRESS_AND_NETMASK &&
190 (value.Length() != kIPv4AddressSize * 2 &&
191 value.Length() != kIPv6AddressSize * 2))) {
192 return false;
193 }
194 subtrees->ip_addresses.push_back(std::vector<uint8_t>(
195 value.UnsafeData(), value.UnsafeData() + value.Length()));
196 break;
197 // registeredID [8] OBJECT IDENTIFIER }
198 case 8:
199 name_type = GENERAL_NAME_REGISTERED_ID;
200 break;
201 default:
202 return false;
203 }
204 DCHECK(name_type);
205 if ((name_type & kSupportedNameTypes) ||
206 on_unsupported_types == RECORD_UNSUPPORTED) {
207 subtrees->present_name_types |= name_type;
208 }
209 return true;
210 }
211
212 // Parses a GeneralSubtrees |value| and store the contents in |subtrees|.
213 // The individual values stored into |subtrees| are not validated by this
214 // function.
215 // NOTE: |subtrees| will be modified regardless of the return.
216 WARN_UNUSED_RESULT bool ParseGeneralSubtrees(
217 const der::Input& value,
218 bool is_critical,
219 NameConstraints::GeneralNames* subtrees) {
220 // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
221 //
222 // GeneralSubtree ::= SEQUENCE {
223 // base GeneralName,
224 // minimum [0] BaseDistance DEFAULT 0,
225 // maximum [1] BaseDistance OPTIONAL }
226 //
227 // BaseDistance ::= INTEGER (0..MAX)
228 der::Parser sequence_parser(value);
229 // The GeneralSubtrees sequence should have at least 1 element.
230 if (!sequence_parser.HasMore())
231 return false;
232 while (sequence_parser.HasMore()) {
233 der::Parser subtree_sequence;
234 if (!sequence_parser.ReadSequence(&subtree_sequence))
235 return false;
236
237 der::Input raw_general_name;
238 if (!subtree_sequence.ReadRawTLV(&raw_general_name))
239 return false;
240
241 if (!ParseGeneralName(raw_general_name,
242 is_critical ? RECORD_UNSUPPORTED : IGNORE_UNSUPPORTED,
243 IP_ADDRESS_AND_NETMASK, subtrees)) {
244 return false;
245 }
246
247 // RFC 5280 section 4.2.1.10:
248 // Within this profile, the minimum and maximum fields are not used with any
249 // name forms, thus, the minimum MUST be zero, and maximum MUST be absent.
250 // However, if an application encounters a critical name constraints
251 // extension that specifies other values for minimum or maximum for a name
252 // form that appears in a subsequent certificate, the application MUST
253 // either process these fields or reject the certificate.
254
255 // Note that technically failing here isn't required: rather only need to
256 // fail if a name of this type actually appears in a subsequent cert and
257 // this extension was marked critical. However the minimum and maximum
258 // fields appear uncommon enough that implementing that isn't useful.
259 if (subtree_sequence.HasMore())
260 return false;
261 }
262 return true;
263 }
264
265 } // namespace
266
267 NameConstraints::GeneralNames::GeneralNames() {}
268
269 NameConstraints::GeneralNames::~GeneralNames() {}
270
271 NameConstraints::~NameConstraints() {}
272
273 // static
274 scoped_ptr<NameConstraints> NameConstraints::CreateFromDer(
275 const der::Input& extension_value,
276 bool is_critical) {
277 scoped_ptr<NameConstraints> name_constraints(new NameConstraints());
278 if (!name_constraints->Parse(extension_value, is_critical))
279 return nullptr;
280 return name_constraints;
281 }
282
283 bool NameConstraints::Parse(const der::Input& extension_value,
284 bool is_critical) {
285 der::Parser extension_parser(extension_value);
286 der::Parser sequence_parser;
287
288 // NameConstraints ::= SEQUENCE {
289 // permittedSubtrees [0] GeneralSubtrees OPTIONAL,
290 // excludedSubtrees [1] GeneralSubtrees OPTIONAL }
291 if (!extension_parser.ReadSequence(&sequence_parser))
292 return false;
293 if (extension_parser.HasMore())
294 return false;
295
296 bool had_permitted_subtrees = false;
297 der::Input permitted_subtrees_value;
298 if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
299 &permitted_subtrees_value,
300 &had_permitted_subtrees)) {
301 return false;
302 }
303 if (had_permitted_subtrees) {
304 if (!ParseGeneralSubtrees(permitted_subtrees_value, is_critical,
Ryan Sleevi 2015/09/24 22:06:19 Why not combine this conditional with the one on 3
mattm 2015/09/30 04:52:31 Done.
305 &permitted_subtrees_)) {
306 return false;
307 }
308 }
309
310 bool had_excluded_subtrees = false;
311 der::Input excluded_subtrees_value;
312 if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
313 &excluded_subtrees_value,
314 &had_excluded_subtrees)) {
315 return false;
316 }
317 if (had_excluded_subtrees) {
318 if (!ParseGeneralSubtrees(excluded_subtrees_value, is_critical,
Ryan Sleevi 2015/09/24 22:06:18 Same here - why not combine with the conditional o
mattm 2015/09/30 04:52:31 Done.
319 &excluded_subtrees_)) {
320 return false;
321 }
322 }
323
324 // RFC 5280 section 4.2.1.10:
325 // Conforming CAs MUST NOT issue certificates where name constraints is an
326 // empty sequence. That is, either the permittedSubtrees field or the
327 // excludedSubtrees MUST be present.
328 if (!had_permitted_subtrees && !had_excluded_subtrees)
329 return false;
330
331 if (sequence_parser.HasMore())
332 return false;
333
334 return true;
335 }
336
337 bool NameConstraints::IsPermittedCert(
338 const der::Input& subject_rdn_sequence,
339 const der::Input& subject_alt_name_extnvalue_tlv,
340 bool is_leaf_cert) const {
341 // Subject Alternative Name handling:
342 //
343 // RFC 5280 section 4.2.1.6:
344 // id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 }
345 //
346 // SubjectAltName ::= GeneralNames
347 //
348 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
349
350 GeneralNames san_names;
351 if (subject_alt_name_extnvalue_tlv.Length()) {
352 der::Parser extnvalue_parser(subject_alt_name_extnvalue_tlv);
353 der::Input subject_alt_name_tlv;
354 if (!extnvalue_parser.ReadTag(der::kOctetString, &subject_alt_name_tlv))
355 return false;
356
357 der::Parser subject_alt_name_parser(subject_alt_name_tlv);
358 der::Parser san_sequence_parser;
359 if (!subject_alt_name_parser.ReadSequence(&san_sequence_parser))
360 return false;
361 // Should not have trailing data after subjectAltName sequence.
362 if (subject_alt_name_parser.HasMore())
363 return false;
364 // The subjectAltName sequence should have at least 1 element.
365 if (!san_sequence_parser.HasMore())
366 return false;
367
368 while (san_sequence_parser.HasMore()) {
369 der::Input raw_general_name;
370 if (!san_sequence_parser.ReadRawTLV(&raw_general_name))
371 return false;
372
373 if (!ParseGeneralName(raw_general_name, RECORD_UNSUPPORTED,
374 IP_ADDRESS_ONLY, &san_names))
375 return false;
376 }
377
378 // Check unsupported name types:
379 // ConstrainedNameTypes for the unsupported types will only be true if that
380 // type of name was present in a name constraint that was marked critical.
381 //
382 // RFC 5280 section 4.2.1.10:
383 // If a name constraints extension that is marked as critical
384 // imposes constraints on a particular name form, and an instance of
385 // that name form appears in the subject field or subjectAltName
386 // extension of a subsequent certificate, then the application MUST
387 // either process the constraint or reject the certificate.
388 if (ConstrainedNameTypes() & san_names.present_name_types &
389 ~kSupportedNameTypes) {
390 return false;
391 }
392
393 // Check supported name types:
394 for (const auto& dns_name : san_names.dns_names) {
395 if (!IsPermittedDNSName(dns_name))
396 return false;
397 }
398
399 for (const auto& directory_name : san_names.directory_names) {
400 if (!IsPermittedDirectoryName(
401 der::Input(directory_name.data(), directory_name.size()))) {
402 return false;
403 }
404 }
405
406 for (const auto& ip_address : san_names.ip_addresses) {
407 if (!IsPermittedIP(ip_address))
408 return false;
409 }
410 }
411
412 // Subject handling:
413
414 // RFC 5280 section 4.2.1.10:
415 // Legacy implementations exist where an electronic mail address is embedded
416 // in the subject distinguished name in an attribute of type emailAddress
417 // (Section 4.1.2.6). When constraints are imposed on the rfc822Name name
418 // form, but the certificate does not include a subject alternative name, the
419 // rfc822Name constraint MUST be applied to the attribute of type emailAddress
420 // in the subject distinguished name.
421 if (!subject_alt_name_extnvalue_tlv.Length() &&
422 (ConstrainedNameTypes() & GENERAL_NAME_RFC822_NAME)) {
423 bool contained_email_address = false;
424 if (!NameContainsEmailAddress(subject_rdn_sequence,
425 &contained_email_address)) {
426 return false;
427 }
428 if (contained_email_address)
429 return false;
430 }
431
432 // RFC 5280 does not specify checking name constraints against subject
433 // CommonName, but since certificate verification allows it, name constraints
434 // must check it similarly.
435 if (is_leaf_cert &&
436 (san_names.dns_names.empty() && san_names.ip_addresses.empty()) &&
437 (ConstrainedNameTypes() &
438 (GENERAL_NAME_DNS_NAME | GENERAL_NAME_IP_ADDRESS))) {
439 // Note that while the commonName is transcoded to UTF-8, no special
440 // handling is done of internationalized domain names. (If an
441 // internationalized hostname is specified in commonName, it must be in
442 // punycode form.)
443 std::string common_name;
444 if (!GetNormalizedCommonNameFromName(subject_rdn_sequence, &common_name))
445 return false;
446 IPAddressNumber ip_number;
447 bool was_ip = ParseIPLiteralToNumber(common_name, &ip_number);
448 // For IP addresses, Chrome only allows IPv4 in commonName (see comment in
449 // X509Certificate::VerifyHostname), otherwise interpret as a dNSName.
Ryan Sleevi 2015/09/24 22:06:18 This seems tightly coupled in the comment; same la
mattm 2015/09/30 04:52:30 Well, I'd say that it is actually coupled, unfortu
450 if (was_ip && ip_number.size() == kIPv4AddressSize) {
451 if (!IsPermittedIP(ip_number))
452 return false;
453 } else {
454 if (!IsPermittedDNSName(common_name))
Ryan Sleevi 2015/09/24 22:06:19 why not combine this with 453 to be an else-if?
mattm 2015/09/30 04:52:31 I kinda liked how it made the IsPermittedDNSName l
455 return false;
456 }
457 }
458
459 // RFC 5280 4.1.2.6:
460 // If subject naming information is present only in the subjectAltName
461 // extension (e.g., a key bound only to an email address or URI), then the
462 // subject name MUST be an empty sequence and the subjectAltName extension
463 // MUST be critical.
464 if (subject_alt_name_extnvalue_tlv.Length() &&
465 subject_rdn_sequence.Length() == 0) {
466 return true;
467 }
468
469 return IsPermittedDirectoryName(subject_rdn_sequence);
470 }
471
472 bool NameConstraints::IsPermittedDNSName(const std::string& name) const {
473 if (permitted_subtrees_.dns_names.empty() &&
Ryan Sleevi 2015/09/24 22:06:19 It doesn't hurt to be extra verbose in the comment
mattm 2015/09/30 04:52:30 Done.
474 excluded_subtrees_.dns_names.empty()) {
475 return true;
476 }
477
478 for (const std::string& excluded_name : excluded_subtrees_.dns_names) {
479 if (DNSNameMatches(name, excluded_name, WILDCARD_PARTIAL_MATCH))
Ryan Sleevi 2015/09/24 22:06:19 Comments explaining nuance? :)
mattm 2015/09/30 04:52:30 Done.
480 return false;
481 }
482 for (const std::string& permitted_name : permitted_subtrees_.dns_names) {
483 if (DNSNameMatches(name, permitted_name, WILDCARD_FULL_MATCH))
Ryan Sleevi 2015/09/24 22:06:19 Ditto
mattm 2015/09/30 04:52:30 Done.
484 return true;
485 }
486
487 return false;
488 }
489
490 bool NameConstraints::IsPermittedDirectoryName(
491 const der::Input& name_rdn_sequence) const {
492 if (permitted_subtrees_.directory_names.empty() &&
493 excluded_subtrees_.directory_names.empty()) {
494 return true;
495 }
496
497 for (const auto& excluded_name : excluded_subtrees_.directory_names) {
498 if (VerifyNameInSubtree(
499 name_rdn_sequence,
500 der::Input(excluded_name.data(), excluded_name.size()))) {
501 return false;
502 }
503 }
504 for (const auto& permitted_name : permitted_subtrees_.directory_names) {
505 if (VerifyNameInSubtree(
506 name_rdn_sequence,
507 der::Input(permitted_name.data(), permitted_name.size()))) {
508 return true;
509 }
510 }
511
512 return false;
513 }
514
515 bool NameConstraints::IsPermittedIP(const IPAddressNumber& ip) const {
516 if (permitted_subtrees_.ip_addresses.empty() &&
517 excluded_subtrees_.ip_addresses.empty()) {
518 return true;
519 }
520
521 for (const auto& excluded_ip : excluded_subtrees_.ip_addresses) {
522 if (VerifyIPMatchesConstraint(ip, excluded_ip))
523 return false;
524 }
525 for (const auto& permitted_ip : permitted_subtrees_.ip_addresses) {
526 if (VerifyIPMatchesConstraint(ip, permitted_ip))
527 return true;
528 }
529
530 return false;
531 }
532
533 int NameConstraints::ConstrainedNameTypes() const {
534 return (permitted_subtrees_.present_name_types |
535 excluded_subtrees_.present_name_types);
536 }
537
538 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698