1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsKeygenThread.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,254 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "pk11func.h" 1.11 +#include "nsCOMPtr.h" 1.12 +#include "nsThreadUtils.h" 1.13 +#include "nsKeygenThread.h" 1.14 +#include "nsIObserver.h" 1.15 +#include "nsNSSShutDown.h" 1.16 +#include "PSMRunnable.h" 1.17 +#include "mozilla/DebugOnly.h" 1.18 + 1.19 +using namespace mozilla; 1.20 +using namespace mozilla::psm; 1.21 + 1.22 +NS_IMPL_ISUPPORTS(nsKeygenThread, nsIKeygenThread) 1.23 + 1.24 + 1.25 +nsKeygenThread::nsKeygenThread() 1.26 +:mutex("nsKeygenThread.mutex"), 1.27 + iAmRunning(false), 1.28 + keygenReady(false), 1.29 + statusDialogClosed(false), 1.30 + alreadyReceivedParams(false), 1.31 + privateKey(nullptr), 1.32 + publicKey(nullptr), 1.33 + slot(nullptr), 1.34 + flags(0), 1.35 + altSlot(nullptr), 1.36 + altFlags(0), 1.37 + usedSlot(nullptr), 1.38 + keyGenMechanism(0), 1.39 + params(nullptr), 1.40 + wincx(nullptr), 1.41 + threadHandle(nullptr) 1.42 +{ 1.43 +} 1.44 + 1.45 +nsKeygenThread::~nsKeygenThread() 1.46 +{ 1.47 + // clean up in the unlikely case that nobody consumed our results 1.48 + 1.49 + if (privateKey) 1.50 + SECKEY_DestroyPrivateKey(privateKey); 1.51 + 1.52 + if (publicKey) 1.53 + SECKEY_DestroyPublicKey(publicKey); 1.54 + 1.55 + if (usedSlot) 1.56 + PK11_FreeSlot(usedSlot); 1.57 +} 1.58 + 1.59 +void nsKeygenThread::SetParams( 1.60 + PK11SlotInfo *a_slot, 1.61 + PK11AttrFlags a_flags, 1.62 + PK11SlotInfo *a_alternative_slot, 1.63 + PK11AttrFlags a_alternative_flags, 1.64 + uint32_t a_keyGenMechanism, 1.65 + void *a_params, 1.66 + void *a_wincx ) 1.67 +{ 1.68 + nsNSSShutDownPreventionLock locker; 1.69 + MutexAutoLock lock(mutex); 1.70 + 1.71 + if (!alreadyReceivedParams) { 1.72 + alreadyReceivedParams = true; 1.73 + slot = (a_slot) ? PK11_ReferenceSlot(a_slot) : nullptr; 1.74 + flags = a_flags; 1.75 + altSlot = (a_alternative_slot) ? PK11_ReferenceSlot(a_alternative_slot) : nullptr; 1.76 + altFlags = a_alternative_flags; 1.77 + keyGenMechanism = a_keyGenMechanism; 1.78 + params = a_params; 1.79 + wincx = a_wincx; 1.80 + } 1.81 +} 1.82 + 1.83 +nsresult nsKeygenThread::ConsumeResult( 1.84 + PK11SlotInfo **a_used_slot, 1.85 + SECKEYPrivateKey **a_privateKey, 1.86 + SECKEYPublicKey **a_publicKey) 1.87 +{ 1.88 + if (!a_used_slot || !a_privateKey || !a_publicKey) { 1.89 + return NS_ERROR_FAILURE; 1.90 + } 1.91 + 1.92 + nsresult rv; 1.93 + 1.94 + MutexAutoLock lock(mutex); 1.95 + 1.96 + // GetParams must not be called until thread creator called 1.97 + // Join on this thread. 1.98 + NS_ASSERTION(keygenReady, "logic error in nsKeygenThread::GetParams"); 1.99 + 1.100 + if (keygenReady) { 1.101 + *a_privateKey = privateKey; 1.102 + *a_publicKey = publicKey; 1.103 + *a_used_slot = usedSlot; 1.104 + 1.105 + privateKey = 0; 1.106 + publicKey = 0; 1.107 + usedSlot = 0; 1.108 + 1.109 + rv = NS_OK; 1.110 + } 1.111 + else { 1.112 + rv = NS_ERROR_FAILURE; 1.113 + } 1.114 + 1.115 + return rv; 1.116 +} 1.117 + 1.118 +static void nsKeygenThreadRunner(void *arg) 1.119 +{ 1.120 + PR_SetCurrentThreadName("Keygen"); 1.121 + nsKeygenThread *self = static_cast<nsKeygenThread *>(arg); 1.122 + self->Run(); 1.123 +} 1.124 + 1.125 +nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver) 1.126 +{ 1.127 + if (!NS_IsMainThread()) { 1.128 + NS_ERROR("nsKeygenThread::StartKeyGeneration called off the main thread"); 1.129 + return NS_ERROR_NOT_SAME_THREAD; 1.130 + } 1.131 + 1.132 + if (!aObserver) 1.133 + return NS_OK; 1.134 + 1.135 + MutexAutoLock lock(mutex); 1.136 + 1.137 + if (iAmRunning || keygenReady) { 1.138 + return NS_OK; 1.139 + } 1.140 + 1.141 + // We must AddRef aObserver only here on the main thread, because it 1.142 + // probably does not implement a thread-safe AddRef. 1.143 + mNotifyObserver = new NotifyObserverRunnable(aObserver, "keygen-finished"); 1.144 + 1.145 + iAmRunning = true; 1.146 + 1.147 + threadHandle = PR_CreateThread(PR_USER_THREAD, nsKeygenThreadRunner, static_cast<void*>(this), 1.148 + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 1.149 + 1.150 + // bool thread_started_ok = (threadHandle != nullptr); 1.151 + // we might want to return "thread started ok" to caller in the future 1.152 + NS_ASSERTION(threadHandle, "Could not create nsKeygenThreadRunner thread\n"); 1.153 + 1.154 + return NS_OK; 1.155 +} 1.156 + 1.157 +nsresult nsKeygenThread::UserCanceled(bool *threadAlreadyClosedDialog) 1.158 +{ 1.159 + if (!threadAlreadyClosedDialog) 1.160 + return NS_OK; 1.161 + 1.162 + *threadAlreadyClosedDialog = false; 1.163 + 1.164 + MutexAutoLock lock(mutex); 1.165 + 1.166 + if (keygenReady) 1.167 + *threadAlreadyClosedDialog = statusDialogClosed; 1.168 + 1.169 + // User somehow closed the dialog, but we will not cancel. 1.170 + // Bad luck, we told him not do, and user still has to wait. 1.171 + // However, we remember that it's closed and will not close 1.172 + // it again to avoid problems. 1.173 + statusDialogClosed = true; 1.174 + 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +void nsKeygenThread::Run(void) 1.179 +{ 1.180 + nsNSSShutDownPreventionLock locker; 1.181 + bool canGenerate = false; 1.182 + 1.183 + { 1.184 + MutexAutoLock lock(mutex); 1.185 + if (alreadyReceivedParams) { 1.186 + canGenerate = true; 1.187 + keygenReady = false; 1.188 + } 1.189 + } 1.190 + 1.191 + if (canGenerate) { 1.192 + privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism, 1.193 + params, &publicKey, 1.194 + flags, wincx); 1.195 + 1.196 + if (privateKey) { 1.197 + usedSlot = PK11_ReferenceSlot(slot); 1.198 + } 1.199 + else if (altSlot) { 1.200 + privateKey = PK11_GenerateKeyPairWithFlags(altSlot, keyGenMechanism, 1.201 + params, &publicKey, 1.202 + altFlags, wincx); 1.203 + if (privateKey) { 1.204 + usedSlot = PK11_ReferenceSlot(altSlot); 1.205 + } 1.206 + } 1.207 + } 1.208 + 1.209 + // This call gave us ownership over privateKey and publicKey. 1.210 + // But as the params structure is owner by our caller, 1.211 + // we effectively transferred ownership to the caller. 1.212 + // As long as key generation can't be canceled, we don't need 1.213 + // to care for cleaning this up. 1.214 + 1.215 + nsCOMPtr<nsIRunnable> notifyObserver; 1.216 + { 1.217 + MutexAutoLock lock(mutex); 1.218 + 1.219 + keygenReady = true; 1.220 + iAmRunning = false; 1.221 + 1.222 + // forget our parameters 1.223 + if (slot) { 1.224 + PK11_FreeSlot(slot); 1.225 + slot = 0; 1.226 + } 1.227 + if (altSlot) { 1.228 + PK11_FreeSlot(altSlot); 1.229 + altSlot = 0; 1.230 + } 1.231 + keyGenMechanism = 0; 1.232 + params = 0; 1.233 + wincx = 0; 1.234 + 1.235 + if (!statusDialogClosed && mNotifyObserver) 1.236 + notifyObserver = mNotifyObserver; 1.237 + 1.238 + mNotifyObserver = nullptr; 1.239 + } 1.240 + 1.241 + if (notifyObserver) { 1.242 + DebugOnly<nsresult> rv = NS_DispatchToMainThread(notifyObserver); 1.243 + NS_ASSERTION(NS_SUCCEEDED(rv), 1.244 + "failed to dispatch keygen thread observer to main thread"); 1.245 + } 1.246 +} 1.247 + 1.248 +void nsKeygenThread::Join() 1.249 +{ 1.250 + if (!threadHandle) 1.251 + return; 1.252 + 1.253 + PR_JoinThread(threadHandle); 1.254 + threadHandle = nullptr; 1.255 + 1.256 + return; 1.257 +}