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