2012-05-31 13:33:35 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-03-20 21:00:44 +03:00
|
|
|
|
2014-01-23 05:13:19 +04:00
|
|
|
#include "nsPKCS12Blob.h"
|
|
|
|
|
2016-04-20 11:14:22 +03:00
|
|
|
#include "ScopedNSSTypes.h"
|
2016-05-19 07:20:56 +03:00
|
|
|
#include "mozilla/Casting.h"
|
2016-04-20 11:14:22 +03:00
|
|
|
#include "nsCRT.h"
|
2016-05-07 10:58:12 +03:00
|
|
|
#include "nsCRTGlue.h"
|
2016-04-20 11:14:22 +03:00
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsICertificateDialogs.h"
|
|
|
|
#include "nsIDirectoryService.h"
|
2003-03-15 04:04:32 +03:00
|
|
|
#include "nsIFile.h"
|
2015-07-07 05:17:00 +03:00
|
|
|
#include "nsIInputStream.h"
|
2016-04-20 11:14:22 +03:00
|
|
|
#include "nsKeygenHandler.h" // For GetSlotWithMechanism
|
|
|
|
#include "nsNSSCertificate.h"
|
2001-05-02 03:23:23 +04:00
|
|
|
#include "nsNSSComponent.h"
|
2001-03-20 21:00:44 +03:00
|
|
|
#include "nsNSSHelper.h"
|
2003-01-18 17:03:00 +03:00
|
|
|
#include "nsNSSShutDown.h"
|
2016-04-20 11:14:22 +03:00
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsPK11TokenDB.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "pkix/pkixtypes.h"
|
|
|
|
#include "prmem.h"
|
|
|
|
#include "prprf.h"
|
2001-03-30 23:55:00 +04:00
|
|
|
#include "secerr.h"
|
2001-03-20 21:00:44 +03:00
|
|
|
|
2012-11-12 21:42:28 +04:00
|
|
|
using namespace mozilla;
|
2016-01-28 21:36:00 +03:00
|
|
|
extern LazyLogModule gPIPNSSLog;
|
2003-01-07 01:23:49 +03:00
|
|
|
|
2002-04-27 09:33:09 +04:00
|
|
|
#define PIP_PKCS12_TMPFILENAME NS_LITERAL_CSTRING(".pip_p12tmp")
|
2001-05-02 03:23:23 +04:00
|
|
|
#define PIP_PKCS12_BUFFER_SIZE 2048
|
2001-08-02 03:01:37 +04:00
|
|
|
#define PIP_PKCS12_RESTORE_OK 1
|
|
|
|
#define PIP_PKCS12_BACKUP_OK 2
|
|
|
|
#define PIP_PKCS12_USER_CANCELED 3
|
|
|
|
#define PIP_PKCS12_NOSMARTCARD_EXPORT 4
|
|
|
|
#define PIP_PKCS12_RESTORE_FAILED 5
|
|
|
|
#define PIP_PKCS12_BACKUP_FAILED 6
|
2001-08-22 08:05:45 +04:00
|
|
|
#define PIP_PKCS12_NSS_ERROR 7
|
2001-03-20 21:00:44 +03:00
|
|
|
|
2001-03-30 23:55:00 +04:00
|
|
|
// constructor
|
2001-06-19 09:34:47 +04:00
|
|
|
nsPKCS12Blob::nsPKCS12Blob():mCertArray(0),
|
2012-07-30 18:20:58 +04:00
|
|
|
mTmpFile(nullptr),
|
|
|
|
mDigest(nullptr),
|
|
|
|
mDigestIterator(nullptr),
|
2011-10-17 18:59:28 +04:00
|
|
|
mTokenSet(false)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2001-03-21 06:37:49 +03:00
|
|
|
mUIContext = new PipUIContext();
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
2001-03-30 23:55:00 +04:00
|
|
|
// destructor
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::~nsPKCS12Blob()
|
|
|
|
{
|
2006-01-10 05:51:24 +03:00
|
|
|
delete mDigestIterator;
|
|
|
|
delete mDigest;
|
bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin
nsPSMUITracker was problematic. Apparently it was originally intended to prevent
NSS shutdown while NSS-related UI operations were going on (such as choosing a
client certificate). However, when nsNSSComponent would receive the event that
told it to shutdown NSS, it would attempt to call
mShutdownObjectList->evaporateAllNSSResources(), which would call
mActivityState.restrictActivityToCurrentThread(), which failed if such a UI
operation was in progress. This actually prevented the important part of
evaporateAllNSSResources, which is the releasing of all NSS objects in use by
PSM objects. Importantly, nsNSSComponent didn't check for or handle this failure
and proceeded to call NSS_Shutdown(), leaving PSM in an inconsistent state where
it thought it was okay to keep using the NSS objects it had when in fact it
wasn't.
In any case, nsPSMUITracker isn't really necessary as long as we have the
nsNSSShutDownPreventionLock mechanism, which mostly works and is what we should
use instead (or not at all, if no such lock is needed for the operation being
performed (for example, if no NSS functions are being called)).
2015-10-17 00:31:57 +03:00
|
|
|
|
|
|
|
nsNSSShutDownPreventionLock locker;
|
|
|
|
if (isAlreadyShutDown()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-20 18:00:19 +03:00
|
|
|
shutdown(ShutdownCalledFrom::Object);
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// nsPKCS12Blob::SetToken
|
|
|
|
//
|
|
|
|
// Set the token to use for import/export
|
2003-02-04 04:37:23 +03:00
|
|
|
nsresult
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::SetToken(nsIPK11Token *token)
|
|
|
|
{
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin
nsPSMUITracker was problematic. Apparently it was originally intended to prevent
NSS shutdown while NSS-related UI operations were going on (such as choosing a
client certificate). However, when nsNSSComponent would receive the event that
told it to shutdown NSS, it would attempt to call
mShutdownObjectList->evaporateAllNSSResources(), which would call
mActivityState.restrictActivityToCurrentThread(), which failed if such a UI
operation was in progress. This actually prevented the important part of
evaporateAllNSSResources, which is the releasing of all NSS objects in use by
PSM objects. Importantly, nsNSSComponent didn't check for or handle this failure
and proceeded to call NSS_Shutdown(), leaving PSM in an inconsistent state where
it thought it was okay to keep using the NSS objects it had when in fact it
wasn't.
In any case, nsPSMUITracker isn't really necessary as long as we have the
nsNSSShutDownPreventionLock mechanism, which mostly works and is what we should
use instead (or not at all, if no such lock is needed for the operation being
performed (for example, if no NSS functions are being called)).
2015-10-17 00:31:57 +03:00
|
|
|
if (isAlreadyShutDown()) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
2003-02-04 04:37:23 +03:00
|
|
|
nsresult rv = NS_OK;
|
2001-06-19 09:29:56 +04:00
|
|
|
if (token) {
|
|
|
|
mToken = token;
|
|
|
|
} else {
|
|
|
|
PK11SlotInfo *slot;
|
bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin
nsPSMUITracker was problematic. Apparently it was originally intended to prevent
NSS shutdown while NSS-related UI operations were going on (such as choosing a
client certificate). However, when nsNSSComponent would receive the event that
told it to shutdown NSS, it would attempt to call
mShutdownObjectList->evaporateAllNSSResources(), which would call
mActivityState.restrictActivityToCurrentThread(), which failed if such a UI
operation was in progress. This actually prevented the important part of
evaporateAllNSSResources, which is the releasing of all NSS objects in use by
PSM objects. Importantly, nsNSSComponent didn't check for or handle this failure
and proceeded to call NSS_Shutdown(), leaving PSM in an inconsistent state where
it thought it was okay to keep using the NSS objects it had when in fact it
wasn't.
In any case, nsPSMUITracker isn't really necessary as long as we have the
nsNSSShutDownPreventionLock mechanism, which mostly works and is what we should
use instead (or not at all, if no such lock is needed for the operation being
performed (for example, if no NSS functions are being called)).
2015-10-17 00:31:57 +03:00
|
|
|
rv = GetSlotWithMechanism(CKM_RSA_PKCS, mUIContext, &slot, locker);
|
2001-06-19 09:29:56 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mToken = 0;
|
|
|
|
} else {
|
|
|
|
mToken = new nsPK11Token(slot);
|
2003-01-07 01:23:49 +03:00
|
|
|
PK11_FreeSlot(slot);
|
2001-06-19 09:29:56 +04:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mTokenSet = true;
|
2003-02-04 04:37:23 +03:00
|
|
|
return rv;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// nsPKCS12Blob::ImportFromFile
|
|
|
|
//
|
|
|
|
// Given a file handle, read a PKCS#12 blob from that file, decode it,
|
|
|
|
// and import the results into the token.
|
|
|
|
nsresult
|
2012-06-06 06:08:30 +04:00
|
|
|
nsPKCS12Blob::ImportFromFile(nsIFile *file)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
2003-02-04 04:37:23 +03:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
if (!mToken) {
|
|
|
|
if (!mTokenSet) {
|
2012-10-18 00:48:36 +04:00
|
|
|
rv = SetToken(nullptr); // Ask the user to pick a slot
|
2003-02-04 04:37:23 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
handleError(PIP_PKCS12_USER_CANCELED);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-06-19 09:29:56 +04:00
|
|
|
|
2003-02-04 04:37:23 +03:00
|
|
|
if (!mToken) {
|
|
|
|
handleError(PIP_PKCS12_RESTORE_FAILED);
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2001-06-19 09:29:56 +04:00
|
|
|
}
|
2003-02-04 04:37:23 +03:00
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
// init slot
|
2011-10-17 18:59:28 +04:00
|
|
|
rv = mToken->Login(true);
|
2002-08-27 00:31:03 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2005-11-11 16:28:56 +03:00
|
|
|
RetryReason wantRetry;
|
2002-08-27 00:31:03 +04:00
|
|
|
|
|
|
|
do {
|
2005-11-11 16:28:56 +03:00
|
|
|
rv = ImportFromFileHelper(file, im_standard_prompt, wantRetry);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && wantRetry == rr_auto_retry_empty_password_flavors)
|
|
|
|
{
|
|
|
|
rv = ImportFromFileHelper(file, im_try_zero_length_secitem, wantRetry);
|
|
|
|
}
|
2002-08-27 00:31:03 +04:00
|
|
|
}
|
2005-11-11 16:28:56 +03:00
|
|
|
while (NS_SUCCEEDED(rv) && (wantRetry != rr_do_not_retry));
|
2002-08-27 00:31:03 +04:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-06-06 06:08:30 +04:00
|
|
|
nsPKCS12Blob::ImportFromFileHelper(nsIFile *file,
|
2005-11-11 16:28:56 +03:00
|
|
|
nsPKCS12Blob::ImportMode aImportMode,
|
|
|
|
nsPKCS12Blob::RetryReason &aWantRetry)
|
2002-08-27 00:31:03 +04:00
|
|
|
{
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
2013-06-24 11:57:51 +04:00
|
|
|
nsresult rv = NS_OK;
|
2002-08-27 00:31:03 +04:00
|
|
|
SECStatus srv = SECSuccess;
|
2012-10-18 00:48:36 +04:00
|
|
|
SEC_PKCS12DecoderContext *dcx = nullptr;
|
2002-08-27 00:31:03 +04:00
|
|
|
SECItem unicodePw;
|
|
|
|
|
2016-05-10 04:02:40 +03:00
|
|
|
UniquePK11SlotInfo slot;
|
2002-08-27 00:31:03 +04:00
|
|
|
nsXPIDLString tokenName;
|
2012-10-18 00:48:36 +04:00
|
|
|
unicodePw.data = nullptr;
|
2016-05-10 04:02:40 +03:00
|
|
|
|
2005-11-11 16:28:56 +03:00
|
|
|
aWantRetry = rr_do_not_retry;
|
2002-08-27 00:31:03 +04:00
|
|
|
|
2005-11-11 16:28:56 +03:00
|
|
|
if (aImportMode == im_try_zero_length_secitem)
|
|
|
|
{
|
|
|
|
unicodePw.len = 0;
|
2001-05-02 03:23:23 +04:00
|
|
|
}
|
2005-11-11 16:28:56 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// get file password (unicode)
|
|
|
|
rv = getPKCS12FilePassword(&unicodePw);
|
|
|
|
if (NS_FAILED(rv)) goto finish;
|
2012-10-18 00:48:36 +04:00
|
|
|
if (!unicodePw.data) {
|
2005-11-11 16:28:56 +03:00
|
|
|
handleError(PIP_PKCS12_USER_CANCELED);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2016-05-10 04:02:40 +03:00
|
|
|
|
2001-06-19 09:29:56 +04:00
|
|
|
mToken->GetTokenName(getter_Copies(tokenName));
|
2004-11-05 18:23:35 +03:00
|
|
|
{
|
|
|
|
NS_ConvertUTF16toUTF8 tokenNameCString(tokenName);
|
2016-05-10 04:02:40 +03:00
|
|
|
slot = UniquePK11SlotInfo(PK11_FindSlotByName(tokenNameCString.get()));
|
2004-11-05 18:23:35 +03:00
|
|
|
}
|
2001-06-19 09:29:56 +04:00
|
|
|
if (!slot) {
|
|
|
|
srv = SECFailure;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
// initialize the decoder
|
2016-05-10 04:02:40 +03:00
|
|
|
dcx = SEC_PKCS12DecoderStart(&unicodePw, slot.get(), nullptr,
|
2001-03-20 21:00:44 +03:00
|
|
|
digest_open, digest_close,
|
|
|
|
digest_read, digest_write,
|
|
|
|
this);
|
2001-05-02 03:23:23 +04:00
|
|
|
if (!dcx) {
|
|
|
|
srv = SECFailure;
|
|
|
|
goto finish;
|
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
// read input file and feed it to the decoder
|
|
|
|
rv = inputToDecoder(dcx, file);
|
2002-08-27 00:31:03 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
if (NS_ERROR_ABORT == rv) {
|
|
|
|
// inputToDecoder indicated a NSS error
|
|
|
|
srv = SECFailure;
|
|
|
|
}
|
|
|
|
goto finish;
|
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
// verify the blob
|
|
|
|
srv = SEC_PKCS12DecoderVerify(dcx);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
2001-03-20 21:00:44 +03:00
|
|
|
// validate bags
|
|
|
|
srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
2001-03-20 21:00:44 +03:00
|
|
|
// import cert and key
|
|
|
|
srv = SEC_PKCS12DecoderImportBags(dcx);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
2001-03-20 21:00:44 +03:00
|
|
|
// Later - check to see if this should become default email cert
|
2001-05-02 03:23:23 +04:00
|
|
|
handleError(PIP_PKCS12_RESTORE_OK);
|
2001-03-20 21:00:44 +03:00
|
|
|
finish:
|
2001-08-22 08:05:45 +04:00
|
|
|
// 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) {
|
2002-08-27 00:31:03 +04:00
|
|
|
if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) {
|
2014-01-04 19:02:17 +04:00
|
|
|
if (unicodePw.len == sizeof(char16_t))
|
2005-11-11 16:28:56 +03:00
|
|
|
{
|
|
|
|
// no password chars available,
|
|
|
|
// unicodeToItem allocated space for the trailing zero character only.
|
|
|
|
aWantRetry = rr_auto_retry_empty_password_flavors;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aWantRetry = rr_bad_password;
|
|
|
|
handleError(PIP_PKCS12_NSS_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
handleError(PIP_PKCS12_NSS_ERROR);
|
2002-08-27 00:31:03 +04:00
|
|
|
}
|
2016-05-10 04:02:40 +03:00
|
|
|
} else if (NS_FAILED(rv)) {
|
2001-08-02 03:01:37 +04:00
|
|
|
handleError(PIP_PKCS12_RESTORE_FAILED);
|
2001-03-30 23:55:00 +04:00
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
// finish the decoder
|
|
|
|
if (dcx)
|
|
|
|
SEC_PKCS12DecoderFinish(dcx);
|
2011-10-17 18:59:28 +04:00
|
|
|
SECITEM_ZfreeItem(&unicodePw, false);
|
2001-05-02 03:23:23 +04:00
|
|
|
return NS_OK;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2006-01-10 05:29:25 +03:00
|
|
|
isExtractable(SECKEYPrivateKey *privKey)
|
|
|
|
{
|
2016-08-13 16:45:00 +03:00
|
|
|
ScopedAutoSECItem value;
|
|
|
|
SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey,
|
|
|
|
CKA_EXTRACTABLE, &value);
|
2006-01-10 05:29:25 +03:00
|
|
|
if (rv != SECSuccess) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2006-01-10 05:29:25 +03:00
|
|
|
}
|
2016-08-13 16:45:00 +03:00
|
|
|
|
|
|
|
bool isExtractable = false;
|
2012-10-18 00:48:36 +04:00
|
|
|
if ((value.len == 1) && value.data) {
|
2008-09-26 02:34:22 +04:00
|
|
|
isExtractable = !!(*(CK_BBOOL*)value.data);
|
2006-01-10 05:29:25 +03:00
|
|
|
}
|
|
|
|
return isExtractable;
|
|
|
|
}
|
2016-08-13 16:45:00 +03:00
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
// 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?
|
|
|
|
// open output file as nsIFileStream object?
|
|
|
|
// set appropriate error codes
|
|
|
|
nsresult
|
2012-06-06 06:08:30 +04:00
|
|
|
nsPKCS12Blob::ExportToFile(nsIFile *file,
|
2001-03-30 23:55:00 +04:00
|
|
|
nsIX509Cert **certs, int numCerts)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
2001-05-02 03:23:23 +04:00
|
|
|
nsresult rv;
|
2001-08-15 05:34:36 +04:00
|
|
|
SECStatus srv = SECSuccess;
|
2012-10-18 00:48:36 +04:00
|
|
|
SEC_PKCS12ExportContext *ecx = nullptr;
|
|
|
|
SEC_PKCS12SafeInfo *certSafe = nullptr, *keySafe = nullptr;
|
2001-03-20 21:00:44 +03:00
|
|
|
SECItem unicodePw;
|
2002-05-08 03:07:19 +04:00
|
|
|
nsAutoString filePath;
|
2001-03-30 23:55:00 +04:00
|
|
|
int i;
|
2012-06-06 06:08:30 +04:00
|
|
|
nsCOMPtr<nsIFile> localFileRef;
|
2001-06-19 09:29:56 +04:00
|
|
|
NS_ASSERTION(mToken, "Need to set the token before exporting");
|
2001-03-20 21:00:44 +03:00
|
|
|
// init slot
|
2001-08-02 03:01:37 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool InformedUserNoSmartcardBackup = false;
|
2001-08-02 03:01:37 +04:00
|
|
|
int numCertsExported = 0;
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
rv = mToken->Login(true);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (NS_FAILED(rv)) goto finish;
|
2001-03-20 21:00:44 +03:00
|
|
|
// get file password (unicode)
|
2012-10-18 00:48:36 +04:00
|
|
|
unicodePw.data = nullptr;
|
2001-03-20 21:00:44 +03:00
|
|
|
rv = newPKCS12FilePassword(&unicodePw);
|
2001-05-02 03:23:23 +04:00
|
|
|
if (NS_FAILED(rv)) goto finish;
|
2012-10-18 00:48:36 +04:00
|
|
|
if (!unicodePw.data) {
|
2001-05-02 03:23:23 +04:00
|
|
|
handleError(PIP_PKCS12_USER_CANCELED);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
// what about slotToUse in psm 1.x ???
|
2001-03-30 23:55:00 +04:00
|
|
|
// create export context
|
2012-10-18 00:48:36 +04:00
|
|
|
ecx = SEC_PKCS12CreateExportContext(nullptr, nullptr, nullptr /*slot*/, nullptr);
|
2001-05-02 03:23:23 +04:00
|
|
|
if (!ecx) {
|
|
|
|
srv = SECFailure;
|
|
|
|
goto finish;
|
|
|
|
}
|
2001-03-30 23:55:00 +04:00
|
|
|
// add password integrity
|
2001-03-20 21:00:44 +03:00
|
|
|
srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
2001-03-20 21:00:44 +03:00
|
|
|
for (i=0; i<numCerts; i++) {
|
2001-03-30 23:55:00 +04:00
|
|
|
nsNSSCertificate *cert = (nsNSSCertificate *)certs[i];
|
|
|
|
// get it as a CERTCertificate XXX
|
2016-04-20 11:14:22 +03:00
|
|
|
UniqueCERTCertificate nssCert(cert->GetCert());
|
2001-05-02 03:23:23 +04:00
|
|
|
if (!nssCert) {
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
goto finish;
|
|
|
|
}
|
2001-06-19 09:29:56 +04:00
|
|
|
// 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)) {
|
2006-01-10 05:29:25 +03:00
|
|
|
// we aren't the internal token, see if the key is extractable.
|
|
|
|
SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot,
|
2014-01-23 05:13:19 +04:00
|
|
|
nssCert.get(), this);
|
2006-01-10 05:29:25 +03:00
|
|
|
|
|
|
|
if (privKey) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool privKeyIsExtractable = isExtractable(privKey);
|
2006-01-10 05:29:25 +03:00
|
|
|
|
|
|
|
SECKEY_DestroyPrivateKey(privKey);
|
|
|
|
|
|
|
|
if (!privKeyIsExtractable) {
|
|
|
|
if (!InformedUserNoSmartcardBackup) {
|
2011-10-17 18:59:28 +04:00
|
|
|
InformedUserNoSmartcardBackup = true;
|
2006-01-10 05:29:25 +03:00
|
|
|
handleError(PIP_PKCS12_NOSMARTCARD_EXPORT);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2001-08-02 03:01:37 +04:00
|
|
|
}
|
2001-06-19 09:29:56 +04:00
|
|
|
}
|
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
// XXX this is why, to verify the slot is the same
|
2012-10-18 00:48:36 +04:00
|
|
|
// PK11_FindObjectForCert(nssCert, nullptr, slot);
|
2001-03-30 23:55:00 +04:00
|
|
|
// create the cert and key safes
|
2001-03-20 21:00:44 +03:00
|
|
|
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);
|
|
|
|
}
|
2001-05-02 03:23:23 +04:00
|
|
|
if (!certSafe || !keySafe) {
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
goto finish;
|
|
|
|
}
|
2001-03-30 23:55:00 +04:00
|
|
|
// add the cert and key to the blob
|
2014-01-23 05:13:19 +04:00
|
|
|
srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, nullptr, nssCert.get(),
|
2001-03-30 23:55:00 +04:00
|
|
|
CERT_GetDefaultCertDB(), // XXX
|
2012-10-18 00:48:36 +04:00
|
|
|
keySafe, nullptr, true, &unicodePw,
|
2001-03-20 21:00:44 +03:00
|
|
|
SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
|
|
|
// cert was dup'ed, so release it
|
2001-08-02 03:01:37 +04:00
|
|
|
++numCertsExported;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
2001-08-02 03:01:37 +04:00
|
|
|
|
|
|
|
if (!numCertsExported) goto finish;
|
|
|
|
|
2001-03-30 23:55:00 +04:00
|
|
|
// prepare the instance to write to an export file
|
2012-10-18 00:48:36 +04:00
|
|
|
this->mTmpFile = nullptr;
|
2002-04-27 09:33:09 +04:00
|
|
|
file->GetPath(filePath);
|
2001-06-29 08:35:04 +04:00
|
|
|
// Use the nsCOMPtr var localFileRef so that
|
2012-06-06 06:08:30 +04:00
|
|
|
// the reference to the nsIFile we create gets released as soon as
|
2001-06-29 08:35:04 +04:00
|
|
|
// we're out of scope, ie when this function exits.
|
2011-10-17 18:59:28 +04:00
|
|
|
if (filePath.RFind(".p12", true, -1, 4) < 0) {
|
2001-06-29 08:35:04 +04:00
|
|
|
// We're going to add the .p12 extension to the file name just like
|
2012-06-06 06:08:30 +04:00
|
|
|
// Communicator used to. We create a new nsIFile and initialize
|
2001-06-29 08:35:04 +04:00
|
|
|
// it with the new patch.
|
2004-06-17 04:13:25 +04:00
|
|
|
filePath.AppendLiteral(".p12");
|
2001-06-29 08:35:04 +04:00
|
|
|
localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
|
|
|
|
if (NS_FAILED(rv)) goto finish;
|
2002-04-27 09:33:09 +04:00
|
|
|
localFileRef->InitWithPath(filePath);
|
2001-06-29 08:35:04 +04:00
|
|
|
file = localFileRef;
|
2001-06-24 23:15:59 +04:00
|
|
|
}
|
2001-06-29 08:35:04 +04:00
|
|
|
rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664,
|
|
|
|
&mTmpFile);
|
|
|
|
if (NS_FAILED(rv) || !this->mTmpFile) goto finish;
|
2001-03-30 23:55:00 +04:00
|
|
|
// encode and write
|
2001-03-20 21:00:44 +03:00
|
|
|
srv = SEC_PKCS12Encode(ecx, write_export_file, this);
|
2001-03-30 23:55:00 +04:00
|
|
|
if (srv) goto finish;
|
2001-05-02 03:23:23 +04:00
|
|
|
handleError(PIP_PKCS12_BACKUP_OK);
|
2001-03-20 21:00:44 +03:00
|
|
|
finish:
|
2001-05-02 03:23:23 +04:00
|
|
|
if (NS_FAILED(rv) || srv != SECSuccess) {
|
2001-08-02 03:01:37 +04:00
|
|
|
handleError(PIP_PKCS12_BACKUP_FAILED);
|
2001-03-30 23:55:00 +04:00
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
if (ecx)
|
|
|
|
SEC_PKCS12DestroyExportContext(ecx);
|
2001-06-21 02:41:29 +04:00
|
|
|
if (this->mTmpFile) {
|
|
|
|
PR_Close(this->mTmpFile);
|
2012-10-18 00:48:36 +04:00
|
|
|
this->mTmpFile = nullptr;
|
2001-06-21 02:41:29 +04:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
SECITEM_ZfreeItem(&unicodePw, false);
|
2001-03-20 21:00:44 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// private members
|
|
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// unicodeToItem
|
|
|
|
//
|
|
|
|
// For the NSS PKCS#12 library, must convert PRUnichars (shorts) to
|
|
|
|
// a buffer of octets. Must handle byte order correctly.
|
2016-05-07 10:58:12 +03:00
|
|
|
nsresult
|
2014-01-04 19:02:17 +04:00
|
|
|
nsPKCS12Blob::unicodeToItem(const char16_t *uni, SECItem *item)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2016-05-07 10:58:12 +03:00
|
|
|
uint32_t len = NS_strlen(uni) + 1;
|
|
|
|
if (!SECITEM_AllocItem(nullptr, item, sizeof(char16_t) * len)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
2016-05-07 10:58:12 +03:00
|
|
|
|
|
|
|
mozilla::NativeEndian::copyAndSwapToBigEndian(item->data, uni, len);
|
|
|
|
|
|
|
|
return NS_OK;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// newPKCS12FilePassword
|
|
|
|
//
|
2001-03-30 23:55:00 +04:00
|
|
|
// Launch a dialog requesting the user for a new PKCS#12 file passowrd.
|
|
|
|
// Handle user canceled by returning null password (caller must catch).
|
2001-03-20 21:00:44 +03:00
|
|
|
nsresult
|
|
|
|
nsPKCS12Blob::newPKCS12FilePassword(SECItem *unicodePw)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
2002-09-24 00:17:16 +04:00
|
|
|
nsAutoString password;
|
2001-03-20 21:00:44 +03:00
|
|
|
nsCOMPtr<nsICertificateDialogs> certDialogs;
|
|
|
|
rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
|
2002-09-17 22:51:22 +04:00
|
|
|
NS_GET_IID(nsICertificateDialogs),
|
|
|
|
NS_CERTIFICATEDIALOGS_CONTRACTID);
|
2001-03-20 21:00:44 +03:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool pressedOK;
|
bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin
nsPSMUITracker was problematic. Apparently it was originally intended to prevent
NSS shutdown while NSS-related UI operations were going on (such as choosing a
client certificate). However, when nsNSSComponent would receive the event that
told it to shutdown NSS, it would attempt to call
mShutdownObjectList->evaporateAllNSSResources(), which would call
mActivityState.restrictActivityToCurrentThread(), which failed if such a UI
operation was in progress. This actually prevented the important part of
evaporateAllNSSResources, which is the releasing of all NSS objects in use by
PSM objects. Importantly, nsNSSComponent didn't check for or handle this failure
and proceeded to call NSS_Shutdown(), leaving PSM in an inconsistent state where
it thought it was okay to keep using the NSS objects it had when in fact it
wasn't.
In any case, nsPSMUITracker isn't really necessary as long as we have the
nsNSSShutDownPreventionLock mechanism, which mostly works and is what we should
use instead (or not at all, if no such lock is needed for the operation being
performed (for example, if no NSS functions are being called)).
2015-10-17 00:31:57 +03:00
|
|
|
rv = certDialogs->SetPKCS12FilePassword(mUIContext, password, &pressedOK);
|
2002-11-14 03:50:02 +03:00
|
|
|
if (NS_FAILED(rv) || !pressedOK) return rv;
|
2016-05-07 10:58:12 +03:00
|
|
|
return unicodeToItem(password.get(), unicodePw);
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// getPKCS12FilePassword
|
|
|
|
//
|
|
|
|
// Launch a dialog requesting the user for the password to a PKCS#12 file.
|
2001-03-30 23:55:00 +04:00
|
|
|
// Handle user canceled by returning null password (caller must catch).
|
2001-03-20 21:00:44 +03:00
|
|
|
nsresult
|
|
|
|
nsPKCS12Blob::getPKCS12FilePassword(SECItem *unicodePw)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
2002-09-24 00:17:16 +04:00
|
|
|
nsAutoString password;
|
2001-03-20 21:00:44 +03:00
|
|
|
nsCOMPtr<nsICertificateDialogs> certDialogs;
|
|
|
|
rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
|
2002-09-17 22:51:22 +04:00
|
|
|
NS_GET_IID(nsICertificateDialogs),
|
|
|
|
NS_CERTIFICATEDIALOGS_CONTRACTID);
|
2001-03-20 21:00:44 +03:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool pressedOK;
|
bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin
nsPSMUITracker was problematic. Apparently it was originally intended to prevent
NSS shutdown while NSS-related UI operations were going on (such as choosing a
client certificate). However, when nsNSSComponent would receive the event that
told it to shutdown NSS, it would attempt to call
mShutdownObjectList->evaporateAllNSSResources(), which would call
mActivityState.restrictActivityToCurrentThread(), which failed if such a UI
operation was in progress. This actually prevented the important part of
evaporateAllNSSResources, which is the releasing of all NSS objects in use by
PSM objects. Importantly, nsNSSComponent didn't check for or handle this failure
and proceeded to call NSS_Shutdown(), leaving PSM in an inconsistent state where
it thought it was okay to keep using the NSS objects it had when in fact it
wasn't.
In any case, nsPSMUITracker isn't really necessary as long as we have the
nsNSSShutDownPreventionLock mechanism, which mostly works and is what we should
use instead (or not at all, if no such lock is needed for the operation being
performed (for example, if no NSS functions are being called)).
2015-10-17 00:31:57 +03:00
|
|
|
rv = certDialogs->GetPKCS12FilePassword(mUIContext, password, &pressedOK);
|
2002-11-14 03:50:02 +03:00
|
|
|
if (NS_FAILED(rv) || !pressedOK) return rv;
|
2016-05-07 10:58:12 +03:00
|
|
|
return unicodeToItem(password.get(), unicodePw);
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// inputToDecoder
|
|
|
|
//
|
|
|
|
// Given a decoder, read bytes from file and input them to the decoder.
|
|
|
|
nsresult
|
2012-06-06 06:08:30 +04:00
|
|
|
nsPKCS12Blob::inputToDecoder(SEC_PKCS12DecoderContext *dcx, nsIFile *file)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
2001-03-20 21:00:44 +03:00
|
|
|
nsresult rv;
|
|
|
|
SECStatus srv;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t amount;
|
2003-03-15 04:04:32 +03:00
|
|
|
char buf[PIP_PKCS12_BUFFER_SIZE];
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> fileStream;
|
2003-03-25 05:17:05 +03:00
|
|
|
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2003-03-15 04:04:32 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
while (true) {
|
2003-03-15 04:04:32 +03:00
|
|
|
rv = fileStream->Read(buf, PIP_PKCS12_BUFFER_SIZE, &amount);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
2001-03-30 23:55:00 +04:00
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
// feed the file data into the decoder
|
2003-03-15 04:04:32 +03:00
|
|
|
srv = SEC_PKCS12DecoderUpdate(dcx,
|
|
|
|
(unsigned char*) buf,
|
|
|
|
amount);
|
2001-03-20 21:00:44 +03:00
|
|
|
if (srv) {
|
2002-08-27 00:31:03 +04:00
|
|
|
// don't allow the close call to overwrite our precious error code
|
|
|
|
int pr_err = PORT_GetError();
|
|
|
|
PORT_SetError(pr_err);
|
|
|
|
return NS_ERROR_ABORT;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
if (amount < PIP_PKCS12_BUFFER_SIZE)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// C callback methods
|
|
|
|
//
|
|
|
|
|
|
|
|
// digest_open
|
2006-01-10 05:51:24 +03:00
|
|
|
// prepare a memory buffer for reading/writing digests
|
2012-09-25 20:18:38 +04:00
|
|
|
SECStatus
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::digest_open(void *arg, PRBool reading)
|
|
|
|
{
|
2016-05-19 04:58:41 +03:00
|
|
|
auto cx = static_cast<nsPKCS12Blob*>(arg);
|
2006-01-10 05:51:24 +03:00
|
|
|
NS_ENSURE_TRUE(cx, SECFailure);
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
if (reading) {
|
2006-01-10 05:51:24 +03:00
|
|
|
NS_ENSURE_TRUE(cx->mDigest, SECFailure);
|
|
|
|
|
|
|
|
delete cx->mDigestIterator;
|
|
|
|
cx->mDigestIterator = new nsCString::const_iterator;
|
|
|
|
|
|
|
|
if (!cx->mDigestIterator) {
|
|
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
cx->mDigest->BeginReading(*cx->mDigestIterator);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete cx->mDigest;
|
|
|
|
cx->mDigest = new nsCString;
|
|
|
|
|
|
|
|
if (!cx->mDigest) {
|
|
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
2006-01-10 05:51:24 +03:00
|
|
|
|
|
|
|
return SECSuccess;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// digest_close
|
2006-01-10 05:51:24 +03:00
|
|
|
// destroy a possibly active iterator
|
|
|
|
// remove the data buffer if requested
|
2012-09-25 20:18:38 +04:00
|
|
|
SECStatus
|
2001-03-30 23:55:00 +04:00
|
|
|
nsPKCS12Blob::digest_close(void *arg, PRBool remove_it)
|
2001-03-20 21:00:44 +03:00
|
|
|
{
|
2016-05-19 04:58:41 +03:00
|
|
|
auto cx = static_cast<nsPKCS12Blob*>(arg);
|
2006-01-10 05:51:24 +03:00
|
|
|
NS_ENSURE_TRUE(cx, SECFailure);
|
|
|
|
|
|
|
|
delete cx->mDigestIterator;
|
2012-07-30 18:20:58 +04:00
|
|
|
cx->mDigestIterator = nullptr;
|
2006-01-10 05:51:24 +03:00
|
|
|
|
2016-05-19 04:58:41 +03:00
|
|
|
if (remove_it) {
|
2006-01-10 05:51:24 +03:00
|
|
|
delete cx->mDigest;
|
2012-07-30 18:20:58 +04:00
|
|
|
cx->mDigest = nullptr;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2001-03-20 21:00:44 +03:00
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
// digest_read
|
2006-01-10 05:51:24 +03:00
|
|
|
// read bytes from the memory buffer
|
2012-09-25 20:18:38 +04:00
|
|
|
int
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::digest_read(void *arg, unsigned char *buf, unsigned long len)
|
|
|
|
{
|
2016-05-19 04:58:41 +03:00
|
|
|
auto cx = static_cast<nsPKCS12Blob*>(arg);
|
2006-01-10 05:51:24 +03:00
|
|
|
NS_ENSURE_TRUE(cx, SECFailure);
|
|
|
|
NS_ENSURE_TRUE(cx->mDigest, SECFailure);
|
|
|
|
|
|
|
|
// iterator object must exist when digest has been opened in read mode
|
|
|
|
NS_ENSURE_TRUE(cx->mDigestIterator, SECFailure);
|
|
|
|
|
|
|
|
unsigned long available = cx->mDigestIterator->size_forward();
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2006-01-10 05:51:24 +03:00
|
|
|
if (len > available)
|
|
|
|
len = available;
|
|
|
|
|
|
|
|
memcpy(buf, cx->mDigestIterator->get(), len);
|
|
|
|
cx->mDigestIterator->advance(len);
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2006-01-10 05:51:24 +03:00
|
|
|
return len;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// digest_write
|
2006-01-10 05:51:24 +03:00
|
|
|
// append bytes to the memory buffer
|
2012-09-25 20:18:38 +04:00
|
|
|
int
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::digest_write(void *arg, unsigned char *buf, unsigned long len)
|
|
|
|
{
|
2016-05-19 04:58:41 +03:00
|
|
|
auto cx = static_cast<nsPKCS12Blob*>(arg);
|
2006-01-10 05:51:24 +03:00
|
|
|
NS_ENSURE_TRUE(cx, SECFailure);
|
|
|
|
NS_ENSURE_TRUE(cx->mDigest, SECFailure);
|
|
|
|
|
|
|
|
// make sure we are in write mode, read iterator has not yet been allocated
|
|
|
|
NS_ENSURE_FALSE(cx->mDigestIterator, SECFailure);
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2016-05-19 07:20:56 +03:00
|
|
|
cx->mDigest->Append(BitwiseCast<char*, unsigned char*>(buf),
|
|
|
|
static_cast<uint32_t>(len));
|
2016-05-19 04:58:41 +03:00
|
|
|
|
2006-01-10 05:51:24 +03:00
|
|
|
return len;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// nickname_collision
|
|
|
|
// what to do when the nickname collides with one already in the db.
|
|
|
|
// TODO: not handled, throw a dialog allowing the nick to be changed?
|
2012-09-25 20:18:38 +04:00
|
|
|
SECItem *
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::nickname_collision(SECItem *oldNick, PRBool *cancel, void *wincx)
|
|
|
|
{
|
2013-11-26 22:18:21 +04:00
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
|
2003-01-18 17:03:00 +03:00
|
|
|
nsNSSShutDownPreventionLock locker;
|
2011-10-17 18:59:28 +04:00
|
|
|
*cancel = false;
|
2001-08-15 05:34:36 +04:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
2012-07-30 18:20:58 +04:00
|
|
|
if (NS_FAILED(rv)) return nullptr;
|
2001-08-15 05:34:36 +04:00
|
|
|
int count = 1;
|
2002-08-23 14:40:27 +04:00
|
|
|
nsCString nickname;
|
2004-02-26 07:07:23 +03:00
|
|
|
nsAutoString nickFromProp;
|
|
|
|
nssComponent->GetPIPNSSBundleString("P12DefaultNickname", nickFromProp);
|
2004-11-05 18:23:35 +03:00
|
|
|
NS_ConvertUTF16toUTF8 nickFromPropC(nickFromProp);
|
2001-08-15 05:34:36 +04:00
|
|
|
// The user is trying to import a PKCS#12 file that doesn't have the
|
|
|
|
// attribute we use to set the nickname. So in order to reduce the
|
|
|
|
// number of interactions we require with the user, we'll build a nickname
|
|
|
|
// for the user. The nickname isn't prominently displayed in the UI,
|
|
|
|
// so it's OK if we generate one on our own here.
|
|
|
|
// XXX If the NSS API were smarter and actually passed a pointer to
|
|
|
|
// the CERTCertificate* we're importing we could actually just
|
|
|
|
// call default_nickname (which is what the issuance code path
|
|
|
|
// does) and come up with a reasonable nickname. Alas, the NSS
|
|
|
|
// API limits our ability to produce a useful nickname without
|
|
|
|
// bugging the user. :(
|
|
|
|
while (1) {
|
|
|
|
// If we've gotten this far, that means there isn't a certificate
|
|
|
|
// in the database that has the same subject name as the cert we're
|
|
|
|
// trying to import. So we need to come up with a "nickname" to
|
|
|
|
// satisfy the NSS requirement or fail in trying to import.
|
|
|
|
// Basically we use a default nickname from a properties file and
|
|
|
|
// see if a certificate exists with that nickname. If there isn't, then
|
|
|
|
// create update the count by one and append the string '#1' Or
|
|
|
|
// whatever the count currently is, and look for a cert with
|
|
|
|
// that nickname. Keep updating the count until we find a nickname
|
|
|
|
// without a corresponding cert.
|
|
|
|
// XXX If a user imports *many* certs without the 'friendly name'
|
|
|
|
// attribute, then this may take a long time. :(
|
2016-05-11 09:38:55 +03:00
|
|
|
nickname = nickFromPropC;
|
2001-08-15 05:34:36 +04:00
|
|
|
if (count > 1) {
|
2016-05-11 09:38:55 +03:00
|
|
|
nickname.AppendPrintf(" #%d", count);
|
2001-08-15 05:34:36 +04:00
|
|
|
}
|
2016-08-05 18:57:44 +03:00
|
|
|
UniqueCERTCertificate cert(CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
|
|
|
|
nickname.get()));
|
2001-08-15 05:34:36 +04:00
|
|
|
if (!cert) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
SECItem *newNick = new SECItem;
|
|
|
|
if (!newNick)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2001-08-15 05:34:36 +04:00
|
|
|
|
|
|
|
newNick->type = siAsciiString;
|
2013-08-22 14:31:48 +04:00
|
|
|
newNick->data = (unsigned char*) strdup(nickname.get());
|
2002-02-28 08:14:10 +03:00
|
|
|
newNick->len = strlen((char*)newNick->data);
|
2001-08-15 05:34:36 +04:00
|
|
|
return newNick;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// write_export_file
|
|
|
|
// write bytes to the exported PKCS#12 file
|
2012-09-25 20:18:38 +04:00
|
|
|
void
|
2001-03-20 21:00:44 +03:00
|
|
|
nsPKCS12Blob::write_export_file(void *arg, const char *buf, unsigned long len)
|
|
|
|
{
|
|
|
|
nsPKCS12Blob *cx = (nsPKCS12Blob *)arg;
|
2001-03-30 23:55:00 +04:00
|
|
|
PR_Write(cx->mTmpFile, buf, len);
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
// do a no-op, since I've already got unicode. Hah!
|
|
|
|
*outBufLen = inBufLen;
|
|
|
|
memcpy(outBuf, inBuf, inBufLen);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2001-03-20 21:00:44 +03:00
|
|
|
}
|
2001-03-30 23:55:00 +04:00
|
|
|
|
2008-09-26 02:34:22 +04:00
|
|
|
void
|
2001-05-02 03:23:23 +04:00
|
|
|
nsPKCS12Blob::handleError(int myerr)
|
2001-03-30 23:55:00 +04:00
|
|
|
{
|
2013-11-26 22:18:21 +04:00
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
|
2011-11-03 08:02:48 +04:00
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
NS_ERROR("nsPKCS12Blob::handleError called off the mai nthread.");
|
2008-09-26 02:34:22 +04:00
|
|
|
return;
|
2003-01-07 01:23:49 +03:00
|
|
|
}
|
|
|
|
|
2001-03-30 23:55:00 +04:00
|
|
|
int prerr = PORT_GetError();
|
2015-06-04 01:25:57 +03:00
|
|
|
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("PKCS12: NSS/NSPR error(%d)", prerr));
|
|
|
|
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("PKCS12: I called(%d)", myerr));
|
2011-11-03 08:02:48 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
const char * msgID = nullptr;
|
2011-11-03 08:02:48 +04:00
|
|
|
|
2001-05-02 03:23:23 +04:00
|
|
|
switch (myerr) {
|
2011-11-03 08:02:48 +04:00
|
|
|
case PIP_PKCS12_RESTORE_OK: msgID = "SuccessfulP12Restore"; break;
|
|
|
|
case PIP_PKCS12_BACKUP_OK: msgID = "SuccessfulP12Backup"; break;
|
2001-05-02 03:23:23 +04:00
|
|
|
case PIP_PKCS12_USER_CANCELED:
|
2008-09-26 02:34:22 +04:00
|
|
|
return; /* Just ignore it for now */
|
2011-11-03 08:02:48 +04:00
|
|
|
case PIP_PKCS12_NOSMARTCARD_EXPORT: msgID = "PKCS12InfoNoSmartcardBackup"; break;
|
|
|
|
case PIP_PKCS12_RESTORE_FAILED: msgID = "PKCS12UnknownErrRestore"; break;
|
|
|
|
case PIP_PKCS12_BACKUP_FAILED: msgID = "PKCS12UnknownErrBackup"; break;
|
2001-08-22 08:05:45 +04:00
|
|
|
case PIP_PKCS12_NSS_ERROR:
|
|
|
|
switch (prerr) {
|
|
|
|
// The following errors have the potential to be "handled", by asking
|
|
|
|
// the user (via a dialog) whether s/he wishes to continue
|
|
|
|
case 0: break;
|
|
|
|
case SEC_ERROR_PKCS12_CERT_COLLISION:
|
|
|
|
/* pop a dialog saying the cert is already in the database */
|
|
|
|
/* ask to keep going? what happens if one collision but others ok? */
|
|
|
|
// The following errors cannot be "handled", notify the user (via an alert)
|
|
|
|
// that the operation failed.
|
2011-11-03 08:02:48 +04:00
|
|
|
case SEC_ERROR_BAD_PASSWORD: msgID = "PK11BadPassword"; break;
|
|
|
|
|
2001-08-22 08:05:45 +04:00
|
|
|
case SEC_ERROR_BAD_DER:
|
|
|
|
case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE:
|
|
|
|
case SEC_ERROR_PKCS12_INVALID_MAC:
|
2011-11-03 08:02:48 +04:00
|
|
|
msgID = "PKCS12DecodeErr";
|
2001-08-22 08:05:45 +04:00
|
|
|
break;
|
2011-11-03 08:02:48 +04:00
|
|
|
|
|
|
|
case SEC_ERROR_PKCS12_DUPLICATE_DATA: msgID = "PKCS12DupData"; break;
|
2001-08-22 08:05:45 +04:00
|
|
|
}
|
2001-05-02 03:23:23 +04:00
|
|
|
break;
|
2001-03-30 23:55:00 +04:00
|
|
|
}
|
2011-11-03 08:02:48 +04:00
|
|
|
|
|
|
|
if (!msgID)
|
|
|
|
msgID = "PKCS12UnknownErr";
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
(void) nssComponent->ShowAlertFromStringBundle(msgID);
|
2001-03-30 23:55:00 +04:00
|
|
|
}
|