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

Side by Side Diff: net/base/x509_openssl_util.cc

Issue 6612013: Add X509Certificate::VerifyCertName(string) API. This will be used... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/base/x509_openssl_util.h" 5 #include "net/base/x509_openssl_util.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/string_piece.h" 10 #include "base/string_piece.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
wtc 2011/03/03 19:38:46 Nit: Remove this header.
Mike Belshe 2011/03/03 23:06:14 Done.
12 #include "net/base/x509_cert_types.h" 12 #include "net/base/x509_cert_types.h"
13 13
14 namespace net { 14 namespace net {
15 15
16 namespace x509_openssl_util { 16 namespace x509_openssl_util {
17 17
18 bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name, 18 bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name,
19 int index, 19 int index,
20 std::string* key, 20 std::string* key,
21 std::string* value) { 21 std::string* value) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 return false; 63 return false;
64 64
65 base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data), 65 base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data),
66 x509_time->length); 66 x509_time->length);
67 67
68 CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ? 68 CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ?
69 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; 69 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
70 return ParseCertificateDate(str_date, format, time); 70 return ParseCertificateDate(str_date, format, time);
71 } 71 }
72 72
73 // TODO(joth): Investigate if we can upstream this into the OpenSSL library,
74 // to avoid duplicating this logic across projects.
75 bool VerifyHostname(const std::string& hostname,
76 const std::vector<std::string>& cert_names) {
77 DCHECK(!hostname.empty());
78
79 // Simple host name validation. A valid domain name must only contain
80 // alpha, digits, hyphens, and dots. An IP address may have digits and dots,
81 // and also square braces and colons for IPv6 addresses.
82 std::string reference_name;
83 reference_name.reserve(hostname.length());
84
85 bool found_alpha = false;
86 bool found_ip6_chars = false;
87 bool found_hyphen = false;
88 int dot_count = 0;
89
90 size_t first_dot_index = std::string::npos;
91 for (std::string::const_iterator it = hostname.begin();
92 it != hostname.end(); ++it) {
93 char c = *it;
94 if (IsAsciiAlpha(c)) {
95 found_alpha = true;
96 c = base::ToLowerASCII(c);
97 } else if (c == '.') {
98 ++dot_count;
99 if (first_dot_index == std::string::npos)
100 first_dot_index = reference_name.length();
101 } else if (c == ':') {
102 found_ip6_chars = true;
103 } else if (c == '-') {
104 found_hyphen = true;
105 } else if (!IsAsciiDigit(c)) {
106 LOG(WARNING) << "Invalid char " << c << " in hostname " << hostname;
107 return false;
108 }
109 reference_name.push_back(c);
110 }
111 DCHECK(!reference_name.empty());
112
113 if (found_ip6_chars || !found_alpha) {
114 // For now we just do simple localhost IP address support, primarily as
115 // it's needed by the test server. TODO(joth): Replace this with full IP
116 // address support. See http://crbug.com/62973
117 if (hostname == "127.0.0.1" &&
118 std::find(cert_names.begin(), cert_names.end(), hostname) !=
119 cert_names.end()) {
120 DVLOG(1) << "Allowing localhost IP certificate: " << hostname;
121 return true;
122 }
123 NOTIMPLEMENTED() << hostname; // See comment above.
124 return false;
125 }
126
127 // |wildcard_domain| is the remainder of |host| after the leading host
128 // component is stripped off, but includes the leading dot e.g.
129 // "www.f.com" -> ".f.com".
130 // If there is no meaningful domain part to |host| (e.g. it is an IP address
131 // or contains no dots) then |wildcard_domain| will be empty.
132 // We required at least 3 components (i.e. 2 dots) as a basic protection
133 // against too-broad wild-carding.
134 base::StringPiece wildcard_domain;
135 if (found_alpha && !found_ip6_chars && dot_count >= 2) {
136 DCHECK(first_dot_index != std::string::npos);
137 wildcard_domain = reference_name;
138 wildcard_domain.remove_prefix(first_dot_index);
139 DCHECK(wildcard_domain.starts_with("."));
140 }
141
142 for (std::vector<std::string>::const_iterator it = cert_names.begin();
143 it != cert_names.end(); ++it) {
144 // Catch badly corrupt cert names up front.
145 if (it->empty() || it->find('\0') != std::string::npos) {
146 LOG(WARNING) << "Bad name in cert: " << *it;
147 continue;
148 }
149 const std::string cert_name_string(StringToLowerASCII(*it));
150 base::StringPiece cert_match(cert_name_string);
151
152 // Remove trailing dot, if any.
153 if (cert_match.ends_with("."))
154 cert_match.remove_suffix(1);
155
156 // The hostname must be at least as long as the cert name it is matching,
157 // as we require the wildcard (if present) to match at least one character.
158 if (cert_match.length() > reference_name.length())
159 continue;
160
161 if (cert_match == reference_name)
162 return true;
163
164 // Next see if this cert name starts with a wildcard, so long as the
165 // hostname we're matching against has a valid 'domain' part to match.
166 // Note the "-10" version of draft-saintandre-tls-server-id-check allows
167 // the wildcard to appear anywhere in the leftmost label, rather than
168 // requiring it to be the only character. See also http://crbug.com/60719
169 if (wildcard_domain.empty() || !cert_match.starts_with("*"))
170 continue;
171
172 // Erase the * but not the . from the domain, as we need to include the dot
173 // in the comparison.
174 cert_match.remove_prefix(1);
175
176 // Do character by character comparison on the remainder to see
177 // if we have a wildcard match. This intentionally does no special handling
178 // for any other wildcard characters in |domain|; alternatively it could
179 // detect these and skip those candidate cert names.
180 if (cert_match == wildcard_domain)
181 return true;
182 }
183 DVLOG(1) << "Could not find any match for " << hostname
184 << " (canonicalized as " << reference_name
185 << ") in cert names " << JoinString(cert_names, '|');
186 return false;
187 }
188
189 } // namespace x509_openssl_util 73 } // namespace x509_openssl_util
190 74
191 } // namespace net 75 } // namespace net
OLDNEW
« net/base/x509_certificate_unittest.cc ('K') | « net/base/x509_openssl_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698