security/manager/ssl/src/nsKeygenThread.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "pk11func.h"
michael@0 8 #include "nsCOMPtr.h"
michael@0 9 #include "nsThreadUtils.h"
michael@0 10 #include "nsKeygenThread.h"
michael@0 11 #include "nsIObserver.h"
michael@0 12 #include "nsNSSShutDown.h"
michael@0 13 #include "PSMRunnable.h"
michael@0 14 #include "mozilla/DebugOnly.h"
michael@0 15
michael@0 16 using namespace mozilla;
michael@0 17 using namespace mozilla::psm;
michael@0 18
michael@0 19 NS_IMPL_ISUPPORTS(nsKeygenThread, nsIKeygenThread)
michael@0 20
michael@0 21
michael@0 22 nsKeygenThread::nsKeygenThread()
michael@0 23 :mutex("nsKeygenThread.mutex"),
michael@0 24 iAmRunning(false),
michael@0 25 keygenReady(false),
michael@0 26 statusDialogClosed(false),
michael@0 27 alreadyReceivedParams(false),
michael@0 28 privateKey(nullptr),
michael@0 29 publicKey(nullptr),
michael@0 30 slot(nullptr),
michael@0 31 flags(0),
michael@0 32 altSlot(nullptr),
michael@0 33 altFlags(0),
michael@0 34 usedSlot(nullptr),
michael@0 35 keyGenMechanism(0),
michael@0 36 params(nullptr),
michael@0 37 wincx(nullptr),
michael@0 38 threadHandle(nullptr)
michael@0 39 {
michael@0 40 }
michael@0 41
michael@0 42 nsKeygenThread::~nsKeygenThread()
michael@0 43 {
michael@0 44 // clean up in the unlikely case that nobody consumed our results
michael@0 45
michael@0 46 if (privateKey)
michael@0 47 SECKEY_DestroyPrivateKey(privateKey);
michael@0 48
michael@0 49 if (publicKey)
michael@0 50 SECKEY_DestroyPublicKey(publicKey);
michael@0 51
michael@0 52 if (usedSlot)
michael@0 53 PK11_FreeSlot(usedSlot);
michael@0 54 }
michael@0 55
michael@0 56 void nsKeygenThread::SetParams(
michael@0 57 PK11SlotInfo *a_slot,
michael@0 58 PK11AttrFlags a_flags,
michael@0 59 PK11SlotInfo *a_alternative_slot,
michael@0 60 PK11AttrFlags a_alternative_flags,
michael@0 61 uint32_t a_keyGenMechanism,
michael@0 62 void *a_params,
michael@0 63 void *a_wincx )
michael@0 64 {
michael@0 65 nsNSSShutDownPreventionLock locker;
michael@0 66 MutexAutoLock lock(mutex);
michael@0 67
michael@0 68 if (!alreadyReceivedParams) {
michael@0 69 alreadyReceivedParams = true;
michael@0 70 slot = (a_slot) ? PK11_ReferenceSlot(a_slot) : nullptr;
michael@0 71 flags = a_flags;
michael@0 72 altSlot = (a_alternative_slot) ? PK11_ReferenceSlot(a_alternative_slot) : nullptr;
michael@0 73 altFlags = a_alternative_flags;
michael@0 74 keyGenMechanism = a_keyGenMechanism;
michael@0 75 params = a_params;
michael@0 76 wincx = a_wincx;
michael@0 77 }
michael@0 78 }
michael@0 79
michael@0 80 nsresult nsKeygenThread::ConsumeResult(
michael@0 81 PK11SlotInfo **a_used_slot,
michael@0 82 SECKEYPrivateKey **a_privateKey,
michael@0 83 SECKEYPublicKey **a_publicKey)
michael@0 84 {
michael@0 85 if (!a_used_slot || !a_privateKey || !a_publicKey) {
michael@0 86 return NS_ERROR_FAILURE;
michael@0 87 }
michael@0 88
michael@0 89 nsresult rv;
michael@0 90
michael@0 91 MutexAutoLock lock(mutex);
michael@0 92
michael@0 93 // GetParams must not be called until thread creator called
michael@0 94 // Join on this thread.
michael@0 95 NS_ASSERTION(keygenReady, "logic error in nsKeygenThread::GetParams");
michael@0 96
michael@0 97 if (keygenReady) {
michael@0 98 *a_privateKey = privateKey;
michael@0 99 *a_publicKey = publicKey;
michael@0 100 *a_used_slot = usedSlot;
michael@0 101
michael@0 102 privateKey = 0;
michael@0 103 publicKey = 0;
michael@0 104 usedSlot = 0;
michael@0 105
michael@0 106 rv = NS_OK;
michael@0 107 }
michael@0 108 else {
michael@0 109 rv = NS_ERROR_FAILURE;
michael@0 110 }
michael@0 111
michael@0 112 return rv;
michael@0 113 }
michael@0 114
michael@0 115 static void nsKeygenThreadRunner(void *arg)
michael@0 116 {
michael@0 117 PR_SetCurrentThreadName("Keygen");
michael@0 118 nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
michael@0 119 self->Run();
michael@0 120 }
michael@0 121
michael@0 122 nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
michael@0 123 {
michael@0 124 if (!NS_IsMainThread()) {
michael@0 125 NS_ERROR("nsKeygenThread::StartKeyGeneration called off the main thread");
michael@0 126 return NS_ERROR_NOT_SAME_THREAD;
michael@0 127 }
michael@0 128
michael@0 129 if (!aObserver)
michael@0 130 return NS_OK;
michael@0 131
michael@0 132 MutexAutoLock lock(mutex);
michael@0 133
michael@0 134 if (iAmRunning || keygenReady) {
michael@0 135 return NS_OK;
michael@0 136 }
michael@0 137
michael@0 138 // We must AddRef aObserver only here on the main thread, because it
michael@0 139 // probably does not implement a thread-safe AddRef.
michael@0 140 mNotifyObserver = new NotifyObserverRunnable(aObserver, "keygen-finished");
michael@0 141
michael@0 142 iAmRunning = true;
michael@0 143
michael@0 144 threadHandle = PR_CreateThread(PR_USER_THREAD, nsKeygenThreadRunner, static_cast<void*>(this),
michael@0 145 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
michael@0 146
michael@0 147 // bool thread_started_ok = (threadHandle != nullptr);
michael@0 148 // we might want to return "thread started ok" to caller in the future
michael@0 149 NS_ASSERTION(threadHandle, "Could not create nsKeygenThreadRunner thread\n");
michael@0 150
michael@0 151 return NS_OK;
michael@0 152 }
michael@0 153
michael@0 154 nsresult nsKeygenThread::UserCanceled(bool *threadAlreadyClosedDialog)
michael@0 155 {
michael@0 156 if (!threadAlreadyClosedDialog)
michael@0 157 return NS_OK;
michael@0 158
michael@0 159 *threadAlreadyClosedDialog = false;
michael@0 160
michael@0 161 MutexAutoLock lock(mutex);
michael@0 162
michael@0 163 if (keygenReady)
michael@0 164 *threadAlreadyClosedDialog = statusDialogClosed;
michael@0 165
michael@0 166 // User somehow closed the dialog, but we will not cancel.
michael@0 167 // Bad luck, we told him not do, and user still has to wait.
michael@0 168 // However, we remember that it's closed and will not close
michael@0 169 // it again to avoid problems.
michael@0 170 statusDialogClosed = true;
michael@0 171
michael@0 172 return NS_OK;
michael@0 173 }
michael@0 174
michael@0 175 void nsKeygenThread::Run(void)
michael@0 176 {
michael@0 177 nsNSSShutDownPreventionLock locker;
michael@0 178 bool canGenerate = false;
michael@0 179
michael@0 180 {
michael@0 181 MutexAutoLock lock(mutex);
michael@0 182 if (alreadyReceivedParams) {
michael@0 183 canGenerate = true;
michael@0 184 keygenReady = false;
michael@0 185 }
michael@0 186 }
michael@0 187
michael@0 188 if (canGenerate) {
michael@0 189 privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism,
michael@0 190 params, &publicKey,
michael@0 191 flags, wincx);
michael@0 192
michael@0 193 if (privateKey) {
michael@0 194 usedSlot = PK11_ReferenceSlot(slot);
michael@0 195 }
michael@0 196 else if (altSlot) {
michael@0 197 privateKey = PK11_GenerateKeyPairWithFlags(altSlot, keyGenMechanism,
michael@0 198 params, &publicKey,
michael@0 199 altFlags, wincx);
michael@0 200 if (privateKey) {
michael@0 201 usedSlot = PK11_ReferenceSlot(altSlot);
michael@0 202 }
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 // This call gave us ownership over privateKey and publicKey.
michael@0 207 // But as the params structure is owner by our caller,
michael@0 208 // we effectively transferred ownership to the caller.
michael@0 209 // As long as key generation can't be canceled, we don't need
michael@0 210 // to care for cleaning this up.
michael@0 211
michael@0 212 nsCOMPtr<nsIRunnable> notifyObserver;
michael@0 213 {
michael@0 214 MutexAutoLock lock(mutex);
michael@0 215
michael@0 216 keygenReady = true;
michael@0 217 iAmRunning = false;
michael@0 218
michael@0 219 // forget our parameters
michael@0 220 if (slot) {
michael@0 221 PK11_FreeSlot(slot);
michael@0 222 slot = 0;
michael@0 223 }
michael@0 224 if (altSlot) {
michael@0 225 PK11_FreeSlot(altSlot);
michael@0 226 altSlot = 0;
michael@0 227 }
michael@0 228 keyGenMechanism = 0;
michael@0 229 params = 0;
michael@0 230 wincx = 0;
michael@0 231
michael@0 232 if (!statusDialogClosed && mNotifyObserver)
michael@0 233 notifyObserver = mNotifyObserver;
michael@0 234
michael@0 235 mNotifyObserver = nullptr;
michael@0 236 }
michael@0 237
michael@0 238 if (notifyObserver) {
michael@0 239 DebugOnly<nsresult> rv = NS_DispatchToMainThread(notifyObserver);
michael@0 240 NS_ASSERTION(NS_SUCCEEDED(rv),
michael@0 241 "failed to dispatch keygen thread observer to main thread");
michael@0 242 }
michael@0 243 }
michael@0 244
michael@0 245 void nsKeygenThread::Join()
michael@0 246 {
michael@0 247 if (!threadHandle)
michael@0 248 return;
michael@0 249
michael@0 250 PR_JoinThread(threadHandle);
michael@0 251 threadHandle = nullptr;
michael@0 252
michael@0 253 return;
michael@0 254 }

mercurial