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