OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/internal/verify_name_match.h" | 5 #include "net/cert/internal/verify_name_match.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/strings/utf_string_conversion_utils.h" | 12 #include "base/strings/utf_string_conversion_utils.h" |
13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
14 #include "base/sys_byteorder.h" | 14 #include "base/sys_byteorder.h" |
15 #include "base/third_party/icu/icu_utf.h" | 15 #include "base/third_party/icu/icu_utf.h" |
16 #include "base/tuple.h" | 16 #include "base/tuple.h" |
17 #include "net/der/input.h" | 17 #include "net/der/input.h" |
18 #include "net/der/parser.h" | 18 #include "net/der/parser.h" |
19 #include "net/der/tag.h" | 19 #include "net/der/tag.h" |
20 | 20 |
21 namespace net { | 21 namespace net { |
22 | 22 |
23 namespace { | 23 namespace { |
24 | 24 |
25 // RFC 5280 section A.1: | |
26 // | |
27 // pkcs-9 OBJECT IDENTIFIER ::= | |
28 // { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } | |
29 // | |
30 // id-emailAddress AttributeType ::= { pkcs-9 1 } | |
31 // | |
32 // In dotted form: 1.2.840.113549.1.9.1 | |
33 const uint8_t kOidEmailAddress[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, | |
34 0x0D, 0x01, 0x09, 0x01}; | |
35 | |
36 // RFC 5280 section A.1: | |
37 // | |
38 // id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 } | |
39 // | |
40 // id-at-commonName AttributeType ::= { id-at 3 } | |
41 // | |
42 // In dotted form: 2.5.4.3 | |
43 const uint8_t kOidCommonName[] = {0x55, 0x04, 0x03}; | |
44 | |
25 // Types of character set checking that NormalizeDirectoryString can perform. | 45 // Types of character set checking that NormalizeDirectoryString can perform. |
26 enum CharsetEnforcement { | 46 enum CharsetEnforcement { |
27 NO_ENFORCEMENT, | 47 NO_ENFORCEMENT, |
28 ENFORCE_PRINTABLE_STRING, | 48 ENFORCE_PRINTABLE_STRING, |
29 ENFORCE_ASCII, | 49 ENFORCE_ASCII, |
30 }; | 50 }; |
31 | 51 |
32 // Normalizes |output|, a UTF-8 encoded string, as if it contained | 52 // Normalizes |output|, a UTF-8 encoded string, as if it contained |
33 // only ASCII characters. | 53 // only ASCII characters. |
34 // | 54 // |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 } | 397 } |
378 if (!matched) | 398 if (!matched) |
379 return false; | 399 return false; |
380 } | 400 } |
381 | 401 |
382 // Every element in |a_type_and_values| had a matching element in | 402 // Every element in |a_type_and_values| had a matching element in |
383 // |b_type_and_values|. | 403 // |b_type_and_values|. |
384 return true; | 404 return true; |
385 } | 405 } |
386 | 406 |
387 } // namespace | 407 enum NameMatchType { |
388 | 408 EXACT_MATCH, |
409 SUBTREE_MATCH, | |
410 }; | |
eroman
2015/08/26 19:56:44
newline
mattm
2015/08/29 01:37:19
Done.
| |
411 // Verify that |a| matches |b|. If |match_type| is EXACT_MATCH, returns true if | |
412 // they are an exact match as defined by RFC 5280 7.1. If |match_type| is | |
413 // SUBTREE_MATCH, returns true if |a| is within the subtree defined by |b| as | |
414 // defined by RFC 5280 7.1. | |
415 // | |
389 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag), | 416 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag), |
390 // defined in RFC 5280 section 4.1.2.4: | 417 // defined in RFC 5280 section 4.1.2.4: |
391 // | 418 // |
392 // Name ::= CHOICE { -- only one possibility for now -- | 419 // Name ::= CHOICE { -- only one possibility for now -- |
393 // rdnSequence RDNSequence } | 420 // rdnSequence RDNSequence } |
394 // | 421 // |
395 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName | 422 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName |
396 // | 423 // |
397 // RelativeDistinguishedName ::= | 424 // RelativeDistinguishedName ::= |
398 // SET SIZE (1..MAX) OF AttributeTypeAndValue | 425 // SET SIZE (1..MAX) OF AttributeTypeAndValue |
399 bool VerifyNameMatch(const der::Input& a, const der::Input& b) { | 426 bool VerifyNameMatchInternal(const der::Input& a, |
427 const der::Input& b, | |
428 NameMatchType match_type) { | |
400 // Empty Names are allowed. RFC 5280 section 4.1.2.4 requires "The issuer | 429 // Empty Names are allowed. RFC 5280 section 4.1.2.4 requires "The issuer |
401 // field MUST contain a non-empty distinguished name (DN)", while section | 430 // field MUST contain a non-empty distinguished name (DN)", while section |
402 // 4.1.2.6 allows for the Subject to be empty in certain cases. The caller is | 431 // 4.1.2.6 allows for the Subject to be empty in certain cases. The caller is |
403 // assumed to have verified those conditions. | 432 // assumed to have verified those conditions. |
404 | 433 |
405 // RFC 5280 section 7.1: | 434 // RFC 5280 section 7.1: |
406 // Two distinguished names DN1 and DN2 match if they have the same number of | 435 // Two distinguished names DN1 and DN2 match if they have the same number of |
407 // RDNs, for each RDN in DN1 there is a matching RDN in DN2, and the matching | 436 // RDNs, for each RDN in DN1 there is a matching RDN in DN2, and the matching |
408 // RDNs appear in the same order in both DNs. | 437 // RDNs appear in the same order in both DNs. |
409 | 438 |
410 // First just check if the inputs have the same number of RDNs: | 439 // First just check if the inputs have the same number of RDNs: |
411 der::Parser a_rdn_sequence_counter(a); | 440 der::Parser a_rdn_sequence_counter(a); |
412 der::Parser b_rdn_sequence_counter(b); | 441 der::Parser b_rdn_sequence_counter(b); |
413 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) { | 442 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) { |
414 if (!a_rdn_sequence_counter.SkipTag(der::kSet) || | 443 if (!a_rdn_sequence_counter.SkipTag(der::kSet) || |
415 !b_rdn_sequence_counter.SkipTag(der::kSet)) { | 444 !b_rdn_sequence_counter.SkipTag(der::kSet)) { |
416 return false; | 445 return false; |
417 } | 446 } |
418 } | 447 } |
419 if (a_rdn_sequence_counter.HasMore() || b_rdn_sequence_counter.HasMore()) | 448 // If doing exact match and either of the sequences has more elements than the |
449 // other, not a match. If doing a subtree match, the first Name may have more | |
450 // RDNs than the second. | |
451 if (b_rdn_sequence_counter.HasMore()) | |
452 return false; | |
453 if (match_type == EXACT_MATCH && a_rdn_sequence_counter.HasMore()) | |
420 return false; | 454 return false; |
421 | 455 |
422 // Same number of RDNs, now check if they match. | 456 // Same number of RDNs, now check if they match. |
423 der::Parser a_rdn_sequence(a); | 457 der::Parser a_rdn_sequence(a); |
424 der::Parser b_rdn_sequence(b); | 458 der::Parser b_rdn_sequence(b); |
425 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { | 459 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { |
426 der::Parser a_rdn, b_rdn; | 460 der::Parser a_rdn, b_rdn; |
427 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || | 461 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || |
428 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) { | 462 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) { |
429 return false; | 463 return false; |
430 } | 464 } |
431 if (!VerifyRdnMatch(&a_rdn, &b_rdn)) | 465 if (!VerifyRdnMatch(&a_rdn, &b_rdn)) |
432 return false; | 466 return false; |
433 } | 467 } |
434 | 468 |
435 return true; | 469 return true; |
436 } | 470 } |
437 | 471 |
472 } // namespace | |
473 | |
474 bool VerifyNameMatch(const der::Input& a_rdn_sequence, | |
475 const der::Input& b_rdn_sequence) { | |
476 return VerifyNameMatchInternal(a_rdn_sequence, b_rdn_sequence, EXACT_MATCH); | |
477 } | |
478 | |
479 bool VerifyNameInSubtree(const der::Input& name_rdn_sequence, | |
480 const der::Input& parent_rdn_sequence) { | |
481 return VerifyNameMatchInternal(name_rdn_sequence, parent_rdn_sequence, | |
482 SUBTREE_MATCH); | |
483 } | |
484 | |
485 bool NameContainsEmailAddress(const der::Input& name_rdn_sequence) { | |
486 der::Parser rdn_sequence_parser(name_rdn_sequence); | |
487 | |
488 while (rdn_sequence_parser.HasMore()) { | |
489 der::Parser rdn_parser; | |
490 if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser)) | |
491 return false; | |
492 | |
493 std::vector<AttributeTypeAndValue> type_and_values; | |
494 if (!ReadRdn(&rdn_parser, &type_and_values)) | |
495 return false; | |
496 | |
497 for (const auto& type_and_value : type_and_values) { | |
498 if (type_and_value.type.Equals(der::Input(kOidEmailAddress))) | |
499 return true; | |
500 } | |
501 } | |
502 | |
503 return false; | |
504 } | |
505 | |
506 std::string GetNormalizedCommonNameFromName( | |
507 const der::Input& name_rdn_sequence) { | |
508 der::Parser rdn_sequence_parser(name_rdn_sequence); | |
509 | |
510 while (rdn_sequence_parser.HasMore()) { | |
511 der::Parser rdn_parser; | |
512 if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser)) | |
513 return std::string(); | |
eroman
2015/08/26 19:56:44
Why return an empty string rather than return fals
mattm
2015/08/29 01:37:19
It just didn't matter much for this case, but I've
| |
514 | |
515 std::vector<AttributeTypeAndValue> type_and_values; | |
516 if (!ReadRdn(&rdn_parser, &type_and_values)) | |
517 return std::string(); | |
518 | |
519 for (const auto& type_and_value : type_and_values) { | |
520 if (type_and_value.type.Equals(der::Input(kOidCommonName))) { | |
521 if (!IsNormalizableDirectoryString(type_and_value.value_tag)) | |
522 return std::string(); | |
523 std::string normalized; | |
524 bool ok = NormalizeValue(type_and_value.value_tag, type_and_value.value, | |
525 &normalized); | |
526 if (!ok) | |
527 return std::string(); | |
528 return normalized; | |
529 } | |
530 } | |
531 } | |
532 | |
533 return std::string(); | |
534 } | |
535 | |
438 } // namespace net | 536 } // namespace net |
OLD | NEW |