nsKeygenThread.cpp 6.2 KB

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