diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-12 19:49:40 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-12 19:49:40 +0000 |
commit | bb639038078bfd16f820c026efeb1a9d21395e60 (patch) | |
tree | a0176554e744bc729bb014d24215de8de002cc00 /net | |
parent | c42d7348f690d96354e509a2082f2de9cc137f5c (diff) | |
download | chromium_src-bb639038078bfd16f820c026efeb1a9d21395e60.zip chromium_src-bb639038078bfd16f820c026efeb1a9d21395e60.tar.gz chromium_src-bb639038078bfd16f820c026efeb1a9d21395e60.tar.bz2 |
Add NSS PKCS12 import/export functions to CertDatabase.
Use sql: prefix when opening NSS UserDB (this will affect existing Chromeos installations, which had been using the old berkelydb format.)
BUG=19991,51327,51328,51330,51332
TEST=net/base/cert_database_nss_unittest.cc
Review URL: http://codereview.chromium.org/3018038
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55916 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/cert_database.h | 19 | ||||
-rw-r--r-- | net/base/cert_database_nss.cc | 19 | ||||
-rw-r--r-- | net/base/cert_database_nss_unittest.cc | 116 | ||||
-rw-r--r-- | net/base/net_error_list.h | 7 | ||||
-rw-r--r-- | net/net.gyp | 10 | ||||
-rw-r--r-- | net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp | 397 | ||||
-rw-r--r-- | net/third_party/mozilla_security_manager/nsPKCS12Blob.h | 73 |
7 files changed, 640 insertions, 1 deletions
diff --git a/net/base/cert_database.h b/net/base/cert_database.h index 9621e45..a264f19 100644 --- a/net/base/cert_database.h +++ b/net/base/cert_database.h @@ -6,11 +6,17 @@ #define NET_BASE_CERT_DATABASE_H_ #pragma once +#include <string> +#include <vector> + #include "base/basictypes.h" +#include "base/string16.h" +#include "base/ref_counted.h" namespace net { class X509Certificate; +typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; // This class provides functions to manipulate the local // certificate store. @@ -32,6 +38,19 @@ class CertDatabase { // the platform cert database, or possibly other network error codes. int AddUserCert(X509Certificate* cert); +#if defined(USE_NSS) + // Import certificates and private keys from PKCS #12 blob. + // Returns OK or a network error code such as ERR_PKCS12_IMPORT_BAD_PASSWORD + // or ERR_PKCS12_IMPORT_ERROR. + int ImportFromPKCS12(const std::string& data, const string16& password); + + // Export the given certificates and private keys into a PKCS #12 blob, + // storing into |output|. + // Returns the number of certificates successfully exported. + int ExportToPKCS12(const CertificateList& certs, const string16& password, + std::string* output); +#endif + private: DISALLOW_COPY_AND_ASSIGN(CertDatabase); }; diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc index 98930ff..e314afa 100644 --- a/net/base/cert_database_nss.cc +++ b/net/base/cert_database_nss.cc @@ -13,15 +13,20 @@ #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() #include "base/logging.h" -#include "base/scoped_ptr.h" #include "base/nss_util.h" +#include "base/scoped_ptr.h" #include "net/base/net_errors.h" #include "net/base/x509_certificate.h" +#include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" + +// PSM = Mozilla's Personal Security Manager. +namespace psm = mozilla_security_manager; namespace net { CertDatabase::CertDatabase() { base::EnsureNSSInit(); + psm::EnsurePKCS12Init(); } int CertDatabase::CheckUserCert(X509Certificate* cert_obj) { @@ -85,4 +90,16 @@ int CertDatabase::AddUserCert(X509Certificate* cert_obj) { return OK; } +int CertDatabase::ImportFromPKCS12( + const std::string& data, const string16& password) { + return psm::nsPKCS12Blob_Import(data.data(), data.size(), password); +} + +int CertDatabase::ExportToPKCS12( + const CertificateList& certs, + const string16& password, + std::string* output) { + return psm::nsPKCS12Blob_Export(output, certs, password); +} + } // namespace net diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc new file mode 100644 index 0000000..f25b043 --- /dev/null +++ b/net/base/cert_database_nss_unittest.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <cert.h> +#include <pk11pub.h> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/nss_util.h" +#include "base/nss_util_internal.h" +#include "base/path_service.h" +#include "base/scoped_temp_dir.h" +#include "base/string_util.h" +#include "net/base/cert_database.h" +#include "net/base/net_errors.h" +#include "net/base/x509_certificate.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +// Returns a FilePath object representing the src/net/data/ssl/certificates +// directory in the source tree. +FilePath GetTestCertsDirectory() { + FilePath certs_dir; + PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir); + certs_dir = certs_dir.AppendASCII("net"); + certs_dir = certs_dir.AppendASCII("data"); + certs_dir = certs_dir.AppendASCII("ssl"); + certs_dir = certs_dir.AppendASCII("certificates"); + return certs_dir; +} + +} // namespace + + +class CertDatabaseNSSTest : public testing::Test { + public: + virtual void SetUp() { + ASSERT_TRUE(temp_db_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + base::OpenTestNSSDB(temp_db_dir_.path(), "CertDatabaseNSSTest db")); + } + virtual void TearDown() { + base::CloseTestNSSDB(); + } + private: + ScopedTempDir temp_db_dir_; +}; + +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) { + PK11SlotInfo* slot = base::GetDefaultNSSKeySlot(); + CertDatabase cert_db; + + CERTCertList* cert_list = PK11_ListCertsInSlot(slot); + // Test db should be empty at start of test. + EXPECT_TRUE(CERT_LIST_END(CERT_LIST_HEAD(cert_list), cert_list)); + CERT_DestroyCertList(cert_list); + + FilePath cert_path = GetTestCertsDirectory().AppendASCII("client.p12"); + std::string cert_data; + ASSERT_TRUE(file_util::ReadFileToString(cert_path, &cert_data)); + EXPECT_EQ(ERR_PKCS12_IMPORT_BAD_PASSWORD, + cert_db.ImportFromPKCS12(cert_data, ASCIIToUTF16(""))); + + + cert_list = PK11_ListCertsInSlot(slot); + // Test db should still be empty. + EXPECT_TRUE(CERT_LIST_END(CERT_LIST_HEAD(cert_list), cert_list)); + CERT_DestroyCertList(cert_list); + + PK11_FreeSlot(slot); +} + +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AndExportAgain) { + PK11SlotInfo* slot = base::GetDefaultNSSKeySlot(); + CertDatabase cert_db; + + CERTCertList* cert_list = PK11_ListCertsInSlot(slot); + // Test db should be empty at start of test. + EXPECT_TRUE(CERT_LIST_END(CERT_LIST_HEAD(cert_list), cert_list)); + CERT_DestroyCertList(cert_list); + + FilePath cert_path = GetTestCertsDirectory().AppendASCII("client.p12"); + std::string cert_data; + ASSERT_TRUE(file_util::ReadFileToString(cert_path, &cert_data)); + EXPECT_EQ(OK, cert_db.ImportFromPKCS12(cert_data, ASCIIToUTF16("12345"))); + + cert_list = PK11_ListCertsInSlot(slot); + // Test db should be empty at start of test. + ASSERT_FALSE(CERT_LIST_END(CERT_LIST_HEAD(cert_list), cert_list)); + scoped_refptr<X509Certificate> cert( + X509Certificate::CreateFromHandle( + CERT_LIST_HEAD(cert_list)->cert, + X509Certificate::SOURCE_LONE_CERT_IMPORT, + X509Certificate::OSCertHandles())); + CERT_DestroyCertList(cert_list); + + EXPECT_EQ("testusercert", + cert->subject().common_name); + + // TODO(mattm): move export test to seperate test case? + CertificateList certs; + certs.push_back(cert); + std::string exported_data; + EXPECT_EQ(1, cert_db.ExportToPKCS12(certs, ASCIIToUTF16("exportpw"), + &exported_data)); + ASSERT_LT(0U, exported_data.size()); + // TODO(mattm): further verification of exported data? + + PK11_FreeSlot(slot); +} + +} // namespace net diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 53849631..1a0e242 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -16,6 +16,7 @@ // 400-499 Cache errors // 500-599 ? // 600-699 FTP errors +// 700-799 Certificate manager errors // // An asynchronous IO operation is not yet complete. This usually does not @@ -420,3 +421,9 @@ NET_ERROR(FTP_COMMAND_NOT_SUPPORTED, -606) // order. // FTP response code 503. NET_ERROR(FTP_BAD_COMMAND_SEQUENCE, -607) + +// PKCS #12 import failed due to incorrect password. +NET_ERROR(PKCS12_IMPORT_BAD_PASSWORD, -701) + +// PKCS #12 import failed due to other error. +NET_ERROR(PKCS12_IMPORT_FAILED, -702) diff --git a/net/net.gyp b/net/net.gyp index b9bda56..4cb3225 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -185,6 +185,8 @@ 'base/x509_cert_types_mac.cc', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', + 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp', + 'third_party/mozilla_security_manager/nsPKCS12Blob.h', ], 'export_dependent_settings': [ '../base/base.gyp:base', @@ -205,6 +207,8 @@ 'base/x509_certificate_nss.cc', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', + 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp', + 'third_party/mozilla_security_manager/nsPKCS12Blob.h', ], }, ], @@ -666,6 +670,7 @@ 'msvs_guid': 'E99DA267-BE90-4F45-88A1-6919DB2C7567', 'sources': [ 'base/address_list_unittest.cc', + 'base/cert_database_nss_unittest.cc', 'base/cookie_monster_unittest.cc', 'base/data_url_unittest.cc', 'base/directory_lister_unittest.cc', @@ -814,6 +819,11 @@ 'base/sdch_filter_unittest.cc', ], }, + { # else: OS is not in the above list + 'sources!': [ + 'base/cert_database_nss_unittest.cc', + ], + } ], ['OS == "linux"', { 'conditions': [ diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp new file mode 100644 index 0000000..ab20b22 --- /dev/null +++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp @@ -0,0 +1,397 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" + +#include <pk11pub.h> +#include <pkcs12.h> +#include <p12plcy.h> +#include <secerr.h> + +#include "base/logging.h" +#include "base/nss_util_internal.h" +#include "base/string_util.h" +#include "net/base/net_errors.h" +#include "net/base/x509_certificate.h" + +namespace mozilla_security_manager { + +namespace { + +// unicodeToItem +// +// 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? +void unicodeToItem(const PRUnichar *uni, SECItem *item) +{ + int len = 0; + while (uni[len++] != 0); + SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); +#ifdef IS_LITTLE_ENDIAN + int i = 0; + for (i=0; i<len; i++) { + item->data[2*i ] = (unsigned char )(uni[i] << 8); + item->data[2*i+1] = (unsigned char )(uni[i]); + } +#else + memcpy(item->data, uni, item->len); +#endif +} + +// write_export_data +// write bytes to the exported PKCS#12 data buffer +void write_export_data(void* arg, const char* buf, unsigned long len) { + std::string* dest = reinterpret_cast<std::string*>(arg); + dest->append(buf, len); +} + +// nickname_collision +// what to do when the nickname collides with one already in the db. +// Based on P12U_NicknameCollisionCallback from nss/cmd/pk12util/pk12util.c +SECItem* PR_CALLBACK +nickname_collision(SECItem *old_nick, PRBool *cancel, void *wincx) +{ + char *nick = NULL; + SECItem *ret_nick = NULL; + CERTCertificate* cert = (CERTCertificate*)wincx; + + if (!cancel || !cert) { + // pk12util calls this error user cancelled? + return NULL; + } + + if (!old_nick) + LOG(INFO) << "no nickname for cert in PKCS12 file."; + + nick = CERT_MakeCANickname(cert); + if (!nick) { + return NULL; + } + + if(old_nick && old_nick->data && old_nick->len && + PORT_Strlen(nick) == old_nick->len && + !PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) { + PORT_Free(nick); + PORT_SetError(SEC_ERROR_IO); + return NULL; + } + + LOG(INFO) << "using nickname " << nick; + ret_nick = PORT_ZNew(SECItem); + if(ret_nick == NULL) { + PORT_Free(nick); + return NULL; + } + + ret_nick->data = (unsigned char *)nick; + ret_nick->len = PORT_Strlen(nick); + + return ret_nick; +} + +// pip_ucs2_ascii_conversion_fn +// required to be set by NSS (to do PKCS#12), but since we've already got +// unicode make this a no-op. +PRBool +pip_ucs2_ascii_conversion_fn(PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes) +{ + CHECK_GE(maxOutBufLen, inBufLen); + // do a no-op, since I've already got unicode. Hah! + *outBufLen = inBufLen; + memcpy(outBuf, inBuf, inBufLen); + return PR_TRUE; +} + +// Based on nsPKCS12Blob::ImportFromFileHelper. +int +nsPKCS12Blob_ImportHelper(const char* pkcs12_data, + size_t pkcs12_len, + const string16& password, + bool try_zero_length_secitem, + PK11SlotInfo *slot) +{ + DCHECK(pkcs12_data); + DCHECK(slot); + int import_result = net::ERR_PKCS12_IMPORT_FAILED; + SECStatus srv = SECSuccess; + SEC_PKCS12DecoderContext *dcx = NULL; + SECItem unicodePw; + unicodePw.type = siBuffer; + unicodePw.len = 0; + unicodePw.data = NULL; + if (!try_zero_length_secitem) { + unicodeToItem(password.c_str(), &unicodePw); + } + + // initialize the decoder + dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, + // wincx + NULL, + // dOpen, dClose, dRead, dWrite, dArg: NULL + // specifies default impl using memory buffer. + NULL, NULL, NULL, NULL, NULL); + if (!dcx) { + srv = SECFailure; + goto finish; + } + // feed input to the decoder + srv = SEC_PKCS12DecoderUpdate(dcx, + (unsigned char*)pkcs12_data, + pkcs12_len); + if (srv) goto finish; + // verify the blob + srv = SEC_PKCS12DecoderVerify(dcx); + if (srv) goto finish; + // validate bags + srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); + if (srv) goto finish; + // import cert and key + srv = SEC_PKCS12DecoderImportBags(dcx); + if (srv) goto finish; + import_result = net::OK; +finish: + // If srv != SECSuccess, NSS probably set a specific error code. + // We should use that error code instead of inventing a new one + // for every error possible. + if (srv != SECSuccess) { + if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) { + import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD; + } + else + { + LOG(ERROR) << "PKCS#12 import failed with error " << PORT_GetError(); + import_result = net::ERR_PKCS12_IMPORT_FAILED; + } + } + // finish the decoder + if (dcx) + SEC_PKCS12DecoderFinish(dcx); + SECITEM_ZfreeItem(&unicodePw, PR_FALSE); + return import_result; +} + +PRBool +isExtractable(SECKEYPrivateKey *privKey) +{ + SECItem value; + PRBool isExtractable = PR_FALSE; + SECStatus rv; + + rv=PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, &value); + if (rv != SECSuccess) { + return PR_FALSE; + } + if ((value.len == 1) && (value.data != NULL)) { + isExtractable = !!(*(CK_BBOOL*)value.data); + } + SECITEM_FreeItem(&value, PR_FALSE); + return isExtractable; +} + +class PKCS12InitSingleton { + public: + // From the PKCS#12 section of nsNSSComponent::InitializeNSS in + // nsNSSComponent.cpp. + PKCS12InitSingleton() { + // Enable ciphers for PKCS#12 + SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); + + // Set no-op ascii-ucs2 conversion function to work around weird NSS + // interface. Thankfully, PKCS12 appears to be the only thing in NSS that + // uses PORT_UCS2_ASCIIConversion, so this doesn't break anything else. + PORT_SetUCS2_ASCIIConversionFunction(pip_ucs2_ascii_conversion_fn); + } +}; + +} // namespace + +void EnsurePKCS12Init() { + Singleton<PKCS12InitSingleton>::get(); +} + +// Based on nsPKCS12Blob::ImportFromFile. +int nsPKCS12Blob_Import(const char* pkcs12_data, + size_t pkcs12_len, + const string16& password) { + PK11SlotInfo *slot = base::GetDefaultNSSKeySlot(); + if (!slot) { + LOG(ERROR) << "Couldn't get Internal key slot!"; + return net::ERR_PKCS12_IMPORT_FAILED; + } + + int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, false, + slot); + + // When the user entered a zero length password: + // An empty password should be represented as an empty + // string (a SECItem that contains a single terminating + // NULL UTF16 character), but some applications use a + // zero length SECItem. + // We try both variations, zero length item and empty string, + // without giving a user prompt when trying the different empty password flavors. + if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.size() == 0) { + rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, true, + slot); + } + + PK11_FreeSlot(slot); + return rv; +} + +// Based on nsPKCS12Blob::ExportToFile +// +// Having already loaded the certs, form them into a blob (loading the keys +// also), encode the blob, and stuff it into the file. +// +// TODO: handle slots correctly +// mirror "slotToUse" behavior from PSM 1.x +// verify the cert array to start off with? +// set appropriate error codes +int +nsPKCS12Blob_Export(std::string* output, + const net::CertificateList& certs, + const string16& password) +{ + int return_count = 0; + SECStatus srv = SECSuccess; + SEC_PKCS12ExportContext *ecx = NULL; + SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL; + SECItem unicodePw; + unicodePw.type = siBuffer; + unicodePw.len = 0; + unicodePw.data = NULL; + + int numCertsExported = 0; + + // get file password (unicode) + unicodeToItem(password.c_str(), &unicodePw); + + // what about slotToUse in psm 1.x ??? + // create export context + ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL); + if (!ecx) { + srv = SECFailure; + goto finish; + } + // add password integrity + srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1); + if (srv) goto finish; + + for (size_t i=0; i<certs.size(); i++) { + DCHECK(certs[i]); + CERTCertificate* nssCert = certs[i]->os_cert_handle(); + DCHECK(nssCert); + + // We can only successfully export certs that are on + // internal token. Most, if not all, smart card vendors + // won't let you extract the private key (in any way + // shape or form) from the card. So let's punt if + // the cert is not in the internal db. + if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) { + // we aren't the internal token, see if the key is extractable. + SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot, + nssCert, + NULL /* wincx */); + + if (privKey) { + PRBool privKeyIsExtractable = isExtractable(privKey); + + SECKEY_DestroyPrivateKey(privKey); + + if (!privKeyIsExtractable) { + LOG(ERROR) << "private key not extractable"; + // TODO(mattm): firefox has a notification dialog about trying to + // export from a smartcard. I don't think we support smartcards, so + // we can ignore that for now. + continue; + } + } + } + + // XXX this is why, to verify the slot is the same + // PK11_FindObjectForCert(nssCert, NULL, slot); + // create the cert and key safes + keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx); + if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { + certSafe = keySafe; + } else { + certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); + } + if (!certSafe || !keySafe) { + LOG(ERROR) << "!certSafe || !keySafe " << certSafe << " " << keySafe; + srv = SECFailure; + goto finish; + } + // add the cert and key to the blob + srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert, + CERT_GetDefaultCertDB(), + keySafe, NULL, PR_TRUE, &unicodePw, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC); + if (srv) goto finish; + ++numCertsExported; + } + + if (!numCertsExported) goto finish; + + // encode and write + srv = SEC_PKCS12Encode(ecx, write_export_data, output); + if (srv) goto finish; + return_count = numCertsExported; +finish: + if (srv) + LOG(ERROR) << "PKCS#12 export failed with error " << PORT_GetError(); + if (ecx) + SEC_PKCS12DestroyExportContext(ecx); + SECITEM_ZfreeItem(&unicodePw, PR_FALSE); + return return_count; +} + +} // namespace mozilla_security_manager diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.h b/net/third_party/mozilla_security_manager/nsPKCS12Blob.h new file mode 100644 index 0000000..95b8d46 --- /dev/null +++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.h @@ -0,0 +1,73 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef NET_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSPKCS12BLOB_H_ +#define NET_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSPKCS12BLOB_H_ + +#include <string> +#include <vector> + +#include "base/string16.h" +#include "base/ref_counted.h" + +typedef struct CERTCertificateStr CERTCertificate; +namespace net { +class X509Certificate; +typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; +} // namespace net + +namespace mozilla_security_manager { + +// Initialize NSS PKCS#12 libs. +void EnsurePKCS12Init(); + +// Import certificate from PKCS#12 blob. +// Returns a net error code. +int nsPKCS12Blob_Import(const char* pkcs12_data, + size_t pkcs12_len, + const string16& password); + +// Export the given certificates into a PKCS#12 blob, storing into output. +// Returns the number of certificates exported. +// TODO(mattm): provide better error return status? +int nsPKCS12Blob_Export(std::string* output, + const net::CertificateList& certs, + const string16& password); + +} // namespace mozilla_security_manager + +#endif // NET_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSPKCS12BLOB_H_ |