123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * 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/. */
- #include "pk11func.h"
- #include "nsCOMPtr.h"
- #include "nsThreadUtils.h"
- #include "nsKeygenThread.h"
- #include "nsIObserver.h"
- #include "nsNSSShutDown.h"
- #include "PSMRunnable.h"
- #include "mozilla/DebugOnly.h"
- using namespace mozilla;
- using namespace mozilla::psm;
- NS_IMPL_ISUPPORTS(nsKeygenThread, nsIKeygenThread)
- nsKeygenThread::nsKeygenThread()
- :mutex("nsKeygenThread.mutex"),
- iAmRunning(false),
- keygenReady(false),
- statusDialogClosed(false),
- alreadyReceivedParams(false),
- privateKey(nullptr),
- publicKey(nullptr),
- slot(nullptr),
- flags(0),
- altSlot(nullptr),
- altFlags(0),
- usedSlot(nullptr),
- keyGenMechanism(0),
- params(nullptr),
- wincx(nullptr),
- threadHandle(nullptr)
- {
- }
- nsKeygenThread::~nsKeygenThread()
- {
- // clean up in the unlikely case that nobody consumed our results
-
- if (privateKey)
- SECKEY_DestroyPrivateKey(privateKey);
-
- if (publicKey)
- SECKEY_DestroyPublicKey(publicKey);
-
- if (usedSlot)
- PK11_FreeSlot(usedSlot);
- }
- void nsKeygenThread::SetParams(
- PK11SlotInfo *a_slot,
- PK11AttrFlags a_flags,
- PK11SlotInfo *a_alternative_slot,
- PK11AttrFlags a_alternative_flags,
- uint32_t a_keyGenMechanism,
- void *a_params,
- void *a_wincx )
- {
- nsNSSShutDownPreventionLock locker;
- MutexAutoLock lock(mutex);
-
- if (!alreadyReceivedParams) {
- alreadyReceivedParams = true;
- slot = (a_slot) ? PK11_ReferenceSlot(a_slot) : nullptr;
- flags = a_flags;
- altSlot = (a_alternative_slot) ? PK11_ReferenceSlot(a_alternative_slot) : nullptr;
- altFlags = a_alternative_flags;
- keyGenMechanism = a_keyGenMechanism;
- params = a_params;
- wincx = a_wincx;
- }
- }
- nsresult nsKeygenThread::ConsumeResult(
- PK11SlotInfo **a_used_slot,
- SECKEYPrivateKey **a_privateKey,
- SECKEYPublicKey **a_publicKey)
- {
- if (!a_used_slot || !a_privateKey || !a_publicKey) {
- return NS_ERROR_FAILURE;
- }
- nsresult rv;
- MutexAutoLock lock(mutex);
-
- // GetParams must not be called until thread creator called
- // Join on this thread.
- NS_ASSERTION(keygenReady, "logic error in nsKeygenThread::GetParams");
- if (keygenReady) {
- *a_privateKey = privateKey;
- *a_publicKey = publicKey;
- *a_used_slot = usedSlot;
- privateKey = 0;
- publicKey = 0;
- usedSlot = 0;
-
- rv = NS_OK;
- }
- else {
- rv = NS_ERROR_FAILURE;
- }
-
- return rv;
- }
- static void nsKeygenThreadRunner(void *arg)
- {
- PR_SetCurrentThreadName("Keygen");
- nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
- self->Run();
- }
- nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
- {
- if (!NS_IsMainThread()) {
- NS_ERROR("nsKeygenThread::StartKeyGeneration called off the main thread");
- return NS_ERROR_NOT_SAME_THREAD;
- }
-
- if (!aObserver)
- return NS_OK;
- MutexAutoLock lock(mutex);
- if (iAmRunning || keygenReady) {
- return NS_OK;
- }
- // We must AddRef aObserver only here on the main thread, because it
- // probably does not implement a thread-safe AddRef.
- mNotifyObserver = new NotifyObserverRunnable(aObserver, "keygen-finished");
- iAmRunning = true;
- threadHandle = PR_CreateThread(PR_USER_THREAD, nsKeygenThreadRunner, static_cast<void*>(this),
- PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
- // bool thread_started_ok = (threadHandle != nullptr);
- // we might want to return "thread started ok" to caller in the future
- NS_ASSERTION(threadHandle, "Could not create nsKeygenThreadRunner thread\n");
-
- return NS_OK;
- }
- nsresult nsKeygenThread::UserCanceled(bool *threadAlreadyClosedDialog)
- {
- if (!threadAlreadyClosedDialog)
- return NS_OK;
- *threadAlreadyClosedDialog = false;
- MutexAutoLock lock(mutex);
-
- if (keygenReady)
- *threadAlreadyClosedDialog = statusDialogClosed;
- // User somehow closed the dialog, but we will not cancel.
- // Bad luck, we told him not do, and user still has to wait.
- // However, we remember that it's closed and will not close
- // it again to avoid problems.
- statusDialogClosed = true;
- return NS_OK;
- }
- void nsKeygenThread::Run(void)
- {
- nsNSSShutDownPreventionLock locker;
- bool canGenerate = false;
- {
- MutexAutoLock lock(mutex);
- if (alreadyReceivedParams) {
- canGenerate = true;
- keygenReady = false;
- }
- }
- if (canGenerate) {
- privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism,
- params, &publicKey,
- flags, wincx);
- if (privateKey) {
- usedSlot = PK11_ReferenceSlot(slot);
- }
- else if (altSlot) {
- privateKey = PK11_GenerateKeyPairWithFlags(altSlot, keyGenMechanism,
- params, &publicKey,
- altFlags, wincx);
- if (privateKey) {
- usedSlot = PK11_ReferenceSlot(altSlot);
- }
- }
- }
-
- // This call gave us ownership over privateKey and publicKey.
- // But as the params structure is owner by our caller,
- // we effectively transferred ownership to the caller.
- // As long as key generation can't be canceled, we don't need
- // to care for cleaning this up.
- nsCOMPtr<nsIRunnable> notifyObserver;
- {
- MutexAutoLock lock(mutex);
- keygenReady = true;
- iAmRunning = false;
- // forget our parameters
- if (slot) {
- PK11_FreeSlot(slot);
- slot = 0;
- }
- if (altSlot) {
- PK11_FreeSlot(altSlot);
- altSlot = 0;
- }
- keyGenMechanism = 0;
- params = 0;
- wincx = 0;
- if (!statusDialogClosed && mNotifyObserver)
- notifyObserver = mNotifyObserver;
- mNotifyObserver = nullptr;
- }
- if (notifyObserver) {
- DebugOnly<nsresult> rv = NS_DispatchToMainThread(notifyObserver);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "failed to dispatch keygen thread observer to main thread");
- }
- }
- void nsKeygenThread::Join()
- {
- if (!threadHandle)
- return;
-
- PR_JoinThread(threadHandle);
- threadHandle = nullptr;
- return;
- }
|