Coverage Report

Created: 2018-09-25 14:53

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