| Index: chromeos/network/onc/onc_certificate_importer.cc
|
| diff --git a/chromeos/network/onc/onc_certificate_importer.cc b/chromeos/network/onc/onc_certificate_importer.cc
|
| index fe8e66b8255e342a6f128ae78a885f4dc265ae49..9ab96312837acb28bc535150455065ba42fdcbe4 100644
|
| --- a/chromeos/network/onc/onc_certificate_importer.cc
|
| +++ b/chromeos/network/onc/onc_certificate_importer.cc
|
| @@ -42,7 +42,8 @@ CertificateImporter::CertificateImporter(bool allow_trust_imports)
|
|
|
| CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates(
|
| const base::ListValue& certificates,
|
| - net::CertificateList* onc_trusted_certificates) {
|
| + net::CertificateList* onc_trusted_certificates,
|
| + CertsByGUID* imported_server_and_ca_certs) {
|
| size_t successful_imports = 0;
|
| for (size_t i = 0; i < certificates.GetSize(); ++i) {
|
| const base::DictionaryValue* certificate = NULL;
|
| @@ -51,7 +52,8 @@ CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates(
|
|
|
| VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate;
|
|
|
| - if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates)) {
|
| + if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates,
|
| + imported_server_and_ca_certs)) {
|
| ONC_LOG_ERROR(
|
| base::StringPrintf("Cannot parse certificate at index %zu", i));
|
| } else {
|
| @@ -129,7 +131,8 @@ bool CertificateImporter::DeleteCertAndKeyByNickname(const std::string& label) {
|
|
|
| bool CertificateImporter::ParseAndStoreCertificate(
|
| const base::DictionaryValue& certificate,
|
| - net::CertificateList* onc_trusted_certificates) {
|
| + net::CertificateList* onc_trusted_certificates,
|
| + CertsByGUID* imported_server_and_ca_certs) {
|
| // Get out the attributes of the given certificate.
|
| std::string guid;
|
| certificate.GetStringWithoutPathExpansion(certificate::kGUID, &guid);
|
| @@ -150,8 +153,9 @@ bool CertificateImporter::ParseAndStoreCertificate(
|
| certificate.GetStringWithoutPathExpansion(certificate::kType, &cert_type);
|
| if (cert_type == certificate::kServer ||
|
| cert_type == certificate::kAuthority) {
|
| - return ParseServerOrCaCertificate(
|
| - cert_type, guid, certificate, onc_trusted_certificates);
|
| + return ParseServerOrCaCertificate(cert_type, guid, certificate,
|
| + onc_trusted_certificates,
|
| + imported_server_and_ca_certs);
|
| } else if (cert_type == certificate::kClient) {
|
| return ParseClientCertificate(guid, certificate);
|
| }
|
| @@ -164,7 +168,8 @@ bool CertificateImporter::ParseServerOrCaCertificate(
|
| const std::string& cert_type,
|
| const std::string& guid,
|
| const base::DictionaryValue& certificate,
|
| - net::CertificateList* onc_trusted_certificates) {
|
| + net::CertificateList* onc_trusted_certificates,
|
| + CertsByGUID* imported_server_and_ca_certs) {
|
| bool web_trust_flag = false;
|
| const base::ListValue* trust_list = NULL;
|
| if (certificate.GetListWithoutPathExpansion(certificate::kTrustBits,
|
| @@ -228,90 +233,56 @@ bool CertificateImporter::ParseServerOrCaCertificate(
|
| }
|
|
|
| scoped_refptr<net::X509Certificate> x509_cert =
|
| - net::X509Certificate::CreateFromBytesWithNickname(
|
| - decoded_x509.data(),
|
| - decoded_x509.size(),
|
| - guid.c_str());
|
| + net::X509Certificate::CreateFromBytes(decoded_x509.data(),
|
| + decoded_x509.size());
|
| if (!x509_cert.get()) {
|
| ONC_LOG_ERROR("Unable to create X509 certificate from bytes.");
|
| return false;
|
| }
|
|
|
| - // Due to a mismatch regarding cert identity between NSS (cert identity is
|
| - // determined by the raw bytes) and ONC (cert identity is determined by
|
| - // GUIDs), we have to special-case a number of situations here:
|
| - //
|
| - // a) The cert bits we're trying to insert are already present in the NSS cert
|
| - // store. This is indicated by the isperm bit in CERTCertificateStr. Since
|
| - // we might have to update the nick name, we just delete the existing cert
|
| - // and reimport the cert bits.
|
| - // b) NSS gives us an actual temporary certificate. In this case, there is no
|
| - // identical certificate known to NSS, so we can safely import the
|
| - // certificate. The GUID being imported may still be on a different
|
| - // certificate, and we could jump through hoops to reimport the existing
|
| - // certificate with a different nickname. However, that would mean lots of
|
| - // effort for a case that's pretty much illegal (reusing GUIDs contradicts
|
| - // the intention of GUIDs), so we just report an error.
|
| - //
|
| - // TODO(mnissler, gspencer): We should probably switch to a mode where we
|
| - // keep our own database for mapping GUIDs to certs in order to enable several
|
| - // GUIDs to map to the same cert. See http://crosbug.com/26073.
|
| + net::NSSCertDatabase::TrustBits trust = import_with_ssl_trust ?
|
| + net::NSSCertDatabase::TRUSTED_SSL :
|
| + net::NSSCertDatabase::TRUST_DEFAULT;
|
| +
|
| net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
|
| if (x509_cert->os_cert_handle()->isperm) {
|
| - if (!cert_database->DeleteCertAndKey(x509_cert.get())) {
|
| - ONC_LOG_ERROR("Unable to delete X509 certificate.");
|
| + VLOG(1) << "Certificate is already installed.";
|
| + if (!cert_database->SetCertTrust(
|
| + x509_cert,
|
| + cert_type == certificate::kServer ? net::SERVER_CERT : net::CA_CERT,
|
| + trust)) {
|
| + ONC_LOG_ERROR("Certificate of type " + cert_type +
|
| + " was already present, but trust couldn't be set.");
|
| + }
|
| + } else {
|
| + net::CertificateList cert_list;
|
| + cert_list.push_back(x509_cert);
|
| + net::NSSCertDatabase::ImportCertFailureList failures;
|
| + bool success = false;
|
| + if (cert_type == certificate::kServer)
|
| + success = cert_database->ImportServerCert(cert_list, trust, &failures);
|
| + else // Authority cert
|
| + success = cert_database->ImportCACerts(cert_list, trust, &failures);
|
| +
|
| + if (!failures.empty()) {
|
| + ONC_LOG_ERROR(
|
| + base::StringPrintf("Error ( %s ) importing %s certificate",
|
| + net::ErrorToString(failures[0].net_error),
|
| + cert_type.c_str()));
|
| return false;
|
| }
|
| -
|
| - // Reload the cert here to get an actual temporary cert instance.
|
| - x509_cert = net::X509Certificate::CreateFromBytesWithNickname(
|
| - decoded_x509.data(),
|
| - decoded_x509.size(),
|
| - guid.c_str());
|
| - if (!x509_cert.get()) {
|
| - ONC_LOG_ERROR("Unable to create X509 certificate from bytes.");
|
| + if (!success) {
|
| + ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate.");
|
| return false;
|
| }
|
| - DCHECK(!x509_cert->os_cert_handle()->isperm);
|
| - DCHECK(x509_cert->os_cert_handle()->istemp);
|
| - }
|
| -
|
| - // Make sure the GUID is not already taken. Note that for the reimport case we
|
| - // have removed the existing cert above.
|
| - net::CertificateList certs;
|
| - ListCertsWithNickname(guid, &certs);
|
| - if (!certs.empty()) {
|
| - ONC_LOG_ERROR("Certificate GUID is already in use: " + guid);
|
| - return false;
|
| - }
|
| -
|
| - net::CertificateList cert_list;
|
| - cert_list.push_back(x509_cert);
|
| - net::NSSCertDatabase::ImportCertFailureList failures;
|
| - bool success = false;
|
| - net::NSSCertDatabase::TrustBits trust = import_with_ssl_trust ?
|
| - net::NSSCertDatabase::TRUSTED_SSL :
|
| - net::NSSCertDatabase::TRUST_DEFAULT;
|
| - if (cert_type == certificate::kServer) {
|
| - success = cert_database->ImportServerCert(cert_list, trust, &failures);
|
| - } else { // Authority cert
|
| - success = cert_database->ImportCACerts(cert_list, trust, &failures);
|
| - }
|
| -
|
| - if (!failures.empty()) {
|
| - ONC_LOG_ERROR(base::StringPrintf("Error ( %s ) importing %s certificate",
|
| - net::ErrorToString(failures[0].net_error),
|
| - cert_type.c_str()));
|
| - return false;
|
| - }
|
| - if (!success) {
|
| - ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate.");
|
| - return false;
|
| }
|
|
|
| if (web_trust_flag && onc_trusted_certificates)
|
| onc_trusted_certificates->push_back(x509_cert);
|
|
|
| + if (imported_server_and_ca_certs)
|
| + (*imported_server_and_ca_certs)[guid] = x509_cert;
|
| +
|
| return true;
|
| }
|
|
|
|
|