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