| Index: net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
|
| diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
|
| deleted file mode 100644
|
| index 0cf3500c6d3ad71abb6ef859c1d99658a2abd080..0000000000000000000000000000000000000000
|
| --- a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
|
| +++ /dev/null
|
| @@ -1,488 +0,0 @@
|
| -/* ***** 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/lazy_instance.h"
|
| -#include "base/logging.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "crypto/nss_util_internal.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/cert/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)
|
| - VLOG(1) << "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;
|
| - }
|
| -
|
| - VLOG(1) << "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 base::string16& password,
|
| - bool is_extractable,
|
| - bool try_zero_length_secitem,
|
| - PK11SlotInfo *slot,
|
| - net::CertificateList* imported_certs)
|
| -{
|
| - DCHECK(pkcs12_data);
|
| - DCHECK(slot);
|
| - int import_result = net::ERR_PKCS12_IMPORT_FAILED;
|
| - 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;
|
| - 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 certificate and key
|
| - srv = SEC_PKCS12DecoderImportBags(dcx);
|
| - if (srv) goto finish;
|
| -
|
| - attribute_value.data = &attribute_data;
|
| - attribute_value.len = sizeof(attribute_data);
|
| -
|
| - 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;
|
| - }
|
| -
|
| - // Iterate through all the imported PKCS12 items and mark any accompanying
|
| - // private keys as non-extractable.
|
| - if (!is_extractable) {
|
| - SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert,
|
| - NULL); // wincx
|
| - if (privKey) {
|
| - // 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.
|
| - // We should use that error code instead of inventing a new one
|
| - // for every error possible.
|
| - if (srv != SECSuccess) {
|
| - int error = PORT_GetError();
|
| - LOG(ERROR) << "PKCS#12 import failed with error " << error;
|
| - switch (error) {
|
| - case SEC_ERROR_BAD_PASSWORD:
|
| - case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT:
|
| - import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD;
|
| - break;
|
| - case SEC_ERROR_PKCS12_INVALID_MAC:
|
| - import_result = net::ERR_PKCS12_IMPORT_INVALID_MAC;
|
| - break;
|
| - case SEC_ERROR_BAD_DER:
|
| - case SEC_ERROR_PKCS12_DECODING_PFX:
|
| - case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE:
|
| - import_result = net::ERR_PKCS12_IMPORT_INVALID_FILE;
|
| - break;
|
| - case SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM:
|
| - case SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE:
|
| - case SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM:
|
| - case SEC_ERROR_PKCS12_UNSUPPORTED_VERSION:
|
| - import_result = net::ERR_PKCS12_IMPORT_UNSUPPORTED;
|
| - break;
|
| - default:
|
| - import_result = net::ERR_PKCS12_IMPORT_FAILED;
|
| - break;
|
| - }
|
| - }
|
| - // Finish the decoder
|
| - if (dcx)
|
| - SEC_PKCS12DecoderFinish(dcx);
|
| - SECITEM_ZfreeItem(&unicodePw, PR_FALSE);
|
| - return import_result;
|
| -}
|
| -
|
| -
|
| -// Attempt to read the CKA_EXTRACTABLE attribute on a private key inside
|
| -// a token. On success, store the attribute in |extractable| and return
|
| -// SECSuccess.
|
| -SECStatus
|
| -isExtractable(SECKEYPrivateKey *privKey, PRBool *extractable)
|
| -{
|
| - SECItem value;
|
| - SECStatus rv;
|
| -
|
| - rv=PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, &value);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| -
|
| - if ((value.len == 1) && (value.data != NULL))
|
| - *extractable = !!(*(CK_BBOOL*)value.data);
|
| - else
|
| - rv = SECFailure;
|
| - SECITEM_FreeItem(&value, PR_FALSE);
|
| - return rv;
|
| -}
|
| -
|
| -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);
|
| - }
|
| -};
|
| -
|
| -// Leaky so it can be initialized on worker threads and because there is no
|
| -// cleanup necessary.
|
| -static base::LazyInstance<PKCS12InitSingleton>::Leaky g_pkcs12_init_singleton =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -
|
| -} // namespace
|
| -
|
| -void EnsurePKCS12Init() {
|
| - g_pkcs12_init_singleton.Get();
|
| -}
|
| -
|
| -// Based on nsPKCS12Blob::ImportFromFile.
|
| -int nsPKCS12Blob_Import(PK11SlotInfo* slot,
|
| - const char* pkcs12_data,
|
| - size_t pkcs12_len,
|
| - const base::string16& password,
|
| - bool is_extractable,
|
| - net::CertificateList* imported_certs) {
|
| -
|
| - int rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password,
|
| - is_extractable, false, slot,
|
| - imported_certs);
|
| -
|
| - // 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.empty()) {
|
| - rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password,
|
| - is_extractable, true, slot, imported_certs);
|
| - }
|
| - 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 base::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].get());
|
| - CERTCertificate* nssCert = certs[i]->os_cert_handle();
|
| - DCHECK(nssCert);
|
| -
|
| - // We only allow certificate and private key extraction if the corresponding
|
| - // CKA_EXTRACTABLE private key attribute is set to CK_TRUE. Most hardware
|
| - // tokens including smartcards enforce this behavior. An internal (soft)
|
| - // token may ignore this attribute (and hence still be able to export) but
|
| - // we still refuse to attempt an export.
|
| - // In addition, some tokens may not support this attribute, in which case
|
| - // we still attempt the export and let the token implementation dictate
|
| - // the export behavior.
|
| - if (nssCert->slot) {
|
| - SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot,
|
| - nssCert,
|
| - NULL); // wincx
|
| - if (privKey) {
|
| - PRBool privKeyIsExtractable = PR_FALSE;
|
| - SECStatus rv = isExtractable(privKey, &privKeyIsExtractable);
|
| - SECKEY_DestroyPrivateKey(privKey);
|
| -
|
| - if (rv == SECSuccess && !privKeyIsExtractable) {
|
| - LOG(ERROR) << "Private key is not extractable";
|
| - 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
|
|
|