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 |
25 // Types of character set checking that NormalizeDirectoryString can perform. | 36 // Types of character set checking that NormalizeDirectoryString can perform. |
26 enum CharsetEnforcement { | 37 enum CharsetEnforcement { |
27 NO_ENFORCEMENT, | 38 NO_ENFORCEMENT, |
28 ENFORCE_PRINTABLE_STRING, | 39 ENFORCE_PRINTABLE_STRING, |
29 ENFORCE_ASCII, | 40 ENFORCE_ASCII, |
30 }; | 41 }; |
31 | 42 |
32 // Normalizes |output|, a UTF-8 encoded string, as if it contained | 43 // Normalizes |output|, a UTF-8 encoded string, as if it contained |
33 // only ASCII characters. | 44 // only ASCII characters. |
34 // | 45 // |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 // elements in a_type_and_values can't match the same element in | 393 // elements in a_type_and_values can't match the same element in |
383 // b_type_and_values multiple times. | 394 // b_type_and_values multiple times. |
384 b_type_and_values.erase(b_iter); | 395 b_type_and_values.erase(b_iter); |
385 } | 396 } |
386 | 397 |
387 // Every element in |a_type_and_values| had a matching element in | 398 // Every element in |a_type_and_values| had a matching element in |
388 // |b_type_and_values|. | 399 // |b_type_and_values|. |
389 return true; | 400 return true; |
390 } | 401 } |
391 | 402 |
392 } // namespace | 403 enum NameMatchType { |
| 404 EXACT_MATCH, |
| 405 SUBTREE_MATCH, |
| 406 }; |
393 | 407 |
| 408 // Verify that |a| matches |b|. If |match_type| is EXACT_MATCH, returns true if |
| 409 // they are an exact match as defined by RFC 5280 7.1. If |match_type| is |
| 410 // SUBTREE_MATCH, returns true if |a| is within the subtree defined by |b| as |
| 411 // defined by RFC 5280 7.1. |
| 412 // |
394 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag), | 413 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag), |
395 // defined in RFC 5280 section 4.1.2.4: | 414 // defined in RFC 5280 section 4.1.2.4: |
396 // | 415 // |
397 // Name ::= CHOICE { -- only one possibility for now -- | 416 // Name ::= CHOICE { -- only one possibility for now -- |
398 // rdnSequence RDNSequence } | 417 // rdnSequence RDNSequence } |
399 // | 418 // |
400 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName | 419 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName |
401 // | 420 // |
402 // RelativeDistinguishedName ::= | 421 // RelativeDistinguishedName ::= |
403 // SET SIZE (1..MAX) OF AttributeTypeAndValue | 422 // SET SIZE (1..MAX) OF AttributeTypeAndValue |
404 bool VerifyNameMatch(const der::Input& a, const der::Input& b) { | 423 bool VerifyNameMatchInternal(const der::Input& a, |
| 424 const der::Input& b, |
| 425 NameMatchType match_type) { |
405 // Empty Names are allowed. RFC 5280 section 4.1.2.4 requires "The issuer | 426 // Empty Names are allowed. RFC 5280 section 4.1.2.4 requires "The issuer |
406 // field MUST contain a non-empty distinguished name (DN)", while section | 427 // field MUST contain a non-empty distinguished name (DN)", while section |
407 // 4.1.2.6 allows for the Subject to be empty in certain cases. The caller is | 428 // 4.1.2.6 allows for the Subject to be empty in certain cases. The caller is |
408 // assumed to have verified those conditions. | 429 // assumed to have verified those conditions. |
409 | 430 |
410 // RFC 5280 section 7.1: | 431 // RFC 5280 section 7.1: |
411 // Two distinguished names DN1 and DN2 match if they have the same number of | 432 // Two distinguished names DN1 and DN2 match if they have the same number of |
412 // RDNs, for each RDN in DN1 there is a matching RDN in DN2, and the matching | 433 // RDNs, for each RDN in DN1 there is a matching RDN in DN2, and the matching |
413 // RDNs appear in the same order in both DNs. | 434 // RDNs appear in the same order in both DNs. |
414 | 435 |
415 // First just check if the inputs have the same number of RDNs: | 436 // First just check if the inputs have the same number of RDNs: |
416 der::Parser a_rdn_sequence_counter(a); | 437 der::Parser a_rdn_sequence_counter(a); |
417 der::Parser b_rdn_sequence_counter(b); | 438 der::Parser b_rdn_sequence_counter(b); |
418 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) { | 439 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) { |
419 if (!a_rdn_sequence_counter.SkipTag(der::kSet) || | 440 if (!a_rdn_sequence_counter.SkipTag(der::kSet) || |
420 !b_rdn_sequence_counter.SkipTag(der::kSet)) { | 441 !b_rdn_sequence_counter.SkipTag(der::kSet)) { |
421 return false; | 442 return false; |
422 } | 443 } |
423 } | 444 } |
424 if (a_rdn_sequence_counter.HasMore() || b_rdn_sequence_counter.HasMore()) | 445 // If doing exact match and either of the sequences has more elements than the |
| 446 // other, not a match. If doing a subtree match, the first Name may have more |
| 447 // RDNs than the second. |
| 448 if (b_rdn_sequence_counter.HasMore()) |
| 449 return false; |
| 450 if (match_type == EXACT_MATCH && a_rdn_sequence_counter.HasMore()) |
425 return false; | 451 return false; |
426 | 452 |
427 // Same number of RDNs, now check if they match. | 453 // Same number of RDNs, now check if they match. |
428 der::Parser a_rdn_sequence(a); | 454 der::Parser a_rdn_sequence(a); |
429 der::Parser b_rdn_sequence(b); | 455 der::Parser b_rdn_sequence(b); |
430 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { | 456 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { |
431 der::Parser a_rdn, b_rdn; | 457 der::Parser a_rdn, b_rdn; |
432 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || | 458 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || |
433 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) { | 459 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) { |
434 return false; | 460 return false; |
435 } | 461 } |
436 if (!VerifyRdnMatch(&a_rdn, &b_rdn)) | 462 if (!VerifyRdnMatch(&a_rdn, &b_rdn)) |
437 return false; | 463 return false; |
438 } | 464 } |
439 | 465 |
440 return true; | 466 return true; |
441 } | 467 } |
442 | 468 |
| 469 } // namespace |
| 470 |
| 471 bool VerifyNameMatch(const der::Input& a_rdn_sequence, |
| 472 const der::Input& b_rdn_sequence) { |
| 473 return VerifyNameMatchInternal(a_rdn_sequence, b_rdn_sequence, EXACT_MATCH); |
| 474 } |
| 475 |
| 476 bool VerifyNameInSubtree(const der::Input& name_rdn_sequence, |
| 477 const der::Input& parent_rdn_sequence) { |
| 478 return VerifyNameMatchInternal(name_rdn_sequence, parent_rdn_sequence, |
| 479 SUBTREE_MATCH); |
| 480 } |
| 481 |
| 482 bool NameContainsEmailAddress(const der::Input& name_rdn_sequence, |
| 483 bool* contained_email_address) { |
| 484 der::Parser rdn_sequence_parser(name_rdn_sequence); |
| 485 |
| 486 while (rdn_sequence_parser.HasMore()) { |
| 487 der::Parser rdn_parser; |
| 488 if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser)) |
| 489 return false; |
| 490 |
| 491 std::vector<AttributeTypeAndValue> type_and_values; |
| 492 if (!ReadRdn(&rdn_parser, &type_and_values)) |
| 493 return false; |
| 494 |
| 495 for (const auto& type_and_value : type_and_values) { |
| 496 if (type_and_value.type.Equals(der::Input(kOidEmailAddress))) { |
| 497 *contained_email_address = true; |
| 498 return true; |
| 499 } |
| 500 } |
| 501 } |
| 502 |
| 503 *contained_email_address = false; |
| 504 return true; |
| 505 } |
| 506 |
443 } // namespace net | 507 } // namespace net |
OLD | NEW |