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 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 | |
OLD | NEW |