nsKeygenHandler.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  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 "base64.h"
  7. #include "cryptohi.h"
  8. #include "keyhi.h"
  9. #include "mozilla/Assertions.h"
  10. #include "nsIContent.h"
  11. #include "nsIDOMHTMLSelectElement.h"
  12. #include "nsIGenKeypairInfoDlg.h"
  13. #include "nsIServiceManager.h"
  14. #include "nsITokenDialogs.h"
  15. #include "nsKeygenHandler.h"
  16. #include "nsKeygenHandlerContent.h"
  17. #include "nsKeygenThread.h"
  18. #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
  19. #include "nsNSSHelper.h"
  20. #include "nsReadableUtils.h"
  21. #include "nsUnicharUtils.h"
  22. #include "nsXULAppAPI.h"
  23. #include "nspr.h"
  24. #include "secasn1.h"
  25. #include "secder.h"
  26. #include "secdert.h"
  27. DERTemplate SECAlgorithmIDTemplate[] = {
  28. { DER_SEQUENCE,
  29. 0, nullptr, sizeof(SECAlgorithmID) },
  30. { DER_OBJECT_ID,
  31. offsetof(SECAlgorithmID,algorithm), },
  32. { DER_OPTIONAL | DER_ANY,
  33. offsetof(SECAlgorithmID,parameters), },
  34. { 0, }
  35. };
  36. DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
  37. { DER_SEQUENCE,
  38. 0, nullptr, sizeof(CERTSubjectPublicKeyInfo) },
  39. { DER_INLINE,
  40. offsetof(CERTSubjectPublicKeyInfo,algorithm),
  41. SECAlgorithmIDTemplate, },
  42. { DER_BIT_STRING,
  43. offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
  44. { 0, }
  45. };
  46. DERTemplate CERTPublicKeyAndChallengeTemplate[] =
  47. {
  48. { DER_SEQUENCE, 0, nullptr, sizeof(CERTPublicKeyAndChallenge) },
  49. { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
  50. { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
  51. { 0, }
  52. };
  53. typedef struct curveNameTagPairStr {
  54. const char *curveName;
  55. SECOidTag curveOidTag;
  56. } CurveNameTagPair;
  57. static CurveNameTagPair nameTagPair[] =
  58. {
  59. { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
  60. { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
  61. { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
  62. { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
  63. { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
  64. { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
  65. { "prime256v1", SEC_OID_ANSIX962_EC_PRIME256V1 },
  66. { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
  67. { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
  68. { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
  69. { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
  70. { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
  71. { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
  72. { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
  73. { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
  74. { "secp192r1", SEC_OID_ANSIX962_EC_PRIME192V1 },
  75. { "nistp192", SEC_OID_ANSIX962_EC_PRIME192V1 },
  76. { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
  77. { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
  78. { "nistp224", SEC_OID_SECG_EC_SECP224R1},
  79. { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
  80. { "secp256r1", SEC_OID_ANSIX962_EC_PRIME256V1 },
  81. { "nistp256", SEC_OID_ANSIX962_EC_PRIME256V1 },
  82. { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
  83. { "nistp384", SEC_OID_SECG_EC_SECP384R1},
  84. { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
  85. { "nistp521", SEC_OID_SECG_EC_SECP521R1},
  86. { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
  87. { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
  88. { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
  89. { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
  90. { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
  91. { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
  92. { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
  93. { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
  94. { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
  95. { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
  96. { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
  97. { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
  98. { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
  99. { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
  100. { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
  101. { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
  102. { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
  103. { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
  104. { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
  105. { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
  106. { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
  107. { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
  108. { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
  109. { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
  110. { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
  111. { "nistk163", SEC_OID_SECG_EC_SECT163K1},
  112. { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
  113. { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
  114. { "nistb163", SEC_OID_SECG_EC_SECT163R2},
  115. { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
  116. { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
  117. { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
  118. { "nistk233", SEC_OID_SECG_EC_SECT233K1},
  119. { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
  120. { "nistb233", SEC_OID_SECG_EC_SECT233R1},
  121. { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
  122. { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
  123. { "nistk283", SEC_OID_SECG_EC_SECT283K1},
  124. { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
  125. { "nistb283", SEC_OID_SECG_EC_SECT283R1},
  126. { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
  127. { "nistk409", SEC_OID_SECG_EC_SECT409K1},
  128. { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
  129. { "nistb409", SEC_OID_SECG_EC_SECT409R1},
  130. { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
  131. { "nistk571", SEC_OID_SECG_EC_SECT571K1},
  132. { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
  133. { "nistb571", SEC_OID_SECG_EC_SECT571R1},
  134. };
  135. mozilla::UniqueSECItem
  136. DecodeECParams(const char* curve)
  137. {
  138. SECOidData *oidData = nullptr;
  139. SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
  140. int i, numCurves;
  141. if (curve && *curve) {
  142. numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
  143. for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
  144. i++) {
  145. if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
  146. curveOidTag = nameTagPair[i].curveOidTag;
  147. }
  148. }
  149. /* Return nullptr if curve name is not recognized */
  150. if ((curveOidTag == SEC_OID_UNKNOWN) ||
  151. (oidData = SECOID_FindOIDByTag(curveOidTag)) == nullptr) {
  152. return nullptr;
  153. }
  154. mozilla::UniqueSECItem ecparams(SECITEM_AllocItem(nullptr, nullptr,
  155. 2 + oidData->oid.len));
  156. if (!ecparams) {
  157. return nullptr;
  158. }
  159. /*
  160. * ecparams->data needs to contain the ASN encoding of an object ID (OID)
  161. * representing the named curve. The actual OID is in
  162. * oidData->oid.data so we simply prepend 0x06 and OID length
  163. */
  164. ecparams->data[0] = SEC_ASN1_OBJECT_ID;
  165. ecparams->data[1] = oidData->oid.len;
  166. memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
  167. return ecparams;
  168. }
  169. NS_IMPL_ISUPPORTS(nsKeygenFormProcessor, nsIFormProcessor)
  170. nsKeygenFormProcessor::nsKeygenFormProcessor()
  171. {
  172. m_ctx = new PipUIContext();
  173. }
  174. nsKeygenFormProcessor::~nsKeygenFormProcessor()
  175. {
  176. nsNSSShutDownPreventionLock locker;
  177. if (isAlreadyShutDown()) {
  178. return;
  179. }
  180. shutdown(ShutdownCalledFrom::Object);
  181. }
  182. nsresult
  183. nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
  184. {
  185. if (GeckoProcessType_Content == XRE_GetProcessType()) {
  186. nsCOMPtr<nsISupports> contentProcessor = new nsKeygenFormProcessorContent();
  187. return contentProcessor->QueryInterface(aIID, aResult);
  188. }
  189. nsresult rv;
  190. NS_ENSURE_NO_AGGREGATION(aOuter);
  191. nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
  192. nsCOMPtr<nsISupports> stabilize = formProc;
  193. rv = formProc->Init();
  194. if (NS_SUCCEEDED(rv)) {
  195. rv = formProc->QueryInterface(aIID, aResult);
  196. }
  197. return rv;
  198. }
  199. nsresult
  200. nsKeygenFormProcessor::Init()
  201. {
  202. static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  203. nsresult rv;
  204. nsCOMPtr<nsINSSComponent> nssComponent;
  205. nssComponent = do_GetService(kNSSComponentCID, &rv);
  206. if (NS_FAILED(rv))
  207. return rv;
  208. // Init possible key size choices.
  209. nssComponent->GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name);
  210. mSECKeySizeChoiceList[0].size = 2048;
  211. nssComponent->GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name);
  212. mSECKeySizeChoiceList[1].size = 1024;
  213. return NS_OK;
  214. }
  215. nsresult
  216. nsKeygenFormProcessor::GetSlot(uint32_t aMechanism, PK11SlotInfo** aSlot)
  217. {
  218. nsNSSShutDownPreventionLock locker;
  219. if (isAlreadyShutDown()) {
  220. return NS_ERROR_NOT_AVAILABLE;
  221. }
  222. return GetSlotWithMechanism(aMechanism, m_ctx, aSlot, locker);
  223. }
  224. uint32_t MapGenMechToAlgoMech(uint32_t mechanism)
  225. {
  226. uint32_t searchMech;
  227. /* We are interested in slots based on the ability to perform
  228. a given algorithm, not on their ability to generate keys usable
  229. by that algorithm. Therefore, map keygen-specific mechanism tags
  230. to tags for the corresponding crypto algorithm. */
  231. switch(mechanism)
  232. {
  233. case CKM_RSA_PKCS_KEY_PAIR_GEN:
  234. searchMech = CKM_RSA_PKCS;
  235. break;
  236. case CKM_RC4_KEY_GEN:
  237. searchMech = CKM_RC4;
  238. break;
  239. case CKM_DH_PKCS_KEY_PAIR_GEN:
  240. searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch is this right? */
  241. break;
  242. case CKM_DES_KEY_GEN:
  243. /* What do we do about DES keygen? Right now, we're just using
  244. DES_KEY_GEN to look for tokens, because otherwise we'll have
  245. to search the token list three times. */
  246. case CKM_EC_KEY_PAIR_GEN:
  247. /* The default should also work for EC key pair generation. */
  248. default:
  249. searchMech = mechanism;
  250. break;
  251. }
  252. return searchMech;
  253. }
  254. nsresult
  255. GetSlotWithMechanism(uint32_t aMechanism, nsIInterfaceRequestor* m_ctx,
  256. PK11SlotInfo** aSlot, nsNSSShutDownPreventionLock& /*proofOfLock*/)
  257. {
  258. PK11SlotList * slotList = nullptr;
  259. char16_t** tokenNameList = nullptr;
  260. nsCOMPtr<nsITokenDialogs> dialogs;
  261. char16_t *unicodeTokenChosen;
  262. PK11SlotListElement *slotElement, *tmpSlot;
  263. uint32_t numSlots = 0, i = 0;
  264. bool canceled;
  265. nsresult rv = NS_OK;
  266. *aSlot = nullptr;
  267. // Get the slot
  268. slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism),
  269. true, true, m_ctx);
  270. if (!slotList || !slotList->head) {
  271. rv = NS_ERROR_FAILURE;
  272. goto loser;
  273. }
  274. if (!slotList->head->next) {
  275. /* only one slot available, just return it */
  276. *aSlot = slotList->head->slot;
  277. } else {
  278. // Gerenate a list of slots and ask the user to choose //
  279. tmpSlot = slotList->head;
  280. while (tmpSlot) {
  281. numSlots++;
  282. tmpSlot = tmpSlot->next;
  283. }
  284. // Allocate the slot name buffer //
  285. tokenNameList = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t *) * numSlots));
  286. if (!tokenNameList) {
  287. rv = NS_ERROR_OUT_OF_MEMORY;
  288. goto loser;
  289. }
  290. i = 0;
  291. slotElement = PK11_GetFirstSafe(slotList);
  292. while (slotElement) {
  293. tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot)));
  294. slotElement = PK11_GetNextSafe(slotList, slotElement, false);
  295. if (tokenNameList[i])
  296. i++;
  297. else {
  298. // OOM. adjust numSlots so we don't free unallocated memory.
  299. numSlots = i;
  300. PK11_FreeSlotListElement(slotList, slotElement);
  301. rv = NS_ERROR_OUT_OF_MEMORY;
  302. goto loser;
  303. }
  304. }
  305. // Throw up the token list dialog and get back the token.
  306. rv = getNSSDialogs(getter_AddRefs(dialogs), NS_GET_IID(nsITokenDialogs),
  307. NS_TOKENDIALOGS_CONTRACTID);
  308. if (NS_FAILED(rv)) {
  309. goto loser;
  310. }
  311. if (!tokenNameList || !*tokenNameList) {
  312. rv = NS_ERROR_OUT_OF_MEMORY;
  313. } else {
  314. rv = dialogs->ChooseToken(m_ctx, (const char16_t**)tokenNameList,
  315. numSlots, &unicodeTokenChosen, &canceled);
  316. }
  317. if (NS_FAILED(rv)) goto loser;
  318. if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
  319. // Get the slot //
  320. slotElement = PK11_GetFirstSafe(slotList);
  321. nsAutoString tokenStr(unicodeTokenChosen);
  322. while (slotElement) {
  323. if (tokenStr.Equals(NS_ConvertUTF8toUTF16(PK11_GetTokenName(slotElement->slot)))) {
  324. *aSlot = slotElement->slot;
  325. PK11_FreeSlotListElement(slotList, slotElement);
  326. break;
  327. }
  328. slotElement = PK11_GetNextSafe(slotList, slotElement, false);
  329. }
  330. if(!(*aSlot)) {
  331. rv = NS_ERROR_FAILURE;
  332. goto loser;
  333. }
  334. }
  335. // Get a reference to the slot //
  336. PK11_ReferenceSlot(*aSlot);
  337. loser:
  338. if (slotList) {
  339. PK11_FreeSlotList(slotList);
  340. }
  341. if (tokenNameList) {
  342. NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList);
  343. }
  344. return rv;
  345. }
  346. nsresult
  347. nsKeygenFormProcessor::GetPublicKey(const nsAString& aValue,
  348. const nsAString& aChallenge,
  349. const nsAFlatString& aKeyType,
  350. nsAString& aOutPublicKey,
  351. const nsAString& aKeyParams)
  352. {
  353. nsNSSShutDownPreventionLock locker;
  354. if (isAlreadyShutDown()) {
  355. return NS_ERROR_NOT_AVAILABLE;
  356. }
  357. nsresult rv = NS_ERROR_FAILURE;
  358. UniquePORTString keystring;
  359. char *keyparamsString = nullptr;
  360. uint32_t keyGenMechanism;
  361. PK11SlotInfo *slot = nullptr;
  362. PK11RSAGenParams rsaParams;
  363. mozilla::UniqueSECItem ecParams;
  364. SECOidTag algTag;
  365. int keysize = 0;
  366. void *params = nullptr; // Non-owning.
  367. SECKEYPrivateKey *privateKey = nullptr;
  368. SECKEYPublicKey *publicKey = nullptr;
  369. CERTSubjectPublicKeyInfo *spkInfo = nullptr;
  370. SECStatus srv = SECFailure;
  371. SECItem spkiItem;
  372. SECItem pkacItem;
  373. SECItem signedItem;
  374. CERTPublicKeyAndChallenge pkac;
  375. pkac.challenge.data = nullptr;
  376. nsCOMPtr<nsIGeneratingKeypairInfoDialogs> dialogs;
  377. nsKeygenThread *KeygenRunnable = 0;
  378. nsCOMPtr<nsIKeygenThread> runnable;
  379. // permanent and sensitive flags for keygen
  380. PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
  381. UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  382. if (!arena) {
  383. goto loser;
  384. }
  385. // Get the key size //
  386. for (size_t i = 0; i < number_of_key_size_choices; ++i) {
  387. if (aValue.Equals(mSECKeySizeChoiceList[i].name)) {
  388. keysize = mSECKeySizeChoiceList[i].size;
  389. break;
  390. }
  391. }
  392. if (!keysize) {
  393. goto loser;
  394. }
  395. // Set the keygen mechanism
  396. if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) {
  397. keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
  398. } else if (aKeyType.LowerCaseEqualsLiteral("ec")) {
  399. keyparamsString = ToNewCString(aKeyParams);
  400. if (!keyparamsString) {
  401. rv = NS_ERROR_OUT_OF_MEMORY;
  402. goto loser;
  403. }
  404. keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
  405. /* ecParams are initialized later */
  406. } else {
  407. goto loser;
  408. }
  409. // Get the slot
  410. rv = GetSlot(keyGenMechanism, &slot);
  411. if (NS_FAILED(rv)) {
  412. goto loser;
  413. }
  414. switch (keyGenMechanism) {
  415. case CKM_RSA_PKCS_KEY_PAIR_GEN:
  416. rsaParams.keySizeInBits = keysize;
  417. rsaParams.pe = DEFAULT_RSA_KEYGEN_PE;
  418. algTag = DEFAULT_RSA_KEYGEN_ALG;
  419. params = &rsaParams;
  420. break;
  421. case CKM_EC_KEY_PAIR_GEN:
  422. /* XXX We ought to rethink how the KEYGEN tag is
  423. * displayed. The pulldown selections presented
  424. * to the user must depend on the keytype.
  425. * The displayed selection could be picked
  426. * from the keyparams attribute (this is currently called
  427. * the pqg attribute).
  428. * For now, we pick ecparams from the keyparams field
  429. * if it specifies a valid supported curve, or else
  430. * we pick one of secp384r1, secp256r1 or secp192r1
  431. * respectively depending on the user's selection
  432. * (High, Medium, Low).
  433. * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical
  434. * reasons, while ECC choices represent a stronger mapping)
  435. * NOTE: The user's selection
  436. * is silently ignored when a valid curve is presented
  437. * in keyparams.
  438. */
  439. ecParams = DecodeECParams(keyparamsString);
  440. if (!ecParams) {
  441. /* The keyparams attribute did not specify a valid
  442. * curve name so use a curve based on the keysize.
  443. * NOTE: Here keysize is used only as an indication of
  444. * High/Medium/Low strength; elliptic curve
  445. * cryptography uses smaller keys than RSA to provide
  446. * equivalent security.
  447. */
  448. switch (keysize) {
  449. case 2048:
  450. ecParams = DecodeECParams("secp384r1");
  451. break;
  452. case 1024:
  453. case 512:
  454. ecParams = DecodeECParams("secp256r1");
  455. break;
  456. }
  457. }
  458. MOZ_ASSERT(ecParams);
  459. params = ecParams.get();
  460. /* XXX The signature algorithm ought to choose the hashing
  461. * algorithm based on key size once ECDSA variations based
  462. * on SHA256 SHA384 and SHA512 are standardized.
  463. */
  464. algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
  465. break;
  466. default:
  467. goto loser;
  468. }
  469. /* Make sure token is initialized. */
  470. rv = setPassword(slot, m_ctx, locker);
  471. if (NS_FAILED(rv))
  472. goto loser;
  473. srv = PK11_Authenticate(slot, true, m_ctx);
  474. if (srv != SECSuccess) {
  475. goto loser;
  476. }
  477. rv = getNSSDialogs(getter_AddRefs(dialogs),
  478. NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
  479. NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
  480. if (NS_SUCCEEDED(rv)) {
  481. KeygenRunnable = new nsKeygenThread();
  482. NS_IF_ADDREF(KeygenRunnable);
  483. }
  484. if (NS_FAILED(rv) || !KeygenRunnable) {
  485. rv = NS_OK;
  486. privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism, params,
  487. &publicKey, attrFlags, m_ctx);
  488. } else {
  489. KeygenRunnable->SetParams( slot, attrFlags, nullptr, 0,
  490. keyGenMechanism, params, m_ctx );
  491. runnable = do_QueryInterface(KeygenRunnable);
  492. if (runnable) {
  493. rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable);
  494. // We call join on the thread so we can be sure that no
  495. // simultaneous access to the passed parameters will happen.
  496. KeygenRunnable->Join();
  497. if (NS_SUCCEEDED(rv)) {
  498. PK11SlotInfo *used_slot = nullptr;
  499. rv = KeygenRunnable->ConsumeResult(&used_slot, &privateKey, &publicKey);
  500. if (NS_SUCCEEDED(rv) && used_slot) {
  501. PK11_FreeSlot(used_slot);
  502. }
  503. }
  504. }
  505. }
  506. if (NS_FAILED(rv) || !privateKey) {
  507. goto loser;
  508. }
  509. // just in case we'll need to authenticate to the db -jp //
  510. privateKey->wincx = m_ctx;
  511. /*
  512. * Create a subject public key info from the public key.
  513. */
  514. spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
  515. if ( !spkInfo ) {
  516. goto loser;
  517. }
  518. /*
  519. * Now DER encode the whole subjectPublicKeyInfo.
  520. */
  521. srv = DER_Encode(arena.get(), &spkiItem, CERTSubjectPublicKeyInfoTemplate,
  522. spkInfo);
  523. if (srv != SECSuccess) {
  524. goto loser;
  525. }
  526. /*
  527. * set up the PublicKeyAndChallenge data structure, then DER encode it
  528. */
  529. pkac.spki = spkiItem;
  530. pkac.challenge.len = aChallenge.Length();
  531. pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge);
  532. if (!pkac.challenge.data) {
  533. rv = NS_ERROR_OUT_OF_MEMORY;
  534. goto loser;
  535. }
  536. srv = DER_Encode(arena.get(), &pkacItem, CERTPublicKeyAndChallengeTemplate,
  537. &pkac);
  538. if (srv != SECSuccess) {
  539. goto loser;
  540. }
  541. /*
  542. * now sign the DER encoded PublicKeyAndChallenge
  543. */
  544. srv = SEC_DerSignData(arena.get(), &signedItem, pkacItem.data, pkacItem.len,
  545. privateKey, algTag);
  546. if (srv != SECSuccess) {
  547. goto loser;
  548. }
  549. /*
  550. * Convert the signed public key and challenge into base64/ascii.
  551. */
  552. keystring = UniquePORTString(
  553. BTOA_DataToAscii(signedItem.data, signedItem.len));
  554. if (!keystring) {
  555. rv = NS_ERROR_OUT_OF_MEMORY;
  556. goto loser;
  557. }
  558. CopyASCIItoUTF16(keystring.get(), aOutPublicKey);
  559. rv = NS_OK;
  560. loser:
  561. if (srv != SECSuccess) {
  562. if ( privateKey ) {
  563. PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
  564. }
  565. if ( publicKey ) {
  566. PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
  567. }
  568. }
  569. if ( spkInfo ) {
  570. SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
  571. }
  572. if ( publicKey ) {
  573. SECKEY_DestroyPublicKey(publicKey);
  574. }
  575. if ( privateKey ) {
  576. SECKEY_DestroyPrivateKey(privateKey);
  577. }
  578. if (slot) {
  579. PK11_FreeSlot(slot);
  580. }
  581. if (KeygenRunnable) {
  582. NS_RELEASE(KeygenRunnable);
  583. }
  584. if (keyparamsString) {
  585. free(keyparamsString);
  586. }
  587. if (pkac.challenge.data) {
  588. free(pkac.challenge.data);
  589. }
  590. return rv;
  591. }
  592. // static
  593. void
  594. nsKeygenFormProcessor::ExtractParams(nsIDOMHTMLElement* aElement,
  595. nsAString& challengeValue,
  596. nsAString& keyTypeValue,
  597. nsAString& keyParamsValue)
  598. {
  599. aElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
  600. if (keyTypeValue.IsEmpty()) {
  601. // If this field is not present, we default to rsa.
  602. keyTypeValue.AssignLiteral("rsa");
  603. }
  604. aElement->GetAttribute(NS_LITERAL_STRING("pqg"),
  605. keyParamsValue);
  606. /* XXX We can still support the pqg attribute in the keygen
  607. * tag for backward compatibility while introducing a more
  608. * general attribute named keyparams.
  609. */
  610. if (keyParamsValue.IsEmpty()) {
  611. aElement->GetAttribute(NS_LITERAL_STRING("keyparams"),
  612. keyParamsValue);
  613. }
  614. aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
  615. }
  616. nsresult
  617. nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement* aElement,
  618. const nsAString& aName,
  619. nsAString& aValue)
  620. {
  621. nsAutoString challengeValue;
  622. nsAutoString keyTypeValue;
  623. nsAutoString keyParamsValue;
  624. ExtractParams(aElement, challengeValue, keyTypeValue, keyParamsValue);
  625. return GetPublicKey(aValue, challengeValue, keyTypeValue,
  626. aValue, keyParamsValue);
  627. }
  628. nsresult
  629. nsKeygenFormProcessor::ProcessValueIPC(const nsAString& aOldValue,
  630. const nsAString& aChallenge,
  631. const nsAString& aKeyType,
  632. const nsAString& aKeyParams,
  633. nsAString& newValue)
  634. {
  635. return GetPublicKey(aOldValue, aChallenge, PromiseFlatString(aKeyType),
  636. newValue, aKeyParams);
  637. }
  638. nsresult
  639. nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType,
  640. nsTArray<nsString>& aContent,
  641. nsAString& aAttribute)
  642. {
  643. if (Compare(aFormType, NS_LITERAL_STRING("SELECT"),
  644. nsCaseInsensitiveStringComparator()) == 0) {
  645. for (size_t i = 0; i < number_of_key_size_choices; ++i) {
  646. aContent.AppendElement(mSECKeySizeChoiceList[i].name);
  647. }
  648. aAttribute.AssignLiteral("-mozilla-keygen");
  649. }
  650. return NS_OK;
  651. }