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

Side by Side Diff: net/cert/internal/verify_name_match.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: use test_helpers.h Created 5 years, 4 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698