OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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_certificate.h" | 5 #include "net/base/x509_certificate.h" |
6 | 6 |
7 #if defined(OS_MACOSX) | 7 #if defined(OS_MACOSX) |
8 #include <Security/Security.h> | 8 #include <Security/Security.h> |
9 #elif defined(USE_NSS) | 9 #elif defined(USE_NSS) |
10 #include <cert.h> | 10 #include <cert.h> |
11 #endif | 11 #endif |
12 | 12 |
13 #include "base/histogram.h" | 13 #include "base/histogram.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/time.h" | 15 #include "base/string_piece.h" |
| 16 #include "net/base/pem_tokenizer.h" |
16 | 17 |
17 namespace net { | 18 namespace net { |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 // Returns true if this cert fingerprint is the null (all zero) fingerprint. | 22 // Returns true if this cert fingerprint is the null (all zero) fingerprint. |
22 // We use this as a bogus fingerprint value. | 23 // We use this as a bogus fingerprint value. |
23 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) { | 24 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) { |
24 for (size_t i = 0; i < arraysize(fingerprint.data); ++i) { | 25 for (size_t i = 0; i < arraysize(fingerprint.data); ++i) { |
25 if (fingerprint.data[i] != 0) | 26 if (fingerprint.data[i] != 0) |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 | 152 |
152 // Otherwise, allocate and cache a new object. | 153 // Otherwise, allocate and cache a new object. |
153 X509Certificate* cert = new X509Certificate(cert_handle, source, | 154 X509Certificate* cert = new X509Certificate(cert_handle, source, |
154 intermediates); | 155 intermediates); |
155 cache->Insert(cert); | 156 cache->Insert(cert); |
156 return cert; | 157 return cert; |
157 } | 158 } |
158 | 159 |
159 // static | 160 // static |
160 X509Certificate* X509Certificate::CreateFromBytes(const char* data, | 161 X509Certificate* X509Certificate::CreateFromBytes(const char* data, |
161 int length) { | 162 size_t length, |
162 OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length); | 163 int format) { |
163 if (!cert_handle) | 164 OSCertHandles certificates; |
| 165 |
| 166 // Indicates the order to use when trying to decode binary data, which is |
| 167 // based on (speculation) as to what will be most common -> least common |
| 168 // TODO(rsleevi): Calculate metrics as to which formats end up being |
| 169 // encountered and re-arrange this based on actual data. |
| 170 static CertificateFormat formats[] = { FORMAT_DER, FORMAT_PKCS7, |
| 171 FORMAT_LEGACY_NETSCAPE }; |
| 172 |
| 173 // If it wasn't PEM encoded, try each of the binary formats in order of |
| 174 // their probability until one successfully decodes. |
| 175 for (size_t i = 0; certificates.empty() && i < arraysize(formats); |
| 176 ++i) { |
| 177 if (format & formats[i]) |
| 178 certificates = CreateOSCertHandlesFromBytes(data, length, formats[i]); |
| 179 } |
| 180 |
| 181 // No certs were read. Check to see if this is perhaps a PEM-wrapped version. |
| 182 if (certificates.empty()) { |
| 183 base::StringPiece data_string(data, length); |
| 184 std::vector<std::string> pem_headers; |
| 185 |
| 186 // To maintain compatibility with NSS/Firefox, CERTIFICATE is a universally |
| 187 // valid PEM block header. |
| 188 pem_headers.push_back("CERTIFICATE"); |
| 189 if (format & FORMAT_PKCS7) |
| 190 pem_headers.push_back("PKCS7"); |
| 191 |
| 192 PEMTokenizer pem_tok(&data_string, pem_headers); |
| 193 while (pem_tok.GetNext()) { |
| 194 std::string decoded(pem_tok.data()); |
| 195 |
| 196 // Try a single cert decode first. If this succeeds, then the data is |
| 197 // likely a PEM cert sequence and thus all PEM blocks should be parsed |
| 198 // as certificates. If it doesn't parse as a single certificate, then |
| 199 // this is potentially one of the other formats, in which case only the |
| 200 // first PEM block is consulted. |
| 201 OSCertHandle handle = NULL; |
| 202 if (format & FORMAT_PEM) |
| 203 handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size()); |
| 204 if (handle != NULL) { |
| 205 format = FORMAT_PEM; |
| 206 certificates.push_back(handle); |
| 207 } else { |
| 208 // If this is the first block, and other formats are specified, try to |
| 209 // decode using the binary contents from the PEM block |
| 210 if (format & ~FORMAT_PEM) |
| 211 return CreateFromBytes(decoded.c_str(), decoded.size(), format); |
| 212 |
| 213 // When parsing PEM, the first bad block encountered terminates |
| 214 // parsing |
| 215 break; |
| 216 } |
| 217 } |
| 218 } |
| 219 |
| 220 // No certificates parsed. |
| 221 if (certificates.empty()) |
164 return NULL; | 222 return NULL; |
165 | 223 |
166 return CreateFromHandle(cert_handle, | 224 X509Certificate* result = CreateFromHandle(certificates.front(), |
167 SOURCE_LONE_CERT_IMPORT, | 225 SOURCE_LONE_CERT_IMPORT, |
168 OSCertHandles()); | 226 certificates.size() == 1 ? OSCertHandles() : |
| 227 OSCertHandles(++certificates.begin(), certificates.end())); |
| 228 |
| 229 // CreateFromHandle duplicates the handles to the intermediates, but does |
| 230 // not do so for the primary certificate. Ensure that every intermediate is |
| 231 // freed |
| 232 for (OSCertHandles::iterator it = ++certificates.begin(); |
| 233 it != certificates.end(); ++it) { |
| 234 FreeOSCertHandle(*it); |
| 235 } |
| 236 |
| 237 return result; |
169 } | 238 } |
170 | 239 |
171 X509Certificate::X509Certificate(OSCertHandle cert_handle, | 240 X509Certificate::X509Certificate(OSCertHandle cert_handle, |
172 Source source, | 241 Source source, |
173 const OSCertHandles& intermediates) | 242 const OSCertHandles& intermediates) |
174 : cert_handle_(cert_handle), | 243 : cert_handle_(cert_handle), |
175 source_(source) { | 244 source_(source) { |
176 #if defined(OS_MACOSX) || defined(OS_WIN) | |
177 // Copy/retain the intermediate cert handles. | 245 // Copy/retain the intermediate cert handles. |
178 for (size_t i = 0; i < intermediates.size(); ++i) | 246 for (size_t i = 0; i < intermediates.size(); ++i) |
179 intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i])); | 247 intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i])); |
180 #endif | |
181 // Platform-specific initialization. | 248 // Platform-specific initialization. |
182 Initialize(); | 249 Initialize(); |
183 } | 250 } |
184 | 251 |
185 X509Certificate::X509Certificate(const std::string& subject, | 252 X509Certificate::X509Certificate(const std::string& subject, |
186 const std::string& issuer, | 253 const std::string& issuer, |
187 base::Time start_date, | 254 base::Time start_date, |
188 base::Time expiration_date) | 255 base::Time expiration_date) |
189 : subject_(subject), | 256 : subject_(subject), |
190 issuer_(issuer), | 257 issuer_(issuer), |
191 valid_start_(start_date), | 258 valid_start_(start_date), |
192 valid_expiry_(expiration_date), | 259 valid_expiry_(expiration_date), |
193 cert_handle_(NULL), | 260 cert_handle_(NULL), |
194 source_(SOURCE_UNUSED) { | 261 source_(SOURCE_UNUSED) { |
195 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); | 262 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); |
196 } | 263 } |
197 | 264 |
198 X509Certificate::~X509Certificate() { | 265 X509Certificate::~X509Certificate() { |
199 // We might not be in the cache, but it is safe to remove ourselves anyway. | 266 // We might not be in the cache, but it is safe to remove ourselves anyway. |
200 X509Certificate::Cache::GetInstance()->Remove(this); | 267 X509Certificate::Cache::GetInstance()->Remove(this); |
201 if (cert_handle_) | 268 if (cert_handle_) |
202 FreeOSCertHandle(cert_handle_); | 269 FreeOSCertHandle(cert_handle_); |
203 #if defined(OS_MACOSX) || defined(OS_WIN) | |
204 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | 270 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) |
205 FreeOSCertHandle(intermediate_ca_certs_[i]); | 271 FreeOSCertHandle(intermediate_ca_certs_[i]); |
206 #endif | |
207 } | 272 } |
208 | 273 |
209 bool X509Certificate::HasExpired() const { | 274 bool X509Certificate::HasExpired() const { |
210 return base::Time::Now() > valid_expiry(); | 275 return base::Time::Now() > valid_expiry(); |
211 } | 276 } |
212 | 277 |
213 bool X509Certificate::HasIntermediateCertificate(OSCertHandle cert) { | 278 bool X509Certificate::HasIntermediateCertificate(OSCertHandle cert) { |
214 #if defined(OS_MACOSX) || defined(OS_WIN) | |
215 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { | 279 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
216 if (IsSameOSCert(cert, intermediate_ca_certs_[i])) | 280 if (IsSameOSCert(cert, intermediate_ca_certs_[i])) |
217 return true; | 281 return true; |
218 } | 282 } |
219 return false; | 283 return false; |
220 #else | |
221 return true; | |
222 #endif | |
223 } | 284 } |
224 | 285 |
225 bool X509Certificate::HasIntermediateCertificates(const OSCertHandles& certs) { | 286 bool X509Certificate::HasIntermediateCertificates(const OSCertHandles& certs) { |
226 for (size_t i = 0; i < certs.size(); ++i) { | 287 for (size_t i = 0; i < certs.size(); ++i) { |
227 if (!HasIntermediateCertificate(certs[i])) | 288 if (!HasIntermediateCertificate(certs[i])) |
228 return false; | 289 return false; |
229 } | 290 } |
230 return true; | 291 return true; |
231 } | 292 } |
232 | 293 |
233 } // namespace net | 294 } // namespace net |
OLD | NEW |