OLD | NEW |
---|---|
(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 // Controls wildcard handling of DNSNameMatches. | |
30 // If WildcardMatchType is WILDCARD_PARTIAL_MATCH "*.bar.com" is considered to | |
31 // match the constraint "foo.bar.com". If it is WILDCARD_FULL_MATCH, "*.bar.com" | |
32 // will match "bar.com" but not "foo.bar.com". | |
33 enum WildcardMatchType { WILDCARD_PARTIAL_MATCH, WILDCARD_FULL_MATCH }; | |
34 | |
35 // Returns true if |name| falls in the subtree defined by |dns_constraint|. | |
36 // RFC 5280 section 4.2.1.10: | |
37 // DNS name restrictions are expressed as host.example.com. Any DNS | |
38 // name that can be constructed by simply adding zero or more labels | |
39 // to the left-hand side of the name satisfies the name constraint. For | |
40 // example, www.host.example.com would satisfy the constraint but | |
41 // host1.example.com would not. | |
42 // | |
43 // |wildcard_matching| controls handling of wildcard names (|name| starts with | |
44 // "*."). Wildcard handling is not specified by RFC 5280, but certificate | |
45 // verification allows it, name constraints must check it similarly. | |
46 bool DNSNameMatches(base::StringPiece name, | |
47 base::StringPiece dns_constraint, | |
48 WildcardMatchType wildcard_matching) { | |
49 // Everything matches the empty DNS name constraint. | |
50 if (dns_constraint.empty()) | |
51 return true; | |
52 | |
53 // Normalize absolute DNS names by removing the trailing dot, if any. | |
54 if (!name.empty() && *name.rbegin() == '.') | |
55 name.remove_suffix(1); | |
56 if (!dns_constraint.empty() && *dns_constraint.rbegin() == '.') | |
57 dns_constraint.remove_suffix(1); | |
58 | |
59 // Wildcard partial-match handling ("*.bar.com" matching name constraint | |
60 // "foo.bar.com"). This only handles the case where the the dnsname and the | |
61 // constraint match after removing the leftmost label, otherwise it is handled | |
62 // by falling through to the check of whether the dnsname is fully within or | |
63 // fully outside of the constraint. | |
64 if (wildcard_matching == WILDCARD_PARTIAL_MATCH && name.size() > 2 && | |
65 name[0] == '*' && name[1] == '.') { | |
66 size_t dns_constraint_dot_pos = dns_constraint.find('.'); | |
67 if (dns_constraint_dot_pos != std::string::npos) { | |
68 base::StringPiece dns_constraint_domain( | |
69 dns_constraint.begin() + dns_constraint_dot_pos + 1, | |
70 dns_constraint.size() - dns_constraint_dot_pos - 1); | |
71 base::StringPiece wildcard_domain(name.begin() + 2, name.size() - 2); | |
72 if (base::EqualsCaseInsensitiveASCII(wildcard_domain, | |
73 dns_constraint_domain)) { | |
74 return true; | |
75 } | |
76 } | |
77 } | |
78 | |
79 if (!base::EndsWith(name, dns_constraint, | |
80 base::CompareCase::INSENSITIVE_ASCII)) { | |
81 return false; | |
82 } | |
83 // Exact match. | |
84 if (name.size() == dns_constraint.size()) | |
85 return true; | |
86 // Subtree match. | |
87 if (name.size() > dns_constraint.size() && | |
88 name[name.size() - dns_constraint.size() - 1] == '.') { | |
89 return true; | |
90 } | |
91 // Trailing text matches, but not in a subtree (e.g., "foobar.com" is not a | |
92 // match for "bar.com"). | |
93 return false; | |
94 } | |
95 | |
96 // Return true if the bitmask |mask| contains only zeros after the first | |
97 // |prefix_length| bits. | |
98 bool IsSuffixZero(std::vector<uint8_t> mask, unsigned prefix_length) { | |
Ryan Sleevi
2015/10/29 01:50:47
Shouldn't mask be const-ref?
mattm
2015/10/29 04:20:38
Indeed. Done.
| |
99 size_t zero_bits = mask.size() * CHAR_BIT - prefix_length; | |
100 size_t zero_bytes = zero_bits / CHAR_BIT; | |
101 std::vector<uint8_t> zeros(zero_bytes, 0); | |
102 if (memcmp(zeros.data(), mask.data() + mask.size() - zero_bytes, zero_bytes)) | |
103 return false; | |
104 size_t leftover_bits = zero_bits % CHAR_BIT; | |
105 if (leftover_bits) { | |
106 uint8_t b = mask[mask.size() - zero_bytes - 1]; | |
107 for (size_t i = 0; i < leftover_bits; ++i) { | |
108 if (b & (1 << i)) | |
109 return false; | |
110 } | |
111 } | |
112 return true; | |
113 } | |
114 | |
115 // Controls handling of unsupported name types in ParseGeneralName. (Unsupported | |
116 // types are those not in kSupportedNameTypes.) | |
117 // RECORD_UNSUPPORTED causes unsupported types to be recorded in | |
118 // |present_name_types|. | |
119 // IGNORE_UNSUPPORTED causes unsupported types to not be recorded. | |
120 enum ParseGeneralNameUnsupportedTypeBehavior { | |
121 RECORD_UNSUPPORTED, | |
122 IGNORE_UNSUPPORTED, | |
123 }; | |
124 | |
125 // Controls parsing of iPAddress names in ParseGeneralName. | |
126 // IP_ADDRESS_ONLY parses the iPAddress names as a 4 or 16 byte IP address. | |
127 // IP_ADDRESS_AND_NETMASK parses the iPAddress names as 8 or 32 bytes containing | |
128 // an IP address followed by a netmask. | |
129 enum ParseGeneralNameIPAddressType { | |
130 IP_ADDRESS_ONLY, | |
131 IP_ADDRESS_AND_NETMASK, | |
132 }; | |
133 | |
134 // Parses a GeneralName value and adds it to |subtrees|. | |
135 WARN_UNUSED_RESULT bool ParseGeneralName( | |
136 const der::Input& input, | |
137 ParseGeneralNameUnsupportedTypeBehavior unsupported_type_behavior, | |
138 ParseGeneralNameIPAddressType ip_address_type, | |
139 NameConstraints::GeneralNames* subtrees) { | |
140 der::Parser parser(input); | |
141 der::Tag tag; | |
142 der::Input value; | |
143 if (!parser.ReadTagAndValue(&tag, &value)) | |
144 return false; | |
145 if (!der::IsContextSpecific(tag)) | |
146 return false; | |
147 GeneralNameTypes name_type = GENERAL_NAME_NONE; | |
148 // GeneralName ::= CHOICE { | |
149 switch (der::GetTagNumber(tag)) { | |
150 // otherName [0] OtherName, | |
151 case 0: | |
152 if (!der::IsConstructed(tag)) | |
153 return false; | |
154 name_type = GENERAL_NAME_OTHER_NAME; | |
155 break; | |
156 // rfc822Name [1] IA5String, | |
157 case 1: | |
158 if (der::IsConstructed(tag)) | |
159 return false; | |
160 name_type = GENERAL_NAME_RFC822_NAME; | |
161 break; | |
162 // dNSName [2] IA5String, | |
163 case 2: { | |
164 if (der::IsConstructed(tag)) | |
165 return false; | |
166 name_type = GENERAL_NAME_DNS_NAME; | |
167 const std::string s = value.AsString(); | |
168 if (!base::IsStringASCII(s)) | |
169 return false; | |
170 subtrees->dns_names.push_back(s); | |
171 break; | |
172 } | |
173 // x400Address [3] ORAddress, | |
174 case 3: | |
175 if (!der::IsConstructed(tag)) | |
176 return false; | |
177 name_type = GENERAL_NAME_X400_ADDRESS; | |
178 break; | |
179 // directoryName [4] Name, | |
180 case 4: | |
181 if (!der::IsConstructed(tag)) | |
182 return false; | |
183 name_type = GENERAL_NAME_DIRECTORY_NAME; | |
184 subtrees->directory_names.push_back(std::vector<uint8_t>( | |
185 value.UnsafeData(), value.UnsafeData() + value.Length())); | |
186 break; | |
187 // ediPartyName [5] EDIPartyName, | |
188 case 5: | |
189 if (!der::IsConstructed(tag)) | |
190 return false; | |
191 name_type = GENERAL_NAME_EDI_PARTY_NAME; | |
192 break; | |
193 // uniformResourceIdentifier [6] IA5String, | |
194 case 6: | |
195 if (der::IsConstructed(tag)) | |
196 return false; | |
197 name_type = GENERAL_NAME_UNIFORM_RESOURCE_IDENTIFIER; | |
198 break; | |
199 // iPAddress [7] OCTET STRING, | |
200 case 7: | |
201 if (der::IsConstructed(tag)) | |
202 return false; | |
203 name_type = GENERAL_NAME_IP_ADDRESS; | |
204 if (ip_address_type == IP_ADDRESS_ONLY) { | |
205 // RFC 5280 section 4.2.1.6: | |
206 // When the subjectAltName extension contains an iPAddress, the address | |
207 // MUST be stored in the octet string in "network byte order", as | |
208 // specified in [RFC791]. The least significant bit (LSB) of each octet | |
209 // is the LSB of the corresponding byte in the network address. For IP | |
210 // version 4, as specified in [RFC791], the octet string MUST contain | |
211 // exactly four octets. For IP version 6, as specified in [RFC2460], | |
212 // the octet string MUST contain exactly sixteen octets. | |
213 if ((value.Length() != kIPv4AddressSize && | |
214 value.Length() != kIPv6AddressSize)) { | |
215 return false; | |
216 } | |
217 subtrees->ip_addresses.push_back(std::vector<uint8_t>( | |
218 value.UnsafeData(), value.UnsafeData() + value.Length())); | |
219 } else { | |
220 DCHECK_EQ(ip_address_type, IP_ADDRESS_AND_NETMASK); | |
221 // RFC 5280 section 4.2.1.10: | |
222 // The syntax of iPAddress MUST be as described in Section 4.2.1.6 with | |
223 // the following additions specifically for name constraints. For IPv4 | |
224 // addresses, the iPAddress field of GeneralName MUST contain eight (8) | |
225 // octets, encoded in the style of RFC 4632 (CIDR) to represent an | |
226 // address range [RFC4632]. For IPv6 addresses, the iPAddress field | |
227 // MUST contain 32 octets similarly encoded. For example, a name | |
228 // constraint for "class C" subnet 192.0.2.0 is represented as the | |
229 // octets C0 00 02 00 FF FF FF 00, representing the CIDR notation | |
230 // 192.0.2.0/24 (mask 255.255.255.0). | |
231 if (value.Length() != kIPv4AddressSize * 2 && | |
232 value.Length() != kIPv6AddressSize * 2) { | |
233 return false; | |
234 } | |
235 const std::vector<uint8_t> mask(value.UnsafeData() + value.Length() / 2, | |
236 value.UnsafeData() + value.Length()); | |
237 const unsigned mask_prefix_length = MaskPrefixLength(mask); | |
238 if (!IsSuffixZero(mask, mask_prefix_length)) | |
239 return false; | |
240 subtrees->ip_address_ranges.push_back(std::make_pair( | |
241 std::vector<uint8_t>(value.UnsafeData(), | |
242 value.UnsafeData() + value.Length() / 2), | |
243 mask_prefix_length)); | |
244 } | |
245 break; | |
246 // registeredID [8] OBJECT IDENTIFIER } | |
247 case 8: | |
248 if (der::IsConstructed(tag)) | |
249 return false; | |
250 name_type = GENERAL_NAME_REGISTERED_ID; | |
251 break; | |
252 default: | |
253 return false; | |
254 } | |
255 DCHECK_NE(GENERAL_NAME_NONE, name_type); | |
256 if ((name_type & kSupportedNameTypes) || | |
257 unsupported_type_behavior == RECORD_UNSUPPORTED) { | |
258 subtrees->present_name_types |= name_type; | |
259 } | |
260 return true; | |
261 } | |
262 | |
263 // Parses a GeneralSubtrees |value| and store the contents in |subtrees|. | |
264 // The individual values stored into |subtrees| are not validated by this | |
265 // function. | |
266 // NOTE: |subtrees| will be modified regardless of the return. | |
267 WARN_UNUSED_RESULT bool ParseGeneralSubtrees( | |
268 const der::Input& value, | |
269 bool is_critical, | |
270 NameConstraints::GeneralNames* subtrees) { | |
271 // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree | |
272 // | |
273 // GeneralSubtree ::= SEQUENCE { | |
274 // base GeneralName, | |
275 // minimum [0] BaseDistance DEFAULT 0, | |
276 // maximum [1] BaseDistance OPTIONAL } | |
277 // | |
278 // BaseDistance ::= INTEGER (0..MAX) | |
279 der::Parser sequence_parser(value); | |
280 // The GeneralSubtrees sequence should have at least 1 element. | |
281 if (!sequence_parser.HasMore()) | |
282 return false; | |
283 while (sequence_parser.HasMore()) { | |
284 der::Parser subtree_sequence; | |
285 if (!sequence_parser.ReadSequence(&subtree_sequence)) | |
286 return false; | |
287 | |
288 der::Input raw_general_name; | |
289 if (!subtree_sequence.ReadRawTLV(&raw_general_name)) | |
290 return false; | |
291 | |
292 if (!ParseGeneralName(raw_general_name, | |
293 is_critical ? RECORD_UNSUPPORTED : IGNORE_UNSUPPORTED, | |
294 IP_ADDRESS_AND_NETMASK, subtrees)) { | |
295 return false; | |
296 } | |
297 | |
298 // RFC 5280 section 4.2.1.10: | |
299 // Within this profile, the minimum and maximum fields are not used with any | |
300 // name forms, thus, the minimum MUST be zero, and maximum MUST be absent. | |
301 // However, if an application encounters a critical name constraints | |
302 // extension that specifies other values for minimum or maximum for a name | |
303 // form that appears in a subsequent certificate, the application MUST | |
304 // either process these fields or reject the certificate. | |
305 | |
306 // Note that technically failing here isn't required: rather only need to | |
307 // fail if a name of this type actually appears in a subsequent cert and | |
308 // this extension was marked critical. However the minimum and maximum | |
309 // fields appear uncommon enough that implementing that isn't useful. | |
310 if (subtree_sequence.HasMore()) | |
311 return false; | |
312 } | |
313 return true; | |
314 } | |
315 | |
316 } // namespace | |
317 | |
318 NameConstraints::GeneralNames::GeneralNames() {} | |
319 | |
320 NameConstraints::GeneralNames::~GeneralNames() {} | |
321 | |
322 NameConstraints::~NameConstraints() {} | |
323 | |
324 // static | |
325 scoped_ptr<NameConstraints> NameConstraints::CreateFromDer( | |
326 const der::Input& extension_value, | |
327 bool is_critical) { | |
328 scoped_ptr<NameConstraints> name_constraints(new NameConstraints()); | |
329 if (!name_constraints->Parse(extension_value, is_critical)) | |
330 return nullptr; | |
331 return name_constraints; | |
332 } | |
333 | |
334 bool NameConstraints::Parse(const der::Input& extension_value, | |
335 bool is_critical) { | |
336 der::Parser extension_parser(extension_value); | |
337 der::Parser sequence_parser; | |
338 | |
339 // NameConstraints ::= SEQUENCE { | |
340 // permittedSubtrees [0] GeneralSubtrees OPTIONAL, | |
341 // excludedSubtrees [1] GeneralSubtrees OPTIONAL } | |
342 if (!extension_parser.ReadSequence(&sequence_parser)) | |
343 return false; | |
344 if (extension_parser.HasMore()) | |
345 return false; | |
346 | |
347 bool had_permitted_subtrees = false; | |
348 der::Input permitted_subtrees_value; | |
349 if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
350 &permitted_subtrees_value, | |
351 &had_permitted_subtrees)) { | |
352 return false; | |
353 } | |
354 if (had_permitted_subtrees && | |
355 !ParseGeneralSubtrees(permitted_subtrees_value, is_critical, | |
356 &permitted_subtrees_)) { | |
357 return false; | |
358 } | |
359 | |
360 bool had_excluded_subtrees = false; | |
361 der::Input excluded_subtrees_value; | |
362 if (!sequence_parser.ReadOptionalTag(der::ContextSpecificConstructed(1), | |
363 &excluded_subtrees_value, | |
364 &had_excluded_subtrees)) { | |
365 return false; | |
366 } | |
367 if (had_excluded_subtrees && | |
368 !ParseGeneralSubtrees(excluded_subtrees_value, is_critical, | |
369 &excluded_subtrees_)) { | |
370 return false; | |
371 } | |
372 | |
373 // RFC 5280 section 4.2.1.10: | |
374 // Conforming CAs MUST NOT issue certificates where name constraints is an | |
375 // empty sequence. That is, either the permittedSubtrees field or the | |
376 // excludedSubtrees MUST be present. | |
377 if (!had_permitted_subtrees && !had_excluded_subtrees) | |
378 return false; | |
379 | |
380 if (sequence_parser.HasMore()) | |
381 return false; | |
382 | |
383 return true; | |
384 } | |
385 | |
386 bool NameConstraints::IsPermittedCert( | |
387 const der::Input& subject_rdn_sequence, | |
388 const der::Input& subject_alt_name_extnvalue_tlv) const { | |
389 // Subject Alternative Name handling: | |
390 // | |
391 // RFC 5280 section 4.2.1.6: | |
392 // id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } | |
393 // | |
394 // SubjectAltName ::= GeneralNames | |
395 // | |
396 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName | |
397 | |
398 GeneralNames san_names; | |
399 if (subject_alt_name_extnvalue_tlv.Length()) { | |
400 der::Parser extnvalue_parser(subject_alt_name_extnvalue_tlv); | |
401 der::Input subject_alt_name_tlv; | |
402 if (!extnvalue_parser.ReadTag(der::kOctetString, &subject_alt_name_tlv)) | |
403 return false; | |
404 | |
405 der::Parser subject_alt_name_parser(subject_alt_name_tlv); | |
406 der::Parser san_sequence_parser; | |
407 if (!subject_alt_name_parser.ReadSequence(&san_sequence_parser)) | |
408 return false; | |
409 // Should not have trailing data after subjectAltName sequence. | |
410 if (subject_alt_name_parser.HasMore()) | |
411 return false; | |
412 // The subjectAltName sequence should have at least 1 element. | |
413 if (!san_sequence_parser.HasMore()) | |
414 return false; | |
415 | |
416 while (san_sequence_parser.HasMore()) { | |
417 der::Input raw_general_name; | |
418 if (!san_sequence_parser.ReadRawTLV(&raw_general_name)) | |
419 return false; | |
420 | |
421 if (!ParseGeneralName(raw_general_name, RECORD_UNSUPPORTED, | |
422 IP_ADDRESS_ONLY, &san_names)) | |
423 return false; | |
424 } | |
425 | |
426 // Check unsupported name types: | |
427 // ConstrainedNameTypes for the unsupported types will only be true if that | |
428 // type of name was present in a name constraint that was marked critical. | |
429 // | |
430 // RFC 5280 section 4.2.1.10: | |
431 // If a name constraints extension that is marked as critical | |
432 // imposes constraints on a particular name form, and an instance of | |
433 // that name form appears in the subject field or subjectAltName | |
434 // extension of a subsequent certificate, then the application MUST | |
435 // either process the constraint or reject the certificate. | |
436 if (ConstrainedNameTypes() & san_names.present_name_types & | |
437 ~kSupportedNameTypes) { | |
438 return false; | |
439 } | |
440 | |
441 // Check supported name types: | |
442 for (const auto& dns_name : san_names.dns_names) { | |
443 if (!IsPermittedDNSName(dns_name)) | |
444 return false; | |
445 } | |
446 | |
447 for (const auto& directory_name : san_names.directory_names) { | |
448 if (!IsPermittedDirectoryName( | |
449 der::Input(directory_name.data(), directory_name.size()))) { | |
450 return false; | |
451 } | |
452 } | |
453 | |
454 for (const auto& ip_address : san_names.ip_addresses) { | |
455 if (!IsPermittedIP(ip_address)) | |
456 return false; | |
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 if (!subject_alt_name_extnvalue_tlv.Length() && | |
470 (ConstrainedNameTypes() & GENERAL_NAME_RFC822_NAME)) { | |
471 bool contained_email_address = false; | |
472 if (!NameContainsEmailAddress(subject_rdn_sequence, | |
473 &contained_email_address)) { | |
474 return false; | |
475 } | |
476 if (contained_email_address) | |
477 return false; | |
478 } | |
479 | |
480 // RFC 5280 4.1.2.6: | |
481 // If subject naming information is present only in the subjectAltName | |
482 // extension (e.g., a key bound only to an email address or URI), then the | |
483 // subject name MUST be an empty sequence and the subjectAltName extension | |
484 // MUST be critical. | |
Ryan Sleevi
2015/10/29 01:50:47
This code doesn't check the criticality; is the ex
mattm
2015/10/29 04:20:38
That was my thought (for example, if there are no
mattm
2015/10/29 04:38:25
Also I imagine this code will end up changed to sp
| |
485 if (subject_alt_name_extnvalue_tlv.Length() && | |
486 subject_rdn_sequence.Length() == 0) { | |
487 return true; | |
488 } | |
489 | |
490 return IsPermittedDirectoryName(subject_rdn_sequence); | |
491 } | |
492 | |
493 bool NameConstraints::IsPermittedDNSName(const std::string& name) const { | |
494 // If there are no name constraints for DNS names, all names are accepted. | |
495 if (!(ConstrainedNameTypes() & GENERAL_NAME_DNS_NAME)) | |
496 return true; | |
497 | |
498 for (const std::string& excluded_name : excluded_subtrees_.dns_names) { | |
499 // When matching wildcard hosts against excluded subtrees, consider it a | |
500 // match if the constraint would match any expansion of the wildcard. Eg, | |
501 // CN=*.bar.com should match a constraint of foo.bar.com. | |
Ryan Sleevi
2015/10/29 01:50:47
remove the CN= ?
mattm
2015/10/29 04:20:38
Done.
| |
502 if (DNSNameMatches(name, excluded_name, WILDCARD_PARTIAL_MATCH)) | |
503 return false; | |
504 } | |
505 for (const std::string& permitted_name : permitted_subtrees_.dns_names) { | |
506 // When matching wildcard hosts against permitted subtrees, consider it a | |
507 // match only if the constraint would match all expansions of the wildcard. | |
508 // Eg, CN=*.bar.com should match a constraint of bar.com, but not | |
Ryan Sleevi
2015/10/29 01:50:47
remove CN= ?
mattm
2015/10/29 04:20:38
Done.
| |
509 // foo.bar.com. | |
510 if (DNSNameMatches(name, permitted_name, WILDCARD_FULL_MATCH)) | |
511 return true; | |
512 } | |
513 | |
514 return false; | |
515 } | |
516 | |
517 bool NameConstraints::IsPermittedDirectoryName( | |
518 const der::Input& name_rdn_sequence) const { | |
519 // If there are no name constraints for directory names, all names are | |
520 // accepted. | |
521 if (!(ConstrainedNameTypes() & GENERAL_NAME_DIRECTORY_NAME)) | |
522 return true; | |
523 | |
524 for (const auto& excluded_name : excluded_subtrees_.directory_names) { | |
525 if (VerifyNameInSubtree( | |
526 name_rdn_sequence, | |
527 der::Input(excluded_name.data(), excluded_name.size()))) { | |
528 return false; | |
529 } | |
530 } | |
531 for (const auto& permitted_name : permitted_subtrees_.directory_names) { | |
532 if (VerifyNameInSubtree( | |
533 name_rdn_sequence, | |
534 der::Input(permitted_name.data(), permitted_name.size()))) { | |
535 return true; | |
536 } | |
537 } | |
538 | |
539 return false; | |
540 } | |
541 | |
542 bool NameConstraints::IsPermittedIP(const IPAddressNumber& ip) const { | |
543 // If there are no name constraints for IP Address names, all names are | |
544 // accepted. | |
545 if (!(ConstrainedNameTypes() & GENERAL_NAME_IP_ADDRESS)) | |
546 return true; | |
547 | |
548 for (const auto& excluded_ip : excluded_subtrees_.ip_address_ranges) { | |
549 if (IPNumberMatchesPrefix(ip, excluded_ip.first, excluded_ip.second)) | |
550 return false; | |
551 } | |
552 for (const auto& permitted_ip : permitted_subtrees_.ip_address_ranges) { | |
553 if (IPNumberMatchesPrefix(ip, permitted_ip.first, permitted_ip.second)) | |
554 return true; | |
555 } | |
556 | |
557 return false; | |
558 } | |
559 | |
560 int NameConstraints::ConstrainedNameTypes() const { | |
561 return (permitted_subtrees_.present_name_types | | |
562 excluded_subtrees_.present_name_types); | |
563 } | |
564 | |
565 } // namespace net | |
OLD | NEW |