security/manager/ssl/src/nsKeygenThread.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

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 }

mercurial