summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/nsKeygenThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/nsKeygenThread.cpp')
-rw-r--r--security/manager/ssl/nsKeygenThread.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/security/manager/ssl/nsKeygenThread.cpp b/security/manager/ssl/nsKeygenThread.cpp
new file mode 100644
index 000000000..b295c4f36
--- /dev/null
+++ b/security/manager/ssl/nsKeygenThread.cpp
@@ -0,0 +1,254 @@
+/* -*- 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;
+}