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

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: win compile fix Created 5 years, 3 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 {
408 EXACT_MATCH,
409 SUBTREE_MATCH,
410 };
388 411
412 // Verify that |a| matches |b|. If |match_type| is EXACT_MATCH, returns true if
413 // they are an exact match as defined by RFC 5280 7.1. If |match_type| is
414 // SUBTREE_MATCH, returns true if |a| is within the subtree defined by |b| as
415 // defined by RFC 5280 7.1.
416 //
389 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag), 417 // |a| and |b| are ASN.1 RDNSequence values (not including the Sequence tag),
390 // defined in RFC 5280 section 4.1.2.4: 418 // defined in RFC 5280 section 4.1.2.4:
391 // 419 //
392 // Name ::= CHOICE { -- only one possibility for now -- 420 // Name ::= CHOICE { -- only one possibility for now --
393 // rdnSequence RDNSequence } 421 // rdnSequence RDNSequence }
394 // 422 //
395 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 423 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
396 // 424 //
397 // RelativeDistinguishedName ::= 425 // RelativeDistinguishedName ::=
398 // SET SIZE (1..MAX) OF AttributeTypeAndValue 426 // SET SIZE (1..MAX) OF AttributeTypeAndValue
399 bool VerifyNameMatch(const der::Input& a, const der::Input& b) { 427 bool VerifyNameMatchInternal(const der::Input& a,
428 const der::Input& b,
429 NameMatchType match_type) {
400 // Empty Names are allowed. RFC 5280 section 4.1.2.4 requires "The issuer 430 // 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 431 // 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 432 // 4.1.2.6 allows for the Subject to be empty in certain cases. The caller is
403 // assumed to have verified those conditions. 433 // assumed to have verified those conditions.
404 434
405 // RFC 5280 section 7.1: 435 // RFC 5280 section 7.1:
406 // Two distinguished names DN1 and DN2 match if they have the same number of 436 // 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 437 // 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. 438 // RDNs appear in the same order in both DNs.
409 439
410 // First just check if the inputs have the same number of RDNs: 440 // First just check if the inputs have the same number of RDNs:
411 der::Parser a_rdn_sequence_counter(a); 441 der::Parser a_rdn_sequence_counter(a);
412 der::Parser b_rdn_sequence_counter(b); 442 der::Parser b_rdn_sequence_counter(b);
413 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) { 443 while (a_rdn_sequence_counter.HasMore() && b_rdn_sequence_counter.HasMore()) {
414 if (!a_rdn_sequence_counter.SkipTag(der::kSet) || 444 if (!a_rdn_sequence_counter.SkipTag(der::kSet) ||
415 !b_rdn_sequence_counter.SkipTag(der::kSet)) { 445 !b_rdn_sequence_counter.SkipTag(der::kSet)) {
416 return false; 446 return false;
417 } 447 }
418 } 448 }
419 if (a_rdn_sequence_counter.HasMore() || b_rdn_sequence_counter.HasMore()) 449 // If doing exact match and either of the sequences has more elements than the
450 // other, not a match. If doing a subtree match, the first Name may have more
451 // RDNs than the second.
452 if (b_rdn_sequence_counter.HasMore())
453 return false;
454 if (match_type == EXACT_MATCH && a_rdn_sequence_counter.HasMore())
420 return false; 455 return false;
421 456
422 // Same number of RDNs, now check if they match. 457 // Same number of RDNs, now check if they match.
423 der::Parser a_rdn_sequence(a); 458 der::Parser a_rdn_sequence(a);
424 der::Parser b_rdn_sequence(b); 459 der::Parser b_rdn_sequence(b);
425 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { 460 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) {
426 der::Parser a_rdn, b_rdn; 461 der::Parser a_rdn, b_rdn;
427 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || 462 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) ||
428 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) { 463 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) {
429 return false; 464 return false;
430 } 465 }
431 if (!VerifyRdnMatch(&a_rdn, &b_rdn)) 466 if (!VerifyRdnMatch(&a_rdn, &b_rdn))
432 return false; 467 return false;
433 } 468 }
434 469
435 return true; 470 return true;
436 } 471 }
437 472
473 } // namespace
474
475 bool VerifyNameMatch(const der::Input& a_rdn_sequence,
476 const der::Input& b_rdn_sequence) {
477 return VerifyNameMatchInternal(a_rdn_sequence, b_rdn_sequence, EXACT_MATCH);
478 }
479
480 bool VerifyNameInSubtree(const der::Input& name_rdn_sequence,
481 const der::Input& parent_rdn_sequence) {
482 return VerifyNameMatchInternal(name_rdn_sequence, parent_rdn_sequence,
483 SUBTREE_MATCH);
484 }
485
486 bool NameContainsEmailAddress(const der::Input& name_rdn_sequence,
487 bool* contained_email_address) {
488 der::Parser rdn_sequence_parser(name_rdn_sequence);
489
490 while (rdn_sequence_parser.HasMore()) {
491 der::Parser rdn_parser;
492 if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser))
493 return false;
494
495 std::vector<AttributeTypeAndValue> type_and_values;
496 if (!ReadRdn(&rdn_parser, &type_and_values))
497 return false;
498
499 for (const auto& type_and_value : type_and_values) {
500 if (type_and_value.type.Equals(der::Input(kOidEmailAddress))) {
501 *contained_email_address = true;
502 return true;
503 }
504 }
505 }
506
507 *contained_email_address = false;
508 return true;
509 }
510
511 bool GetNormalizedCommonNameFromName(const der::Input& name_rdn_sequence,
512 std::string* normalized_common_name) {
513 der::Parser rdn_sequence_parser(name_rdn_sequence);
514
515 while (rdn_sequence_parser.HasMore()) {
516 der::Parser rdn_parser;
517 if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser))
518 return false;
519
520 std::vector<AttributeTypeAndValue> type_and_values;
521 if (!ReadRdn(&rdn_parser, &type_and_values))
522 return false;
523
524 for (const auto& type_and_value : type_and_values) {
525 if (type_and_value.type.Equals(der::Input(kOidCommonName))) {
526 if (!IsNormalizableDirectoryString(type_and_value.value_tag))
527 return false;
528 return NormalizeValue(type_and_value.value_tag, type_and_value.value,
529 normalized_common_name);
530 }
531 }
532 }
533
534 return false;
535 }
536
438 } // namespace net 537 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698