| 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 GetCertFromPEMEncoding(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 = GetCertFromPEMEncoding(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 |