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

Side by Side Diff: net/cert/x509_certificate.cc

Issue 14741019: Disallow wildcards from matching top-level registry controlled domains during cert validation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | net/cert/x509_certificate_nss.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/x509_certificate.h" 5 #include "net/cert/x509_certificate.h"
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <map> 10 #include <map>
11 #include <string> 11 #include <string>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/base64.h" 14 #include "base/base64.h"
15 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/memory/singleton.h" 17 #include "base/memory/singleton.h"
18 #include "base/metrics/histogram.h" 18 #include "base/metrics/histogram.h"
19 #include "base/pickle.h" 19 #include "base/pickle.h"
20 #include "base/sha1.h" 20 #include "base/sha1.h"
21 #include "base/string_util.h" 21 #include "base/string_util.h"
22 #include "base/strings/string_piece.h" 22 #include "base/strings/string_piece.h"
23 #include "base/synchronization/lock.h" 23 #include "base/synchronization/lock.h"
24 #include "base/time.h" 24 #include "base/time.h"
25 #include "googleurl/src/url_canon_ip.h" 25 #include "googleurl/src/url_canon_ip.h"
26 #include "net/base/net_util.h" 26 #include "net/base/net_util.h"
27 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
27 #include "net/cert/pem_tokenizer.h" 28 #include "net/cert/pem_tokenizer.h"
28 29
29 namespace net { 30 namespace net {
30 31
31 namespace { 32 namespace {
32 33
33 // Indicates the order to use when trying to decode binary data, which is 34 // Indicates the order to use when trying to decode binary data, which is
34 // based on (speculation) as to what will be most common -> least common 35 // based on (speculation) as to what will be most common -> least common
35 const X509Certificate::Format kFormatDecodePriority[] = { 36 const X509Certificate::Format kFormatDecodePriority[] = {
36 X509Certificate::FORMAT_SINGLE_CERTIFICATE, 37 X509Certificate::FORMAT_SINGLE_CERTIFICATE,
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 // |reference_domain| is the remainder of |host| after the leading host 546 // |reference_domain| is the remainder of |host| after the leading host
546 // component is stripped off, but includes the leading dot e.g. 547 // component is stripped off, but includes the leading dot e.g.
547 // "www.f.com" -> ".f.com". 548 // "www.f.com" -> ".f.com".
548 // If there is no meaningful domain part to |host| (e.g. it contains no dots) 549 // If there is no meaningful domain part to |host| (e.g. it contains no dots)
549 // then |reference_domain| will be empty. 550 // then |reference_domain| will be empty.
550 base::StringPiece reference_host, reference_domain; 551 base::StringPiece reference_host, reference_domain;
551 SplitOnChar(reference_name, '.', &reference_host, &reference_domain); 552 SplitOnChar(reference_name, '.', &reference_host, &reference_domain);
552 bool allow_wildcards = false; 553 bool allow_wildcards = false;
553 if (!reference_domain.empty()) { 554 if (!reference_domain.empty()) {
554 DCHECK(reference_domain.starts_with(".")); 555 DCHECK(reference_domain.starts_with("."));
555 // We required at least 3 components (i.e. 2 dots) as a basic protection 556
556 // against too-broad wild-carding. 557 // Do not allow wildcards for public/ICANN registry controlled domains -
557 // Also we don't attempt wildcard matching on a purely numerical hostname. 558 // that is, prevent *.com or *.co.uk as valid presented names, but do not
wtc 2013/05/16 18:03:08 Nit: but do not => but not ?
558 allow_wildcards = reference_domain.rfind('.') != 0 && 559 // *.appspot.com (a private registry controlled domain).
560 // In addition, unknown top-level domains (such as 'intranet' domains or
561 // new TLDs/gTLDs not yet added to the registry controlled domain dataset)
562 // are also implicitly prevented.
563 // Because |reference_domain| must contain at least one name component that
564 // is not registry controlled, this ensures that all reference domains
565 // contain at least three domain components when using wildcards.
566 size_t registry_length =
567 registry_controlled_domains::GetRegistryLength(
568 reference_name,
569 registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
570 registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
571
572 // Because |reference_name| was already canonicalized, the following
573 // should never happen.
574 CHECK_NE(std::string::npos, registry_length);
575
576 // Account for the leading dot in |reference_domain|.
577 bool is_registry_controlled =
578 registry_length != 0 &&
579 registry_length == (reference_domain.size() - 1);
580
581 // Additionally, do not attempt wildcard matching for purely numeric
582 // hostnames.
583 allow_wildcards =
584 !is_registry_controlled &&
559 reference_name.find_first_not_of("0123456789.") != std::string::npos; 585 reference_name.find_first_not_of("0123456789.") != std::string::npos;
560 } 586 }
561 587
562 // Now step through the DNS names doing wild card comparison (if necessary) 588 // Now step through the DNS names doing wild card comparison (if necessary)
563 // on each against the reference name. If subjectAltName is empty, then 589 // on each against the reference name. If subjectAltName is empty, then
564 // fallback to use the common name instead. 590 // fallback to use the common name instead.
565 std::vector<std::string> common_name_as_vector; 591 std::vector<std::string> common_name_as_vector;
566 const std::vector<std::string>* presented_names = &cert_san_dns_names; 592 const std::vector<std::string>* presented_names = &cert_san_dns_names;
567 if (common_name_fallback) { 593 if (common_name_fallback) {
568 // Note: there's a small possibility cert_common_name is an international 594 // Note: there's a small possibility cert_common_name is an international
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 !(pattern_begin.empty() && pattern_end.empty())) 641 !(pattern_begin.empty() && pattern_end.empty()))
616 continue; 642 continue;
617 643
618 if (reference_host.starts_with(pattern_begin) && 644 if (reference_host.starts_with(pattern_begin) &&
619 reference_host.ends_with(pattern_end)) 645 reference_host.ends_with(pattern_end))
620 return true; 646 return true;
621 } 647 }
622 return false; 648 return false;
623 } 649 }
624 650
625 #if !defined(USE_NSS)
626 bool X509Certificate::VerifyNameMatch(const std::string& hostname) const { 651 bool X509Certificate::VerifyNameMatch(const std::string& hostname) const {
627 std::vector<std::string> dns_names, ip_addrs; 652 std::vector<std::string> dns_names, ip_addrs;
628 GetSubjectAltName(&dns_names, &ip_addrs); 653 GetSubjectAltName(&dns_names, &ip_addrs);
629 return VerifyHostname(hostname, subject_.common_name, dns_names, ip_addrs); 654 return VerifyHostname(hostname, subject_.common_name, dns_names, ip_addrs);
630 } 655 }
631 #endif
632 656
633 // static 657 // static
634 bool X509Certificate::GetPEMEncoded(OSCertHandle cert_handle, 658 bool X509Certificate::GetPEMEncoded(OSCertHandle cert_handle,
635 std::string* pem_encoded) { 659 std::string* pem_encoded) {
636 std::string der_encoded; 660 std::string der_encoded;
637 if (!GetDEREncoded(cert_handle, &der_encoded) || der_encoded.empty()) 661 if (!GetDEREncoded(cert_handle, &der_encoded) || der_encoded.empty())
638 return false; 662 return false;
639 std::string b64_encoded; 663 std::string b64_encoded;
640 if (!base::Base64Encode(der_encoded, &b64_encoded) || b64_encoded.empty()) 664 if (!base::Base64Encode(der_encoded, &b64_encoded) || b64_encoded.empty())
641 return false; 665 return false;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 RemoveFromCache(cert_handle_); 716 RemoveFromCache(cert_handle_);
693 FreeOSCertHandle(cert_handle_); 717 FreeOSCertHandle(cert_handle_);
694 } 718 }
695 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 719 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
696 RemoveFromCache(intermediate_ca_certs_[i]); 720 RemoveFromCache(intermediate_ca_certs_[i]);
697 FreeOSCertHandle(intermediate_ca_certs_[i]); 721 FreeOSCertHandle(intermediate_ca_certs_[i]);
698 } 722 }
699 } 723 }
700 724
701 } // namespace net 725 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/cert/x509_certificate_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698