summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/certificate_manager_model.cc2
-rw-r--r--chrome/browser/chromeos/cros/network_library.cc3
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser.cc165
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser.h34
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser_unittest.cc189
-rw-r--r--net/base/cert_database.h16
-rw-r--r--net/base/cert_database_nss.cc37
-rw-r--r--net/base/cert_database_nss_unittest.cc24
-rw-r--r--net/base/cert_database_openssl.cc7
-rw-r--r--net/base/x509_certificate.h43
-rw-r--r--net/base/x509_certificate_nss.cc101
-rw-r--r--net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp38
-rw-r--r--net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp93
-rw-r--r--net/third_party/mozilla_security_manager/nsPKCS12Blob.h8
14 files changed, 559 insertions, 201 deletions
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index e722ad8..6989f72 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -115,7 +115,7 @@ int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule* module,
const string16& password,
bool is_extractable) {
int result = cert_db_.ImportFromPKCS12(module, data, password,
- is_extractable);
+ is_extractable, NULL);
if (result == net::OK)
Refresh();
return result;
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc
index 787a5c1..43acb7c 100644
--- a/chrome/browser/chromeos/cros/network_library.cc
+++ b/chrome/browser/chromeos/cros/network_library.cc
@@ -39,6 +39,7 @@
#include "content/public/browser/browser_thread.h"
#include "crypto/nss_util.h" // crypto::GetTPMTokenInfo() for 802.1X and VPN.
#include "grit/generated_resources.h"
+#include "net/base/x509_certificate.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/text/bytes_formatting.h"
@@ -2839,7 +2840,7 @@ bool NetworkLibraryImplBase::LoadOncNetworks(const std::string& onc_blob,
for (int i = 0; i < parser.GetCertificatesSize(); i++) {
// Insert each of the available certs into the certificate DB.
- if (!parser.ParseCertificate(i)) {
+ if (parser.ParseCertificate(i).get() == NULL) {
DLOG(WARNING) << "Cannot parse certificate in ONC file";
return false;
}
diff --git a/chrome/browser/chromeos/cros/onc_network_parser.cc b/chrome/browser/chromeos/cros/onc_network_parser.cc
index 19ed94d..55f8e9a 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/chromeos/cros/onc_network_parser.h"
+#include <pk11pub.h>
+#include <keyhi.h>
+
#include "base/base64.h"
#include "base/json/json_value_serializer.h"
#include "base/json/json_writer.h" // for debug output only.
@@ -200,9 +203,8 @@ OncNetworkParser::OncNetworkParser(const std::string& onc_blob)
root_dict_->GetList("Certificates", &certificates_);
VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and "
<< GetCertificatesSize() << " certificates";
- if (!has_network_configurations || !has_certificates) {
- LOG(WARNING) << "ONC file has no NetworkConfigurations or Certificates.";
- }
+ LOG_IF(WARNING, (!has_network_configurations && !has_certificates))
+ << "ONC file has no NetworkConfigurations or Certificates.";
}
}
@@ -228,7 +230,8 @@ int OncNetworkParser::GetCertificatesSize() const {
return certificates_ ? certificates_->GetSize() : 0;
}
-bool OncNetworkParser::ParseCertificate(int cert_index) {
+scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
+ int cert_index) {
CHECK(certificates_);
CHECK(static_cast<size_t>(cert_index) < certificates_->GetSize());
CHECK(cert_index >= 0);
@@ -244,35 +247,39 @@ bool OncNetworkParser::ParseCertificate(int cert_index) {
<< ": " << certificate_json;
}
- // Get out the attributes of the given cert.
+ // Get out the attributes of the given certificate.
std::string guid;
bool remove = false;
if (!certificate->GetString("GUID", &guid) || guid.empty()) {
LOG(WARNING) << "ONC File: certificate missing identifier at index"
<< cert_index;
- return false;
+ return NULL;
}
if (!certificate->GetBoolean("Remove", &remove))
remove = false;
net::CertDatabase cert_database;
- if (remove)
- return cert_database.DeleteCertAndKeyByLabel(guid);
+ if (remove) {
+ bool success = DeleteCertAndKeyByNickname(guid);
+ DCHECK(success);
+ // TODO(gspencer): return removed certificate?
+ return NULL;
+ }
- // Not removing, so let's get the data we need to add this cert.
+ // Not removing, so let's get the data we need to add this certificate.
std::string cert_type;
certificate->GetString("Type", &cert_type);
if (cert_type == "Server" || cert_type == "Authority") {
- return ParseServerOrCaCertificate(cert_index, cert_type, certificate);
+ return ParseServerOrCaCertificate(cert_index, cert_type, guid, certificate);
}
if (cert_type == "Client") {
- return ParseClientCertificate(cert_index, certificate);
+ return ParseClientCertificate(cert_index, guid, certificate);
}
LOG(WARNING) << "ONC File: certificate of unknown type: " << cert_type
<< " at index " << cert_index;
- return false;
+ return NULL;
}
Network* OncNetworkParser::ParseNetwork(int n) {
@@ -350,9 +357,11 @@ std::string OncNetworkParser::GetGuidFromDictionary(
return guid_string;
}
-bool OncNetworkParser::ParseServerOrCaCertificate(
+scoped_refptr<net::X509Certificate>
+OncNetworkParser::ParseServerOrCaCertificate(
int cert_index,
const std::string& cert_type,
+ const std::string& guid,
base::DictionaryValue* certificate) {
net::CertDatabase cert_database;
bool web_trust = false;
@@ -363,7 +372,7 @@ bool OncNetworkParser::ParseServerOrCaCertificate(
if (!trust_list->GetString(i, &trust_type)) {
LOG(WARNING) << "ONC File: certificate trust is invalid at index "
<< cert_index;
- return false;
+ return NULL;
}
if (trust_type == "Web") {
web_trust = true;
@@ -371,7 +380,7 @@ bool OncNetworkParser::ParseServerOrCaCertificate(
LOG(WARNING) << "ONC File: certificate contains unknown "
<< "trust type: " << trust_type
<< " at index " << cert_index;
- return false;
+ return NULL;
}
}
}
@@ -381,23 +390,26 @@ bool OncNetworkParser::ParseServerOrCaCertificate(
LOG(WARNING) << "ONC File: certificate missing appropriate "
<< "certificate data for type: " << cert_type
<< " at index " << cert_index;
- return false;
+ return NULL;
}
std::string decoded_x509;
if (!base::Base64Decode(x509_data, &decoded_x509)) {
LOG(WARNING) << "Unable to base64 decode X509 data: \""
<< x509_data << "\".";
- return false;
+ return NULL;
}
- scoped_refptr<net::X509Certificate> x509_cert(
- net::X509Certificate::CreateFromBytes(decoded_x509.c_str(),
- decoded_x509.size()));
+ scoped_refptr<net::X509Certificate> x509_cert =
+ net::X509Certificate::CreateFromBytesWithNickname(
+ decoded_x509.c_str(),
+ decoded_x509.size(),
+ guid.c_str());
if (!x509_cert.get()) {
LOG(WARNING) << "Unable to create X509 certificate from bytes.";
- return false;
+ return NULL;
}
+
net::CertificateList cert_list;
cert_list.push_back(x509_cert);
net::CertDatabase::ImportCertFailureList failures;
@@ -415,20 +427,22 @@ bool OncNetworkParser::ParseServerOrCaCertificate(
<< net::ErrorToString(failures[0].net_error)
<< ") importing " << cert_type << " certificate at index "
<< cert_index;
- return false;
+ return NULL;
}
if (!success) {
LOG(WARNING) << "ONC File: Unknown error importing " << cert_type
<< " certificate at index " << cert_index;
- return false;
+ return NULL;
}
VLOG(2) << "Successfully imported server/ca certificate at index "
<< cert_index;
- return true;
+
+ return x509_cert;
}
-bool OncNetworkParser::ParseClientCertificate(
+scoped_refptr<net::X509Certificate> OncNetworkParser::ParseClientCertificate(
int cert_index,
+ const std::string& guid,
base::DictionaryValue* certificate) {
net::CertDatabase cert_database;
std::string pkcs12_data;
@@ -436,29 +450,60 @@ bool OncNetworkParser::ParseClientCertificate(
pkcs12_data.empty()) {
LOG(WARNING) << "ONC File: PKCS12 data is missing for Client "
<< "certificate at index " << cert_index;
- return false;
+ return NULL;
}
std::string decoded_pkcs12;
if (!base::Base64Decode(pkcs12_data, &decoded_pkcs12)) {
LOG(WARNING) << "Unable to base64 decode PKCS#12 data: \""
<< pkcs12_data << "\".";
- return false;
+ return NULL;
}
// Since this has a private key, always use the private module.
scoped_refptr<net::CryptoModule> module(cert_database.GetPrivateModule());
+ net::CertificateList imported_certs;
+
int result = cert_database.ImportFromPKCS12(
- module.get(), decoded_pkcs12, string16(), false);
+ module.get(), decoded_pkcs12, string16(), false, &imported_certs);
if (result != net::OK) {
LOG(WARNING) << "ONC File: Unable to import Client certificate at index "
<< cert_index
<< " (error " << net::ErrorToString(result) << ").";
- return false;
+ return NULL;
}
+
+ if (imported_certs.size() == 0) {
+ LOG(WARNING) << "ONC File: PKCS12 data contains no importable certificates"
+ << " at index " << cert_index;
+ return NULL;
+ }
+
+ if (imported_certs.size() != 1) {
+ LOG(WARNING) << "ONC File: PKCS12 data at index " << cert_index
+ << " contains more than one certificate. Only the first one will"
+ << " be imported.";
+ }
+
+ scoped_refptr<net::X509Certificate> cert_result = imported_certs[0];
+
+ // Find the private key associated with this certificate, and set the
+ // nickname on it.
+ SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
+ cert_result->os_cert_handle()->slot,
+ cert_result->os_cert_handle(),
+ NULL); // wincx
+ if (private_key) {
+ PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str()));
+ SECKEY_DestroyPrivateKey(private_key);
+ } else {
+ LOG(WARNING) << "ONC File: Unable to find private key for cert at index"
+ << cert_index;
+ }
+
VLOG(2) << "Successfully imported client certificate at index "
<< cert_index;
- return true;
+ return cert_result;
}
bool OncNetworkParser::ParseNestedObject(Network* network,
@@ -588,6 +633,66 @@ bool OncNetworkParser::ParseNetworkConfigurationValue(
return false;
}
+// static
+bool OncNetworkParser::DeleteCertAndKeyByNickname(const std::string& label) {
+ net::CertificateList cert_list;
+ ListCertsWithNickname(label, &cert_list);
+ net::CertDatabase cert_db;
+ bool result = true;
+ for (net::CertificateList::iterator iter = cert_list.begin();
+ iter != cert_list.end(); ++iter) {
+ // If we fail, we try and delete the rest still.
+ // TODO(gspencer): this isn't very "transactional". If we fail on some, but
+ // not all, then it's possible to leave things in a weird state.
+ // Luckily there should only be one cert with a particular
+ // label, and the cert not being found is one of the few reasons the
+ // delete could fail, but still... The other choice is to return
+ // failure immediately, but that doesn't seem to do what is intended.
+ if (!cert_db.DeleteCertAndKey(iter->get()))
+ result = false;
+ }
+ return result;
+}
+
+// static
+void OncNetworkParser::ListCertsWithNickname(const std::string& label,
+ net::CertificateList* result) {
+ net::CertificateList all_certs;
+ net::CertDatabase cert_db;
+ cert_db.ListCerts(&all_certs);
+ result->clear();
+ for (net::CertificateList::iterator iter = all_certs.begin();
+ iter != all_certs.end(); ++iter) {
+ if (iter->get()->os_cert_handle()->nickname) {
+ // Separate the nickname stored in the certificate at the colon, since
+ // NSS likes to store it as token:nickname.
+ const char* delimiter =
+ ::strchr(iter->get()->os_cert_handle()->nickname, ':');
+ if (delimiter) {
+ delimiter++; // move past the colon.
+ if (strcmp(delimiter, label.c_str()) == 0) {
+ result->push_back(*iter);
+ continue;
+ }
+ }
+ }
+ // Now we find the private key for this certificate and see if it has a
+ // nickname that matches. If there is a private key, and it matches,
+ // then this is a client cert that we are looking for.
+ SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
+ iter->get()->os_cert_handle()->slot,
+ iter->get()->os_cert_handle(),
+ NULL); // wincx
+ if (private_key) {
+ char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key);
+ if (private_key_nickname && private_key_nickname == label)
+ result->push_back(*iter);
+ PORT_Free(private_key_nickname);
+ SECKEY_DestroyPrivateKey(private_key);
+ }
+ }
+}
+
// -------------------- OncWirelessNetworkParser --------------------
OncWirelessNetworkParser::OncWirelessNetworkParser() {}
diff --git a/chrome/browser/chromeos/cros/onc_network_parser.h b/chrome/browser/chromeos/cros/onc_network_parser.h
index 48fbe61..ee3bd65 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser.h
+++ b/chrome/browser/chromeos/cros/onc_network_parser.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/compiler_specific.h" // for OVERRIDE
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/network_parser.h"
@@ -19,6 +20,11 @@ class ListValue;
class Value;
}
+namespace net {
+class X509Certificate;
+typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
+}
+
namespace chromeos {
// This is a simple representation of the signature of an ONC typed
@@ -52,16 +58,17 @@ class OncNetworkParser : public NetworkParser {
// Returns the number of networks in the "NetworkConfigs" list.
int GetNetworkConfigsSize() const;
- // Returns the number of certificates in the "Certificates" list.
- int GetCertificatesSize() const;
-
// Call to create the network by parsing network config in the nth position.
// (0-based). Returns NULL if there's a parse error or if n is out of range.
Network* ParseNetwork(int n);
+ // Returns the number of certificates in the "Certificates" list.
+ int GetCertificatesSize() const;
+
// Call to parse and import the nth certificate in the certificate
- // list. Returns false on failure.
- bool ParseCertificate(int n);
+ // list into the certificate store. Returns a NULL refptr if
+ // there's a parse error or if n is out of range.
+ scoped_refptr<net::X509Certificate> ParseCertificate(int n);
virtual Network* CreateNetworkFromInfo(const std::string& service_path,
const base::DictionaryValue& info) OVERRIDE;
@@ -104,14 +111,27 @@ class OncNetworkParser : public NetworkParser {
const std::string& onc_type);
private:
- bool ParseServerOrCaCertificate(
+ FRIEND_TEST_ALL_PREFIXES(OncNetworkParserTest, TestAddClientCertificate);
+ FRIEND_TEST_ALL_PREFIXES(OncNetworkParserTest, TestAddServerCertificate);
+ FRIEND_TEST_ALL_PREFIXES(OncNetworkParserTest, TestAddAuthorityCertificate);
+ scoped_refptr<net::X509Certificate> ParseServerOrCaCertificate(
int cert_index,
const std::string& cert_type,
+ const std::string& guid,
base::DictionaryValue* certificate);
- bool ParseClientCertificate(
+ scoped_refptr<net::X509Certificate> ParseClientCertificate(
int cert_index,
+ const std::string& guid,
base::DictionaryValue* certificate);
+ // This lists the certificates that have the string |label| as their
+ // certificate nickname (exact match).
+ static void ListCertsWithNickname(const std::string& label,
+ net::CertificateList* result);
+ // This deletes any certificate that has the string |label| as its
+ // nickname (exact match).
+ static bool DeleteCertAndKeyByNickname(const std::string& label);
+
// Error message from the JSON parser, if applicable.
std::string parse_error_;
diff --git a/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc b/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
index b2a2486..ec5907a 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
@@ -5,21 +5,27 @@
#include "chrome/browser/chromeos/cros/onc_network_parser.h"
#include <cert.h>
+#include <keyhi.h>
#include <pk11pub.h>
#include "base/lazy_instance.h"
#include "base/scoped_temp_dir.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/system/runtime_environment.h"
#include "crypto/nss_util.h"
#include "net/base/cert_database.h"
+#include "net/base/cert_type.h"
#include "net/base/crypto_module.h"
#include "net/base/x509_certificate.h"
+#include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
+namespace msm = mozilla_security_manager;
namespace chromeos {
+namespace {
const char kNetworkConfigurationOpenVPN[] =
" {"
" \"GUID\": \"{408290ea-9299-4757-ab04-8957d55f0f13}\","
@@ -102,6 +108,21 @@ const char kCertificateWebAuthority[] =
"1kohau6FauQx87by5NIRPdkNPvkQ==\""
" }";
+const char g_token_name[] = "OncNetworkParserTest token";
+
+net::CertType GetCertType(const net::X509Certificate* cert) {
+ DCHECK(cert);
+ msm::nsNSSCertTrust trust(cert->os_cert_handle()->trust);
+ if (trust.HasAnyUser())
+ return net::USER_CERT;
+ if (trust.HasAnyCA() || CERT_IsCACert(cert->os_cert_handle(), NULL))
+ return net::CA_CERT;
+ if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE))
+ return net::SERVER_CERT;
+ return net::UNKNOWN_CERT;
+}
+
+} // namespace
class OncNetworkParserTest : public testing::Test {
public:
@@ -113,8 +134,7 @@ class OncNetworkParserTest : public testing::Test {
// it once, and empty it for each test case. Here's the bug:
// https://bugzilla.mozilla.org/show_bug.cgi?id=588269
ASSERT_TRUE(
- crypto::OpenTestNSSDB(temp_db_dir_.Get().path(),
- "OncNetworkParserTest db"));
+ crypto::OpenTestNSSDB(temp_db_dir_.Get().path(), g_token_name));
}
static void TearDownTestCase() {
@@ -446,47 +466,6 @@ TEST_F(OncNetworkParserTest, TestCreateNetworkL2TPIPsec) {
EXPECT_FALSE(vpn->save_credentials());
}
-TEST_F(OncNetworkParserTest, TestAddServerCertificate) {
- std::string test_blob(
- "{"
- " \"Certificates\": ["
- " {"
- " \"GUID\": \"{f998f760-272b-6939-4c2beffe428697aa}\","
- " \"Type\": \"Server\","
- " \"X509\": \"MIICWDCCAcECAxAAATANBgkqhkiG9w0BAQQFADCBkzEVM"
- "BMGA1UEChMMR29vZ2xlLCBJbmMuMREwDwYDVQQLEwhDaHJvbWVPUzEiMCAGCSqGSIb3DQ"
- "EJARYTZ3NwZW5jZXJAZ29vZ2xlLmNvbTEaMBgGA1UEBxMRTW91bnRhaW4gVmlldywgQ0E"
- "xCzAJBgNVBAgTAkNBMQswCQYDVQQGEwJVUzENMAsGA1UEAxMEbG1hbzAeFw0xMTAzMTYy"
- "MzQ5MzhaFw0xMjAzMTUyMzQ5MzhaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEVM"
- "BMGA1UEChMMR29vZ2xlLCBJbmMuMREwDwYDVQQLEwhDaHJvbWVPUzENMAsGA1UEAxMEbG"
- "1hbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA31WiJ9LvprrhKtDlW0RdLFAO7Qj"
- "kvs+sG6j2Vp2aBSrlhALG/0BVHUhWi4F/HHJho+ncLHAg5AGO0sdAjYUdQG6tfPqjLsIA"
- "LtoKEZZdFe/JhmqOEaxWsSdu2S2RdPgCQOsP79EH58gXwu2gejCkJDmU22WL4YLuqOc17"
- "nxbDC8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCv4vMD+PMlfnftu4/6Yf/oMLE8yCOqZT"
- "Q/dWCxB9PiJnOefiBeSzSZE6Uv3G7qnblZPVZaFeJMd+ostt0viCyPucFsFgLMyyoV1dM"
- "VPVwJT5Iq1AHehWXnTBbxUK9wioA5jOEKdroKjuSSsg/Q8Wx6cpJmttQz5olGPgstmACR"
- "WA==\""
- " }"
- " ],"
- "}");
- OncNetworkParser parser(test_blob);
-
- EXPECT_EQ(1, parser.GetCertificatesSize());
- EXPECT_TRUE(parser.ParseCertificate(0));
-}
-
-TEST_F(OncNetworkParserTest, TestAddAuthorityCertificate) {
- const std::string test_blob(std::string("{"
- " \"Certificates\": [") +
- std::string(kCertificateWebAuthority) + std::string(
- " ],"
- "}"));
- OncNetworkParser parser(test_blob);
-
- EXPECT_EQ(1, parser.GetCertificatesSize());
- EXPECT_TRUE(parser.ParseCertificate(0));
-}
-
TEST_F(OncNetworkParserTest, TestAddClientCertificate) {
std::string test_blob(
"{"
@@ -529,10 +508,130 @@ TEST_F(OncNetworkParserTest, TestAddClientCertificate) {
" }"
" ],"
"}");
+ std::string test_guid("{f998f760-272b-6939-4c2beffe428697ac}");
OncNetworkParser parser(test_blob);
+ ASSERT_EQ(1, parser.GetCertificatesSize());
+
+ scoped_refptr<net::X509Certificate> cert = parser.ParseCertificate(0).get();
+ EXPECT_TRUE(cert.get() != NULL);
+ EXPECT_EQ(net::USER_CERT, GetCertType(cert.get()));
+
+ EXPECT_STREQ(test_guid.c_str(),
+ cert->GetDefaultNickname(net::USER_CERT).c_str());
+ net::CertificateList result_list;
+ OncNetworkParser::ListCertsWithNickname(test_guid, &result_list);
+ ASSERT_EQ(1ul, result_list.size());
+ EXPECT_EQ(net::USER_CERT, GetCertType(result_list[0].get()));
+
+ SECKEYPrivateKeyList* privkey_list =
+ PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL);
+ EXPECT_TRUE(privkey_list);
+ if (privkey_list) {
+ SECKEYPrivateKeyListNode* node = PRIVKEY_LIST_HEAD(privkey_list);
+ int count = 0;
+ while (!PRIVKEY_LIST_END(node, privkey_list)) {
+ char* name = PK11_GetPrivateKeyNickname(node->key);
+ EXPECT_STREQ(test_guid.c_str(), name);
+ PORT_Free(name);
+ count++;
+ node = PRIVKEY_LIST_NEXT(node);
+ }
+ EXPECT_EQ(1, count);
+ SECKEY_DestroyPrivateKeyList(privkey_list);
+ }
+
+ SECKEYPublicKeyList* pubkey_list =
+ PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL);
+ EXPECT_TRUE(pubkey_list);
+ if (pubkey_list) {
+ SECKEYPublicKeyListNode* node = PUBKEY_LIST_HEAD(pubkey_list);
+ int count = 0;
+ while (!PUBKEY_LIST_END(node, pubkey_list)) {
+ count++;
+ node = PUBKEY_LIST_NEXT(node);
+ }
+ EXPECT_EQ(1, count);
+ SECKEY_DestroyPublicKeyList(pubkey_list);
+ }
+}
+
+TEST_F(OncNetworkParserTest, TestAddServerCertificate) {
+ std::string test_blob(
+ "{"
+ " \"Certificates\": ["
+ " {"
+ " \"GUID\": \"{f998f760-272b-6939-4c2beffe428697aa}\","
+ " \"Type\": \"Server\","
+ " \"X509\": \"MIICWDCCAcECAxAAATANBgkqhkiG9w0BAQQFADCBkzEVM"
+ "BMGA1UEChMMR29vZ2xlLCBJbmMuMREwDwYDVQQLEwhDaHJvbWVPUzEiMCAGCSqGSIb3DQ"
+ "EJARYTZ3NwZW5jZXJAZ29vZ2xlLmNvbTEaMBgGA1UEBxMRTW91bnRhaW4gVmlldywgQ0E"
+ "xCzAJBgNVBAgTAkNBMQswCQYDVQQGEwJVUzENMAsGA1UEAxMEbG1hbzAeFw0xMTAzMTYy"
+ "MzQ5MzhaFw0xMjAzMTUyMzQ5MzhaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEVM"
+ "BMGA1UEChMMR29vZ2xlLCBJbmMuMREwDwYDVQQLEwhDaHJvbWVPUzENMAsGA1UEAxMEbG"
+ "1hbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA31WiJ9LvprrhKtDlW0RdLFAO7Qj"
+ "kvs+sG6j2Vp2aBSrlhALG/0BVHUhWi4F/HHJho+ncLHAg5AGO0sdAjYUdQG6tfPqjLsIA"
+ "LtoKEZZdFe/JhmqOEaxWsSdu2S2RdPgCQOsP79EH58gXwu2gejCkJDmU22WL4YLuqOc17"
+ "nxbDC8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCv4vMD+PMlfnftu4/6Yf/oMLE8yCOqZT"
+ "Q/dWCxB9PiJnOefiBeSzSZE6Uv3G7qnblZPVZaFeJMd+ostt0viCyPucFsFgLMyyoV1dM"
+ "VPVwJT5Iq1AHehWXnTBbxUK9wioA5jOEKdroKjuSSsg/Q8Wx6cpJmttQz5olGPgstmACR"
+ "WA==\""
+ " }"
+ " ],"
+ "}");
+ std::string test_guid("{f998f760-272b-6939-4c2beffe428697aa}");
+ OncNetworkParser parser(test_blob);
+ ASSERT_EQ(1, parser.GetCertificatesSize());
+
+ scoped_refptr<net::X509Certificate> cert = parser.ParseCertificate(0).get();
+ EXPECT_TRUE(cert.get() != NULL);
+ EXPECT_EQ(net::SERVER_CERT, GetCertType(cert.get()));
+
+ EXPECT_STREQ(test_guid.c_str(),
+ cert->GetDefaultNickname(net::SERVER_CERT).c_str());
+ net::CertificateList result_list;
+ OncNetworkParser::ListCertsWithNickname(test_guid, &result_list);
+ ASSERT_EQ(1ul, result_list.size());
+ EXPECT_EQ(net::SERVER_CERT, GetCertType(result_list[0].get()));
+
+ SECKEYPrivateKeyList* privkey_list =
+ PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL);
+ EXPECT_FALSE(privkey_list);
+
+ SECKEYPublicKeyList* pubkey_list =
+ PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL);
+ EXPECT_FALSE(pubkey_list);
+
+}
+
+TEST_F(OncNetworkParserTest, TestAddAuthorityCertificate) {
+ const std::string test_blob(std::string("{"
+ " \"Certificates\": [") +
+ std::string(kCertificateWebAuthority) + std::string(
+ " ],"
+ "}"));
+ std::string test_guid("{f998f760-272b-6939-4c2beffe428697ab}");
+ OncNetworkParser parser(test_blob);
+ ASSERT_EQ(1, parser.GetCertificatesSize());
+
+ scoped_refptr<net::X509Certificate> cert = parser.ParseCertificate(0).get();
+ EXPECT_TRUE(cert.get() != NULL);
+ EXPECT_EQ(net::CA_CERT, GetCertType(cert.get()));
+
+ EXPECT_STREQ(test_guid.c_str(),
+ cert->GetDefaultNickname(net::CA_CERT).c_str());
+ net::CertificateList result_list;
+ OncNetworkParser::ListCertsWithNickname(test_guid, &result_list);
+ ASSERT_EQ(1ul, result_list.size());
+ EXPECT_EQ(net::CA_CERT, GetCertType(result_list[0].get()));
+
+ SECKEYPrivateKeyList* privkey_list =
+ PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL);
+ EXPECT_FALSE(privkey_list);
+
+ SECKEYPublicKeyList* pubkey_list =
+ PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL);
+ EXPECT_FALSE(pubkey_list);
- EXPECT_EQ(1, parser.GetCertificatesSize());
- EXPECT_TRUE(parser.ParseCertificate(0));
}
TEST_F(OncNetworkParserTest, TestNetworkAndCertificate) {
diff --git a/net/base/cert_database.h b/net/base/cert_database.h
index a735e693..cfd670c 100644
--- a/net/base/cert_database.h
+++ b/net/base/cert_database.h
@@ -99,8 +99,8 @@ class NET_EXPORT CertDatabase {
int AddUserCert(X509Certificate* cert);
#if defined(USE_NSS) || defined(USE_OPENSSL)
- // Get a list of unique certificates in the certificate database. (One
- // instance of all certificates.)
+ // Get a list of unique certificates in the certificate database (one
+ // instance of all certificates).
void ListCerts(CertificateList* certs);
// Get the default module for public key data.
@@ -119,11 +119,13 @@ class NET_EXPORT CertDatabase {
// If |is_extractable| is false, mark the private key as being unextractable
// from the module.
// Returns OK or a network error code such as ERR_PKCS12_IMPORT_BAD_PASSWORD
- // or ERR_PKCS12_IMPORT_ERROR.
+ // or ERR_PKCS12_IMPORT_ERROR. |imported_certs|, if non-NULL, returns a list
+ // of certs that were imported.
int ImportFromPKCS12(CryptoModule* module,
const std::string& data,
const string16& password,
- bool is_extractable);
+ bool is_extractable,
+ CertificateList* imported_certs);
// Export the given certificates and private keys into a PKCS #12 blob,
// storing into |output|.
@@ -178,12 +180,6 @@ class NET_EXPORT CertDatabase {
// success.
bool DeleteCertAndKey(const X509Certificate* cert);
- // Delete the certificate and associated public and private key (if
- // one exists) with the given label from the database. Returns true
- // on success. ("label" here refers to the NSS Attribute CKA_LABEL,
- // also referred to as a nickname or friendly name).
- bool DeleteCertAndKeyByLabel(const std::string& label);
-
// Check whether cert is stored in a readonly slot.
bool IsReadOnly(const X509Certificate* cert) const;
#endif
diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc
index 817372d..6781917 100644
--- a/net/base/cert_database_nss.cc
+++ b/net/base/cert_database_nss.cc
@@ -66,28 +66,12 @@ int CertDatabase::AddUserCert(X509Certificate* cert_obj) {
PK11SlotInfo* slot = NULL;
std::string nickname;
- // Create a nickname for this certificate.
- // We use the scheme used by Firefox:
- // --> <subject's common name>'s <issuer's common name> ID.
-
- std::string username, ca_name;
- char* temp_username = CERT_GetCommonName(&cert->subject);
- char* temp_ca_name = CERT_GetCommonName(&cert->issuer);
- if (temp_username) {
- username = temp_username;
- PORT_Free(temp_username);
- }
- if (temp_ca_name) {
- ca_name = temp_ca_name;
- PORT_Free(temp_ca_name);
- }
- nickname = username + "'s " + ca_name + " ID";
-
{
crypto::AutoNSSWriteLock lock;
- slot = PK11_ImportCertForKey(cert,
- const_cast<char*>(nickname.c_str()),
- NULL);
+ slot = PK11_ImportCertForKey(
+ cert,
+ cert_obj->GetDefaultNickname(net::USER_CERT).c_str(),
+ NULL);
}
if (!slot) {
@@ -161,11 +145,13 @@ int CertDatabase::ImportFromPKCS12(
CryptoModule* module,
const std::string& data,
const string16& password,
- bool is_extractable) {
+ bool is_extractable,
+ net::CertificateList* imported_certs) {
int result = psm::nsPKCS12Blob_Import(module->os_module_handle(),
data.data(), data.size(),
password,
- is_extractable);
+ is_extractable,
+ imported_certs);
if (result == net::OK)
CertDatabase::NotifyObserversOfUserCertAdded(NULL);
@@ -328,13 +314,6 @@ bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
return true;
}
-bool CertDatabase::DeleteCertAndKeyByLabel(const std::string& label) {
- // TODO(gspencer):Find the certificate with the given CKA_LABEL
- // (nickname), and delete it.
- NOTIMPLEMENTED();
- return false;
-}
-
bool CertDatabase::IsReadOnly(const X509Certificate* cert) const {
PK11SlotInfo* slot = cert->os_cert_handle()->slot;
return slot && PK11_IsReadOnly(slot);
diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc
index 1129544..c76b5bb 100644
--- a/net/base/cert_database_nss_unittest.cc
+++ b/net/base/cert_database_nss_unittest.cc
@@ -154,7 +154,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) {
cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
string16(),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
// Test db should still be empty.
EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
@@ -166,7 +167,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsExtractableAndExportAgain) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
@@ -189,7 +191,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12Twice) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
EXPECT_EQ(1U, ListCertsInSlot(slot_->os_module_handle()).size());
// NSS has a SEC_ERROR_PKCS12_DUPLICATE_DATA error, but it doesn't look like
@@ -197,7 +200,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12Twice) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
EXPECT_EQ(1U, ListCertsInSlot(slot_->os_module_handle()).size());
}
@@ -207,7 +211,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsUnextractableAndExportAgain) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- false)); // is_extractable
+ false, // is_extractable
+ NULL));
CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
@@ -228,7 +233,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12OnlyMarkIncludedKey) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
@@ -238,7 +244,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12OnlyMarkIncludedKey) {
EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
ASCIIToUTF16("12345"),
- false)); // is_extractable
+ false, // is_extractable
+ NULL));
cert_list = ListCertsInSlot(slot_->os_module_handle());
ASSERT_EQ(1U, cert_list.size());
@@ -257,7 +264,8 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12InvalidFile) {
cert_db_.ImportFromPKCS12(slot_,
pkcs12_data,
string16(),
- true)); // is_extractable
+ true, // is_extractable
+ NULL));
// Test db should still be empty.
EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
diff --git a/net/base/cert_database_openssl.cc b/net/base/cert_database_openssl.cc
index 76bd3f8..ca429c08 100644
--- a/net/base/cert_database_openssl.cc
+++ b/net/base/cert_database_openssl.cc
@@ -82,13 +82,6 @@ bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
return false;
}
-bool CertDatabase::DeleteCertAndKeyByLabel(const std::string& label) {
- // TODO(gspencer):Find the certificate with the given label
- // (nickname), and delete it.
- NOTIMPLEMENTED();
- return false;
-}
-
CertDatabase::TrustBits CertDatabase::GetCertTrust(const X509Certificate* cert,
CertType type) const {
// TODO(bulach): implement me.
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index 6e155683..05e74b3 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/string_piece.h"
#include "base/time.h"
+#include "net/base/cert_type.h"
#include "net/base/net_export.h"
#include "net/base/x509_cert_types.h"
@@ -146,6 +147,24 @@ class NET_EXPORT X509Certificate
// The returned pointer must be stored in a scoped_refptr<X509Certificate>.
static X509Certificate* CreateFromBytes(const char* data, int length);
+#if defined(USE_NSS)
+ // Create an X509Certificate from the DER-encoded representation.
+ // |nickname| can be NULL if an auto-generated nickname is desired.
+ // Returns NULL on failure. The returned pointer must be stored in a
+ // scoped_refptr<X509Certificate>.
+ //
+ // This function differs from CreateFromBytes in that it takes a
+ // nickname that will be used when the certificate is imported into PKCS#11.
+ static X509Certificate* CreateFromBytesWithNickname(const char* data,
+ int length,
+ const char* nickname);
+
+ // The default nickname of the certificate, based on the certificate type
+ // passed in. If this object was created using CreateFromBytesWithNickname,
+ // then this will return the nickname specified upon creation.
+ std::string GetDefaultNickname(CertType type) const;
+#endif
+
// Create an X509Certificate from the representation stored in the given
// pickle. The data for this object is found relative to the given
// pickle_iter, which should be passed to the pickle's various Read* methods.
@@ -413,15 +432,27 @@ class NET_EXPORT X509Certificate
// Returns true if two OSCertHandles refer to identical certificates.
static bool IsSameOSCert(OSCertHandle a, OSCertHandle b);
- // Creates an OS certificate handle from the BER-encoded representation.
+ // Creates an OS certificate handle from the DER-encoded representation.
// Returns NULL on failure.
static OSCertHandle CreateOSCertHandleFromBytes(const char* data,
int length);
+#if defined(USE_NSS)
+ // Creates an OS certificate handle from the DER-encoded representation.
+ // Returns NULL on failure. Sets the default nickname if |nickname| is
+ // non-NULL.
+ static OSCertHandle CreateOSCertHandleFromBytesWithNickname(
+ const char* data,
+ int length,
+ const char* nickname);
+#endif
+
// Creates all possible OS certificate handles from |data| encoded in a
// specific |format|. Returns an empty collection on failure.
static OSCertHandles CreateOSCertHandlesFromBytes(
- const char* data, int length, Format format);
+ const char* data,
+ int length,
+ Format format);
// Duplicates (or adds a reference to) an OS certificate handle.
static OSCertHandle DupOSCertHandle(OSCertHandle cert_handle);
@@ -553,6 +584,14 @@ class NET_EXPORT X509Certificate
// that may be needed for chain building.
OSCertHandles intermediate_ca_certs_;
+#if defined(USE_NSS)
+ // This stores any default nickname that has been set on the certificate
+ // at creation time with CreateFromBytesWithNickname.
+ // If this is empty, then GetDefaultNickname will return a generated name
+ // based on the type of the certificate.
+ std::string default_nickname_;
+#endif
+
#if defined(OS_MACOSX)
// Blocks multiple threads from verifying the cert simultaneously.
// (Marked mutable because it's used in a const method.)
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index bbb5cef..af7172c 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -6,6 +6,7 @@
#include <cert.h>
#include <cryptohi.h>
+#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
#include <prerror.h>
@@ -685,6 +686,90 @@ void X509Certificate::Initialize() {
}
// static
+X509Certificate* X509Certificate::CreateFromBytesWithNickname(
+ const char* data,
+ int length,
+ const char* nickname) {
+ OSCertHandle cert_handle = CreateOSCertHandleFromBytesWithNickname(data,
+ length,
+ nickname);
+ if (!cert_handle)
+ return NULL;
+
+ X509Certificate* cert = CreateFromHandle(cert_handle, OSCertHandles());
+ FreeOSCertHandle(cert_handle);
+
+ if (nickname)
+ cert->default_nickname_ = nickname;
+
+ return cert;
+}
+
+std::string X509Certificate::GetDefaultNickname(CertType type) const {
+ if (!default_nickname_.empty())
+ return default_nickname_;
+
+ std::string result;
+ if (type == USER_CERT) {
+ // Find the private key for this certificate and see if it has a
+ // nickname. If there is a private key, and it has a nickname, then
+ // we return that nickname.
+ SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
+ cert_handle_->slot,
+ cert_handle_,
+ NULL); // wincx
+ if (private_key) {
+ char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key);
+ if (private_key_nickname) {
+ result = private_key_nickname;
+ PORT_Free(private_key_nickname);
+ SECKEY_DestroyPrivateKey(private_key);
+ return result;
+ }
+ SECKEY_DestroyPrivateKey(private_key);
+ }
+ }
+
+ switch (type) {
+ case CA_CERT: {
+ char* nickname = CERT_MakeCANickname(cert_handle_);
+ result = nickname;
+ PORT_Free(nickname);
+ break;
+ }
+ case USER_CERT: {
+ // Create a nickname for a user certificate.
+ // We use the scheme used by Firefox:
+ // --> <subject's common name>'s <issuer's common name> ID.
+ // TODO(gspencer): internationalize this: it's wrong to
+ // hard code English.
+
+ std::string username, ca_name;
+ char* temp_username = CERT_GetCommonName(
+ &cert_handle_->subject);
+ char* temp_ca_name = CERT_GetCommonName(&cert_handle_->issuer);
+ if (temp_username) {
+ username = temp_username;
+ PORT_Free(temp_username);
+ }
+ if (temp_ca_name) {
+ ca_name = temp_ca_name;
+ PORT_Free(temp_ca_name);
+ }
+ result = username + "'s " + ca_name + " ID";
+ break;
+ }
+ case SERVER_CERT:
+ result = subject_.GetDisplayName();
+ break;
+ case UNKNOWN_CERT:
+ default:
+ break;
+ }
+ return result;
+}
+
+// static
X509Certificate* X509Certificate::CreateSelfSigned(
crypto::RSAPrivateKey* key,
const std::string& subject,
@@ -922,6 +1007,15 @@ bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
+ return CreateOSCertHandleFromBytesWithNickname(data, length, NULL);
+}
+
+// static
+X509Certificate::OSCertHandle
+X509Certificate::CreateOSCertHandleFromBytesWithNickname(
+ const char* data,
+ int length,
+ const char* nickname) {
if (length < 0)
return NULL;
@@ -936,13 +1030,16 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
der_cert.type = siDERCertBuffer;
// Parse into a certificate structure.
- return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
+ return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
+ const_cast<char*>(nickname),
PR_FALSE, PR_TRUE);
}
// static
X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
- const char* data, int length, Format format) {
+ const char* data,
+ int length,
+ Format format) {
OSCertHandles results;
if (length < 0)
return results;
diff --git a/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp b/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
index 3e50cd1..0cf430d 100644
--- a/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
+++ b/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp
@@ -80,14 +80,12 @@ bool ImportCACerts(const net::CertificateList& certificates,
// Mozilla uses CERT_AddTempCertToPerm, however it is privately exported,
// and it doesn't take the slot as an argument either. Instead, we use
// PK11_ImportCert and CERT_ChangeCertTrust.
- char* nickname = CERT_MakeCANickname(root->os_cert_handle());
- if (!nickname)
- return false;
- SECStatus srv = PK11_ImportCert(slot.get(), root->os_cert_handle(),
- CK_INVALID_HANDLE,
- nickname,
- PR_FALSE /* includeTrust (unused) */);
- PORT_Free(nickname);
+ SECStatus srv = PK11_ImportCert(
+ slot.get(),
+ root->os_cert_handle(),
+ CK_INVALID_HANDLE,
+ root->GetDefaultNickname(net::CA_CERT).c_str(),
+ PR_FALSE /* includeTrust (unused) */);
if (srv != SECSuccess) {
LOG(ERROR) << "PK11_ImportCert failed with error " << PORT_GetError();
return false;
@@ -139,14 +137,12 @@ bool ImportCACerts(const net::CertificateList& certificates,
// Mozilla uses CERT_ImportCerts, which doesn't take a slot arg. We use
// PK11_ImportCert instead.
- char* nickname = CERT_MakeCANickname(cert->os_cert_handle());
- if (!nickname)
- return false;
- SECStatus srv = PK11_ImportCert(slot.get(), cert->os_cert_handle(),
- CK_INVALID_HANDLE,
- nickname,
- PR_FALSE /* includeTrust (unused) */);
- PORT_Free(nickname);
+ SECStatus srv = PK11_ImportCert(
+ slot.get(),
+ cert->os_cert_handle(),
+ CK_INVALID_HANDLE,
+ cert->GetDefaultNickname(net::CA_CERT).c_str(),
+ PR_FALSE /* includeTrust (unused) */);
if (srv != SECSuccess) {
LOG(ERROR) << "PK11_ImportCert failed with error " << PORT_GetError();
// TODO(mattm): Should we bail or continue on error here? Mozilla doesn't
@@ -174,10 +170,12 @@ bool ImportServerCert(const net::CertificateList& certificates,
// Mozilla uses CERT_ImportCerts, which doesn't take a slot arg. We use
// PK11_ImportCert instead.
- SECStatus srv = PK11_ImportCert(slot.get(), cert->os_cert_handle(),
- CK_INVALID_HANDLE,
- cert->subject().GetDisplayName().c_str(),
- PR_FALSE /* includeTrust (unused) */);
+ SECStatus srv = PK11_ImportCert(
+ slot.get(),
+ cert->os_cert_handle(),
+ CK_INVALID_HANDLE,
+ cert->GetDefaultNickname(net::SERVER_CERT).c_str(),
+ PR_FALSE /* includeTrust (unused) */);
if (srv != SECSuccess) {
LOG(ERROR) << "PK11_ImportCert failed with error " << PORT_GetError();
not_imported->push_back(net::CertDatabase::ImportCertFailure(
diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
index 7781bf7..3087cec 100644
--- a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
+++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
@@ -57,7 +57,7 @@ namespace {
//
// For the NSS PKCS#12 library, must convert PRUnichars (shorts) to
// a buffer of octets. Must handle byte order correctly.
-// TODO: Is there a mozilla way to do this? In the string lib?
+// TODO: Is there a Mozilla way to do this? In the string lib?
void unicodeToItem(const PRUnichar *uni, SECItem *item)
{
int len = 0;
@@ -138,7 +138,7 @@ pip_ucs2_ascii_conversion_fn(PRBool toUnicode,
PRBool swapBytes)
{
CHECK_GE(maxOutBufLen, inBufLen);
- // do a no-op, since I've already got unicode. Hah!
+ // do a no-op, since I've already got Unicode. Hah!
*outBufLen = inBufLen;
memcpy(outBuf, inBuf, inBufLen);
return PR_TRUE;
@@ -151,7 +151,8 @@ nsPKCS12Blob_ImportHelper(const char* pkcs12_data,
const string16& password,
bool is_extractable,
bool try_zero_length_secitem,
- PK11SlotInfo *slot)
+ PK11SlotInfo *slot,
+ net::CertificateList* imported_certs)
{
DCHECK(pkcs12_data);
DCHECK(slot);
@@ -159,6 +160,10 @@ nsPKCS12Blob_ImportHelper(const char* pkcs12_data,
SECStatus srv = SECSuccess;
SEC_PKCS12DecoderContext *dcx = NULL;
SECItem unicodePw;
+ SECItem attribute_value;
+ CK_BBOOL attribute_data = CK_FALSE;
+ const SEC_PKCS12DecoderItem* decoder_item = NULL;
+
unicodePw.type = siBuffer;
unicodePw.len = 0;
unicodePw.data = NULL;
@@ -188,57 +193,71 @@ nsPKCS12Blob_ImportHelper(const char* pkcs12_data,
// validate bags
srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
if (srv) goto finish;
- // import cert and key
+ // import certificate and key
srv = SEC_PKCS12DecoderImportBags(dcx);
if (srv) goto finish;
- if (!is_extractable) {
- SECItem attribute_value;
- CK_BBOOL attribute_data = CK_FALSE;
- attribute_value.data = &attribute_data;
- attribute_value.len = sizeof(attribute_data);
+ attribute_value.data = &attribute_data;
+ attribute_value.len = sizeof(attribute_data);
- srv = SEC_PKCS12DecoderIterateInit(dcx);
- if (srv) goto finish;
+ srv = SEC_PKCS12DecoderIterateInit(dcx);
+ if (srv) goto finish;
+
+ if (imported_certs)
+ imported_certs->clear();
+
+ // Collect the list of decoded certificates, and mark private keys
+ // non-extractable if needed.
+ while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) {
+ if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID)
+ continue;
+
+ CERTCertificate* cert = PK11_FindCertFromDERCertItem(
+ slot, decoder_item->der,
+ NULL); // wincx
+ if (!cert) {
+ LOG(ERROR) << "Could not grab a handle to the certificate in the slot "
+ << "from the corresponding PKCS#12 DER certificate.";
+ continue;
+ }
+
+ // Add the cert to the list
+ if (imported_certs) {
+ // Empty list of intermediates.
+ net::X509Certificate::OSCertHandles intermediates;
+ imported_certs->push_back(
+ net::X509Certificate::CreateFromHandle(cert, intermediates));
+ }
+
+ // Once we have determined that the imported certificate has an
+ // associated private key too, only then can we mark the key as
+ // non-extractable.
+ if (!decoder_item->hasKey) {
+ CERT_DestroyCertificate(cert);
+ continue;
+ }
- const SEC_PKCS12DecoderItem* decoder_item = NULL;
// Iterate through all the imported PKCS12 items and mark any accompanying
- // private keys as unextractable.
- while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) {
- if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID)
- continue;
- if (!decoder_item->hasKey)
- continue;
-
- // Once we have determined that the imported certificate has an
- // associated private key too, only then can we mark the key as
- // unextractable.
- CERTCertificate* cert = PK11_FindCertFromDERCertItem(
- slot, decoder_item->der,
- NULL); // wincx
- if (!cert) {
- LOG(ERROR) << "Could not grab a handle to the certificate in the slot "
- << "from the corresponding PKCS#12 DER certificate.";
- continue;
- }
+ // private keys as non-extractable.
+ if (!is_extractable) {
SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert,
NULL); // wincx
- CERT_DestroyCertificate(cert);
if (privKey) {
- // Mark the private key as unextractable.
+ // Mark the private key as non-extractable.
srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE,
&attribute_value);
SECKEY_DestroyPrivateKey(privKey);
if (srv) {
LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private "
<< "key.";
+ CERT_DestroyCertificate(cert);
break;
}
}
}
+ CERT_DestroyCertificate(cert);
if (srv) goto finish;
}
-
import_result = net::OK;
finish:
// If srv != SECSuccess, NSS probably set a specific error code.
@@ -335,10 +354,12 @@ int nsPKCS12Blob_Import(PK11SlotInfo* slot,
const char* pkcs12_data,
size_t pkcs12_len,
const string16& password,
- bool is_extractable) {
+ bool is_extractable,
+ net::CertificateList* imported_certs) {
int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password,
- is_extractable, false, slot);
+ is_extractable, false, slot,
+ imported_certs);
// When the user entered a zero length password:
// An empty password should be represented as an empty
@@ -350,7 +371,7 @@ int nsPKCS12Blob_Import(PK11SlotInfo* slot,
// flavors.
if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.empty()) {
rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password,
- is_extractable, true, slot);
+ is_extractable, true, slot, imported_certs);
}
return rv;
}
diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.h b/net/third_party/mozilla_security_manager/nsPKCS12Blob.h
index ace6baa..d0c8da1 100644
--- a/net/third_party/mozilla_security_manager/nsPKCS12Blob.h
+++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.h
@@ -57,13 +57,15 @@ namespace mozilla_security_manager {
void EnsurePKCS12Init();
// Import the private key and certificate from a PKCS#12 blob into the slot.
-// If |is_extractable| is false, mark the private key as unextractable.
-// Returns a net error code.
+// If |is_extractable| is false, mark the private key as non-extractable.
+// Returns a net error code. |imported_certs|, if non-NULL, returns a list of
+// certs that were imported.
int nsPKCS12Blob_Import(PK11SlotInfo* slot,
const char* pkcs12_data,
size_t pkcs12_len,
const string16& password,
- bool is_extractable);
+ bool is_extractable,
+ net::CertificateList* imported_certs);
// Export the given certificates into a PKCS#12 blob, storing into output.
// Returns the number of certificates exported.