OLD | NEW |
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 "chromeos/network/onc/onc_certificate_importer.h" | 5 #include "chromeos/network/onc/onc_certificate_importer.h" |
6 | 6 |
7 #include <cert.h> | 7 #include <cert.h> |
8 #include <keyhi.h> | 8 #include <keyhi.h> |
9 #include <pk11pub.h> | 9 #include <pk11pub.h> |
10 | 10 |
11 #include "base/base64.h" | 11 #include "base/base64.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "chromeos/network/network_event_log.h" | 14 #include "chromeos/network/network_event_log.h" |
15 #include "chromeos/network/onc/onc_constants.h" | 15 #include "chromeos/network/onc/onc_constants.h" |
| 16 #include "chromeos/network/onc/onc_utils.h" |
16 #include "net/base/crypto_module.h" | 17 #include "net/base/crypto_module.h" |
17 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
18 #include "net/cert/nss_cert_database.h" | 19 #include "net/cert/nss_cert_database.h" |
19 #include "net/cert/pem_tokenizer.h" | |
20 #include "net/cert/x509_certificate.h" | 20 #include "net/cert/x509_certificate.h" |
21 | 21 |
22 #define ONC_LOG_WARNING(message) \ | 22 #define ONC_LOG_WARNING(message) \ |
23 NET_LOG_DEBUG("ONC Certificate Import Warning", message) | 23 NET_LOG_DEBUG("ONC Certificate Import Warning", message) |
24 #define ONC_LOG_ERROR(message) \ | 24 #define ONC_LOG_ERROR(message) \ |
25 NET_LOG_ERROR("ONC Certificate Import Error", message) | 25 NET_LOG_ERROR("ONC Certificate Import Error", message) |
26 | 26 |
27 namespace { | |
28 | |
29 // The PEM block header used for DER certificates | |
30 const char kCertificateHeader[] = "CERTIFICATE"; | |
31 // This is an older PEM marker for DER certificates. | |
32 const char kX509CertificateHeader[] = "X509 CERTIFICATE"; | |
33 | |
34 } // namespace | |
35 | |
36 namespace chromeos { | 27 namespace chromeos { |
37 namespace onc { | 28 namespace onc { |
38 | 29 |
39 CertificateImporter::CertificateImporter(bool allow_trust_imports) | 30 CertificateImporter::CertificateImporter(bool allow_trust_imports) |
40 : allow_trust_imports_(allow_trust_imports) { | 31 : allow_trust_imports_(allow_trust_imports) { |
41 } | 32 } |
42 | 33 |
43 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( | 34 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( |
44 const base::ListValue& certificates, | 35 const base::ListValue& certificates, |
45 net::CertificateList* onc_trusted_certificates) { | 36 net::CertificateList* onc_trusted_certificates) { |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 std::string x509_data; | 190 std::string x509_data; |
200 if (!certificate.GetStringWithoutPathExpansion(certificate::kX509, | 191 if (!certificate.GetStringWithoutPathExpansion(certificate::kX509, |
201 &x509_data) || | 192 &x509_data) || |
202 x509_data.empty()) { | 193 x509_data.empty()) { |
203 ONC_LOG_ERROR( | 194 ONC_LOG_ERROR( |
204 "Certificate missing appropriate certificate data for type: " + | 195 "Certificate missing appropriate certificate data for type: " + |
205 cert_type); | 196 cert_type); |
206 return false; | 197 return false; |
207 } | 198 } |
208 | 199 |
209 // Parse PEM certificate, and get the decoded data for use in creating | |
210 // certificate below. | |
211 std::vector<std::string> pem_headers; | |
212 pem_headers.push_back(kCertificateHeader); | |
213 pem_headers.push_back(kX509CertificateHeader); | |
214 | |
215 net::PEMTokenizer pem_tokenizer(x509_data, pem_headers); | |
216 std::string decoded_x509; | |
217 if (!pem_tokenizer.GetNext()) { | |
218 // If we failed to read the data as a PEM file, then let's just try plain | |
219 // base64 decode: some versions of Spigots didn't apply the PEM marker | |
220 // strings. For this to work, there has to be no white space, and it has to | |
221 // only contain the base64-encoded data. | |
222 if (!base::Base64Decode(x509_data, &decoded_x509)) { | |
223 ONC_LOG_ERROR("Unable to base64 decode X509 data: " + x509_data); | |
224 return false; | |
225 } | |
226 } else { | |
227 decoded_x509 = pem_tokenizer.data(); | |
228 } | |
229 | |
230 scoped_refptr<net::X509Certificate> x509_cert = | 200 scoped_refptr<net::X509Certificate> x509_cert = |
231 net::X509Certificate::CreateFromBytesWithNickname( | 201 DecodePEMCertificate(x509_data, guid); |
232 decoded_x509.data(), | |
233 decoded_x509.size(), | |
234 guid.c_str()); | |
235 if (!x509_cert.get()) { | 202 if (!x509_cert.get()) { |
236 ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); | 203 ONC_LOG_ERROR("Unable to create certificate from PEM encoding, type: " + |
| 204 cert_type); |
237 return false; | 205 return false; |
238 } | 206 } |
239 | 207 |
240 // Due to a mismatch regarding cert identity between NSS (cert identity is | 208 // Due to a mismatch regarding cert identity between NSS (cert identity is |
241 // determined by the raw bytes) and ONC (cert identity is determined by | 209 // determined by the raw bytes) and ONC (cert identity is determined by |
242 // GUIDs), we have to special-case a number of situations here: | 210 // GUIDs), we have to special-case a number of situations here: |
243 // | 211 // |
244 // a) The cert bits we're trying to insert are already present in the NSS cert | 212 // a) The cert bits we're trying to insert are already present in the NSS cert |
245 // store. This is indicated by the isperm bit in CERTCertificateStr. Since | 213 // store. This is indicated by the isperm bit in CERTCertificateStr. Since |
246 // we might have to update the nick name, we just delete the existing cert | 214 // we might have to update the nick name, we just delete the existing cert |
(...skipping 10 matching lines...) Expand all Loading... |
257 // keep our own database for mapping GUIDs to certs in order to enable several | 225 // keep our own database for mapping GUIDs to certs in order to enable several |
258 // GUIDs to map to the same cert. See http://crosbug.com/26073. | 226 // GUIDs to map to the same cert. See http://crosbug.com/26073. |
259 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance(); | 227 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance(); |
260 if (x509_cert->os_cert_handle()->isperm) { | 228 if (x509_cert->os_cert_handle()->isperm) { |
261 if (!cert_database->DeleteCertAndKey(x509_cert.get())) { | 229 if (!cert_database->DeleteCertAndKey(x509_cert.get())) { |
262 ONC_LOG_ERROR("Unable to delete X509 certificate."); | 230 ONC_LOG_ERROR("Unable to delete X509 certificate."); |
263 return false; | 231 return false; |
264 } | 232 } |
265 | 233 |
266 // Reload the cert here to get an actual temporary cert instance. | 234 // Reload the cert here to get an actual temporary cert instance. |
267 x509_cert = net::X509Certificate::CreateFromBytesWithNickname( | 235 x509_cert = DecodePEMCertificate(x509_data, guid); |
268 decoded_x509.data(), | |
269 decoded_x509.size(), | |
270 guid.c_str()); | |
271 if (!x509_cert.get()) { | 236 if (!x509_cert.get()) { |
272 ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); | 237 ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); |
273 return false; | 238 return false; |
274 } | 239 } |
275 DCHECK(!x509_cert->os_cert_handle()->isperm); | 240 DCHECK(!x509_cert->os_cert_handle()->isperm); |
276 DCHECK(x509_cert->os_cert_handle()->istemp); | 241 DCHECK(x509_cert->os_cert_handle()->istemp); |
277 } | 242 } |
278 | 243 |
279 // Make sure the GUID is not already taken. Note that for the reimport case we | 244 // Make sure the GUID is not already taken. Note that for the reimport case we |
280 // have removed the existing cert above. | 245 // have removed the existing cert above. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); | 334 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); |
370 SECKEY_DestroyPrivateKey(private_key); | 335 SECKEY_DestroyPrivateKey(private_key); |
371 } else { | 336 } else { |
372 ONC_LOG_WARNING("Unable to find private key for certificate."); | 337 ONC_LOG_WARNING("Unable to find private key for certificate."); |
373 } | 338 } |
374 return true; | 339 return true; |
375 } | 340 } |
376 | 341 |
377 } // namespace onc | 342 } // namespace onc |
378 } // namespace chromeos | 343 } // namespace chromeos |
OLD | NEW |