PageRenderTime 97ms CodeModel.GetById 18ms app.highlight 72ms RepoModel.GetById 1ms app.codeStats 0ms

/security/manager/ssl/src/nsKeygenHandler.cpp

http://github.com/zpao/v8monkey
C++ | 848 lines | 636 code | 92 blank | 120 comment | 117 complexity | 1ee60626f43088d0405af000c965bbdf MD5 | raw file
  1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2 *
  3 * ***** BEGIN LICENSE BLOCK *****
  4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5 *
  6 * The contents of this file are subject to the Mozilla Public License Version
  7 * 1.1 (the "License"); you may not use this file except in compliance with
  8 * the License. You may obtain a copy of the License at
  9 * http://www.mozilla.org/MPL/
 10 *
 11 * Software distributed under the License is distributed on an "AS IS" basis,
 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 13 * for the specific language governing rights and limitations under the
 14 * License.
 15 *
 16 * The Original Code is mozilla.org code.
 17 *
 18 * The Initial Developer of the Original Code is
 19 * Netscape Communications Corporation.
 20 * Portions created by the Initial Developer are Copyright (C) 1998
 21 * the Initial Developer. All Rights Reserved.
 22 *
 23 * Contributor(s):
 24 *   Vipul Gupta <vipul.gupta@sun.com>
 25 *   Douglas Stebila <douglas@stebila.ca>
 26 *
 27 * Alternatively, the contents of this file may be used under the terms of
 28 * either the GNU General Public License Version 2 or later (the "GPL"), or
 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 30 * in which case the provisions of the GPL or the LGPL are applicable instead
 31 * of those above. If you wish to allow use of your version of this file only
 32 * under the terms of either the GPL or the LGPL, and not to allow others to
 33 * use your version of this file under the terms of the MPL, indicate your
 34 * decision by deleting the provisions above and replace them with the notice
 35 * and other provisions required by the GPL or the LGPL. If you do not delete
 36 * the provisions above, a recipient may use your version of this file under
 37 * the terms of any one of the MPL, the GPL or the LGPL.
 38 *
 39 * ***** END LICENSE BLOCK ***** */
 40
 41extern "C" {
 42#include "secdert.h"
 43}
 44#include "nspr.h"
 45#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
 46#include "keyhi.h"
 47#include "secder.h"
 48#include "cryptohi.h"
 49#include "base64.h"
 50#include "secasn1.h"
 51extern "C" {
 52#include "pk11pqg.h"
 53}
 54#include "nsKeygenHandler.h"
 55#include "nsVoidArray.h"
 56#include "nsIServiceManager.h"
 57#include "nsIDOMHTMLSelectElement.h"
 58#include "nsIContent.h"
 59#include "nsKeygenThread.h"
 60#include "nsReadableUtils.h"
 61#include "nsUnicharUtils.h"
 62#include "nsCRT.h"
 63#include "nsITokenDialogs.h"
 64#include "nsIGenKeypairInfoDlg.h"
 65#include "nsNSSShutDown.h"
 66
 67//These defines are taken from the PKCS#11 spec
 68#define CKM_RSA_PKCS_KEY_PAIR_GEN     0x00000000
 69#define CKM_DH_PKCS_KEY_PAIR_GEN      0x00000020
 70#define CKM_DSA_KEY_PAIR_GEN          0x00000010
 71
 72DERTemplate SECAlgorithmIDTemplate[] = {
 73    { DER_SEQUENCE,
 74          0, NULL, sizeof(SECAlgorithmID) },
 75    { DER_OBJECT_ID,
 76          offsetof(SECAlgorithmID,algorithm), },
 77    { DER_OPTIONAL | DER_ANY,
 78          offsetof(SECAlgorithmID,parameters), },
 79    { 0, }
 80};
 81
 82DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
 83    { DER_SEQUENCE,
 84          0, nsnull, sizeof(CERTSubjectPublicKeyInfo) },
 85    { DER_INLINE,
 86          offsetof(CERTSubjectPublicKeyInfo,algorithm),
 87          SECAlgorithmIDTemplate, },
 88    { DER_BIT_STRING,
 89          offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
 90    { 0, }
 91};
 92
 93DERTemplate CERTPublicKeyAndChallengeTemplate[] =
 94{
 95    { DER_SEQUENCE, 0, nsnull, sizeof(CERTPublicKeyAndChallenge) },
 96    { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
 97    { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
 98    { 0, }
 99};
100
101const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
102    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) },
103    { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) },
104    { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) },
105    { SEC_ASN1_INTEGER, offsetof(PQGParams,base) },
106    { 0, }
107};
108
109
110static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
111static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
112
113static PQGParams *
114decode_pqg_params(char *aStr)
115{
116    unsigned char *buf = nsnull;
117    unsigned int len;
118    PRArenaPool *arena = nsnull;
119    PQGParams *params = nsnull;
120    SECStatus status;
121
122    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
123    if (!arena)
124        return nsnull;
125
126    params = static_cast<PQGParams*>(PORT_ArenaZAlloc(arena, sizeof(PQGParams)));
127    if (!params)
128        goto loser;
129    params->arena = arena;
130
131    buf = ATOB_AsciiToData(aStr, &len);
132    if ((!buf) || (len == 0))
133        goto loser;
134
135    status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len);
136    if (status != SECSuccess)
137        goto loser;
138
139    return params;
140
141loser:
142    if (arena) {
143      PORT_FreeArena(arena, false);
144    }
145    if (buf) {
146      PR_Free(buf);
147    }
148    return nsnull;
149}
150
151static int
152pqg_prime_bits(char *str)
153{
154    PQGParams *params = nsnull;
155    int primeBits = 0, i;
156
157    params = decode_pqg_params(str);
158    if (!params)
159        goto done; /* lose */
160
161    for (i = 0; params->prime.data[i] == 0; i++)
162        /* empty */;
163    primeBits = (params->prime.len - i) * 8;
164
165done:
166    if (params)
167        PK11_PQG_DestroyParams(params);
168    return primeBits;
169}
170
171typedef struct curveNameTagPairStr {
172    const char *curveName;
173    SECOidTag curveOidTag;
174} CurveNameTagPair;
175
176static CurveNameTagPair nameTagPair[] =
177{ 
178  { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
179  { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
180  { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
181  { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
182  { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
183  { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
184  { "prime256v1", SEC_OID_ANSIX962_EC_PRIME256V1 },
185
186  { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
187  { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
188  { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
189  { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
190  { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
191  { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
192  { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
193  { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
194  { "secp192r1", SEC_OID_ANSIX962_EC_PRIME192V1 },
195  { "nistp192", SEC_OID_ANSIX962_EC_PRIME192V1 },
196  { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
197  { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
198  { "nistp224", SEC_OID_SECG_EC_SECP224R1},
199  { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
200  { "secp256r1", SEC_OID_ANSIX962_EC_PRIME256V1 },
201  { "nistp256", SEC_OID_ANSIX962_EC_PRIME256V1 },
202  { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
203  { "nistp384", SEC_OID_SECG_EC_SECP384R1},
204  { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
205  { "nistp521", SEC_OID_SECG_EC_SECP521R1},
206
207  { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
208  { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
209  { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
210  { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
211  { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
212  { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
213  { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
214  { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
215  { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
216  { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
217  { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
218  { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
219  { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
220  { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
221  { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
222  { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
223  { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
224  { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
225  { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
226  { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
227
228  { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
229  { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
230  { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
231  { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
232  { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
233  { "nistk163", SEC_OID_SECG_EC_SECT163K1},
234  { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
235  { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
236  { "nistb163", SEC_OID_SECG_EC_SECT163R2},
237  { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
238  { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
239  { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
240  { "nistk233", SEC_OID_SECG_EC_SECT233K1},
241  { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
242  { "nistb233", SEC_OID_SECG_EC_SECT233R1},
243  { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
244  { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
245  { "nistk283", SEC_OID_SECG_EC_SECT283K1},
246  { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
247  { "nistb283", SEC_OID_SECG_EC_SECT283R1},
248  { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
249  { "nistk409", SEC_OID_SECG_EC_SECT409K1},
250  { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
251  { "nistb409", SEC_OID_SECG_EC_SECT409R1},
252  { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
253  { "nistk571", SEC_OID_SECG_EC_SECT571K1},
254  { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
255  { "nistb571", SEC_OID_SECG_EC_SECT571R1},
256
257};
258
259SECKEYECParams * 
260decode_ec_params(const char *curve)
261{
262    SECKEYECParams *ecparams;
263    SECOidData *oidData = NULL;
264    SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
265    int i, numCurves;
266
267    if (curve && *curve) {
268        numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
269        for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); 
270             i++) {
271            if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
272                curveOidTag = nameTagPair[i].curveOidTag;
273        }
274    }
275
276    /* Return NULL if curve name is not recognized */
277    if ((curveOidTag == SEC_OID_UNKNOWN) || 
278        (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
279        return nsnull;
280    }
281
282    ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
283
284    if (!ecparams)
285      return nsnull;
286
287    /* 
288     * ecparams->data needs to contain the ASN encoding of an object ID (OID)
289     * representing the named curve. The actual OID is in 
290     * oidData->oid.data so we simply prepend 0x06 and OID length
291     */
292    ecparams->data[0] = SEC_ASN1_OBJECT_ID;
293    ecparams->data[1] = oidData->oid.len;
294    memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
295
296    return ecparams;
297}
298
299NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor)
300
301nsKeygenFormProcessor::nsKeygenFormProcessor()
302{ 
303   m_ctx = new PipUIContext();
304
305} 
306
307nsKeygenFormProcessor::~nsKeygenFormProcessor()
308{
309}
310
311nsresult
312nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
313{
314  nsresult rv;
315  NS_ENSURE_NO_AGGREGATION(aOuter);
316  nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
317  if (!formProc)
318    return NS_ERROR_OUT_OF_MEMORY;
319
320  nsCOMPtr<nsISupports> stabilize = formProc;
321  rv = formProc->Init();
322  if (NS_SUCCEEDED(rv)) {
323    rv = formProc->QueryInterface(aIID, aResult);
324  }
325  return rv;
326}
327
328nsresult
329nsKeygenFormProcessor::Init()
330{
331  nsresult rv;
332
333  nsCOMPtr<nsINSSComponent> nssComponent;
334  nssComponent = do_GetService(kNSSComponentCID, &rv);
335  if (NS_FAILED(rv))
336    return rv;
337
338  // Init possible key size choices.
339  nssComponent->GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name);
340  mSECKeySizeChoiceList[0].size = 2048;
341
342  nssComponent->GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name);
343  mSECKeySizeChoiceList[1].size = 1024;
344
345  return NS_OK;
346}
347
348nsresult
349nsKeygenFormProcessor::GetSlot(PRUint32 aMechanism, PK11SlotInfo** aSlot)
350{
351  return GetSlotWithMechanism(aMechanism,m_ctx,aSlot);
352}
353
354
355PRUint32 MapGenMechToAlgoMech(PRUint32 mechanism)
356{
357    PRUint32 searchMech;
358
359    /* We are interested in slots based on the ability to perform
360       a given algorithm, not on their ability to generate keys usable
361       by that algorithm. Therefore, map keygen-specific mechanism tags
362       to tags for the corresponding crypto algorthm. */
363    switch(mechanism)
364    {
365    case CKM_RSA_PKCS_KEY_PAIR_GEN:
366        searchMech = CKM_RSA_PKCS;
367        break;
368    case CKM_DSA_KEY_PAIR_GEN:
369        searchMech = CKM_DSA;
370        break;
371    case CKM_RC4_KEY_GEN:
372        searchMech = CKM_RC4;
373        break;
374    case CKM_DH_PKCS_KEY_PAIR_GEN:
375        searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch  is this right? */
376        break;
377    case CKM_DES_KEY_GEN:
378        /* What do we do about DES keygen? Right now, we're just using
379           DES_KEY_GEN to look for tokens, because otherwise we'll have
380           to search the token list three times. */
381    case CKM_EC_KEY_PAIR_GEN:
382        /* The default should also work for EC key pair generation. */
383    default:
384        searchMech = mechanism;
385        break;
386    }
387    return searchMech;
388}
389
390
391nsresult
392GetSlotWithMechanism(PRUint32 aMechanism, 
393                     nsIInterfaceRequestor *m_ctx,
394                     PK11SlotInfo** aSlot)
395{
396    nsNSSShutDownPreventionLock locker;
397    PK11SlotList * slotList = nsnull;
398    PRUnichar** tokenNameList = nsnull;
399    nsITokenDialogs * dialogs;
400    PRUnichar *unicodeTokenChosen;
401    PK11SlotListElement *slotElement, *tmpSlot;
402    PRUint32 numSlots = 0, i = 0;
403    bool canceled;
404    nsresult rv = NS_OK;
405
406    *aSlot = nsnull;
407
408    // Get the slot
409    slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism), 
410                                true, true, m_ctx);
411    if (!slotList || !slotList->head) {
412        rv = NS_ERROR_FAILURE;
413        goto loser;
414    }
415
416    if (!slotList->head->next) {
417        /* only one slot available, just return it */
418        *aSlot = slotList->head->slot;
419      } else {
420        // Gerenate a list of slots and ask the user to choose //
421        tmpSlot = slotList->head;
422        while (tmpSlot) {
423            numSlots++;
424            tmpSlot = tmpSlot->next;
425        }
426
427        // Allocate the slot name buffer //
428        tokenNameList = static_cast<PRUnichar**>(nsMemory::Alloc(sizeof(PRUnichar *) * numSlots));
429        if (!tokenNameList) {
430            rv = NS_ERROR_OUT_OF_MEMORY;
431            goto loser;
432        }
433
434        i = 0;
435        slotElement = PK11_GetFirstSafe(slotList);
436        while (slotElement) {
437            tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot)));
438            slotElement = PK11_GetNextSafe(slotList, slotElement, false);
439            if (tokenNameList[i])
440                i++;
441            else {
442                // OOM. adjust numSlots so we don't free unallocated memory. 
443                numSlots = i;
444                PK11_FreeSlotListElement(slotList, slotElement);
445                rv = NS_ERROR_OUT_OF_MEMORY;
446                goto loser;
447            }
448        }
449
450		/* Throw up the token list dialog and get back the token */
451		rv = getNSSDialogs((void**)&dialogs,
452			               NS_GET_IID(nsITokenDialogs),
453                     NS_TOKENDIALOGS_CONTRACTID);
454
455		if (NS_FAILED(rv)) goto loser;
456
457    {
458      nsPSMUITracker tracker;
459      if (!tokenNameList || !*tokenNameList) {
460          rv = NS_ERROR_OUT_OF_MEMORY;
461      }
462      else if (tracker.isUIForbidden()) {
463        rv = NS_ERROR_NOT_AVAILABLE;
464      }
465      else {
466        rv = dialogs->ChooseToken(m_ctx, (const PRUnichar**)tokenNameList, numSlots, &unicodeTokenChosen, &canceled);
467      }
468    }
469		NS_RELEASE(dialogs);
470		if (NS_FAILED(rv)) goto loser;
471
472		if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
473
474        // Get the slot //
475        slotElement = PK11_GetFirstSafe(slotList);
476        nsAutoString tokenStr(unicodeTokenChosen);
477        while (slotElement) {
478            if (tokenStr.Equals(NS_ConvertUTF8toUTF16(PK11_GetTokenName(slotElement->slot)))) {
479                *aSlot = slotElement->slot;
480                PK11_FreeSlotListElement(slotList, slotElement);
481                break;
482            }
483            slotElement = PK11_GetNextSafe(slotList, slotElement, false);
484        }
485        if(!(*aSlot)) {
486            rv = NS_ERROR_FAILURE;
487            goto loser;
488        }
489      }
490
491      // Get a reference to the slot //
492      PK11_ReferenceSlot(*aSlot);
493loser:
494      if (slotList) {
495          PK11_FreeSlotList(slotList);
496      }
497      if (tokenNameList) {
498          NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList);
499      }
500      return rv;
501}
502
503nsresult
504nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge, 
505				    nsAFlatString& aKeyType,
506				    nsAString& aOutPublicKey, nsAString& aKeyParams)
507{
508    nsNSSShutDownPreventionLock locker;
509    nsresult rv = NS_ERROR_FAILURE;
510    char *keystring = nsnull;
511    char *keyparamsString = nsnull, *str = nsnull;
512    KeyType type;
513    PRUint32 keyGenMechanism;
514    PRInt32 primeBits;
515    PK11SlotInfo *slot = nsnull;
516    PK11RSAGenParams rsaParams;
517    SECOidTag algTag;
518    int keysize = 0;
519    void *params;
520    SECKEYPrivateKey *privateKey = nsnull;
521    SECKEYPublicKey *publicKey = nsnull;
522    CERTSubjectPublicKeyInfo *spkInfo = nsnull;
523    PRArenaPool *arena = nsnull;
524    SECStatus sec_rv = SECFailure;
525    SECItem spkiItem;
526    SECItem pkacItem;
527    SECItem signedItem;
528    CERTPublicKeyAndChallenge pkac;
529    pkac.challenge.data = nsnull;
530    nsIGeneratingKeypairInfoDialogs * dialogs;
531    nsKeygenThread *KeygenRunnable = 0;
532    nsCOMPtr<nsIKeygenThread> runnable;
533
534    // Get the key size //
535    for (size_t i = 0; i < number_of_key_size_choices; ++i) {
536        if (aValue.Equals(mSECKeySizeChoiceList[i].name)) {
537            keysize = mSECKeySizeChoiceList[i].size;
538            break;
539        }
540    }
541    if (!keysize) {
542        goto loser;
543    }
544
545    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
546    if (!arena) {
547        goto loser;
548    }
549
550    // Set the keygen mechanism
551    if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) {
552        type = rsaKey;
553        keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
554    } else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
555        char * end;
556        keyparamsString = ToNewCString(aKeyParams);
557        if (!keyparamsString) {
558            rv = NS_ERROR_OUT_OF_MEMORY;
559            goto loser;
560        }
561
562        type = dsaKey;
563        keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
564        if (strcmp(keyparamsString, "null") == 0)
565            goto loser;
566        str = keyparamsString;
567        bool found_match = false;
568        do {
569            end = strchr(str, ',');
570            if (end != nsnull)
571                *end = '\0';
572            primeBits = pqg_prime_bits(str);
573            if (keysize == primeBits) {
574                found_match = true;
575                break;
576            }
577            str = end + 1;
578        } while (end != nsnull);
579        if (!found_match) {
580            goto loser;
581        }
582    } else if (aKeyType.LowerCaseEqualsLiteral("ec")) {
583        keyparamsString = ToNewCString(aKeyParams);
584        if (!keyparamsString) {
585            rv = NS_ERROR_OUT_OF_MEMORY;
586            goto loser;
587        }
588
589        type = ecKey;
590        keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
591        /* ecParams are initialized later */
592    } else {
593        goto loser;
594    }
595
596    // Get the slot
597    rv = GetSlot(keyGenMechanism, &slot);
598    if (NS_FAILED(rv)) {
599        goto loser;
600    }
601    switch (keyGenMechanism) {
602        case CKM_RSA_PKCS_KEY_PAIR_GEN:
603            rsaParams.keySizeInBits = keysize;
604            rsaParams.pe = DEFAULT_RSA_KEYGEN_PE;
605            algTag = DEFAULT_RSA_KEYGEN_ALG;
606            params = &rsaParams;
607            break;
608        case CKM_DSA_KEY_PAIR_GEN:
609            // XXX Fix this! XXX //
610            goto loser;
611        case CKM_EC_KEY_PAIR_GEN:
612            /* XXX We ought to rethink how the KEYGEN tag is 
613             * displayed. The pulldown selections presented
614             * to the user must depend on the keytype.
615             * The displayed selection could be picked
616             * from the keyparams attribute (this is currently called
617             * the pqg attribute).
618             * For now, we pick ecparams from the keyparams field
619             * if it specifies a valid supported curve, or else 
620             * we pick one of secp384r1, secp256r1 or secp192r1
621             * respectively depending on the user's selection
622             * (High, Medium, Low). 
623             * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical
624             * reasons, while ECC choices represent a stronger mapping)
625             * NOTE: The user's selection
626             * is silently ignored when a valid curve is presented
627             * in keyparams.
628             */
629            if ((params = decode_ec_params(keyparamsString)) == nsnull) {
630                /* The keyparams attribute did not specify a valid
631                 * curve name so use a curve based on the keysize.
632                 * NOTE: Here keysize is used only as an indication of
633                 * High/Medium/Low strength; elliptic curve
634                 * cryptography uses smaller keys than RSA to provide
635                 * equivalent security.
636                 */
637                switch (keysize) {
638                case 2048:
639                    params = decode_ec_params("secp384r1");
640                    break;
641                case 1024:
642                case 512:
643                    params = decode_ec_params("secp256r1");
644                    break;
645                } 
646            }
647            /* XXX The signature algorithm ought to choose the hashing
648             * algorithm based on key size once ECDSA variations based
649             * on SHA256 SHA384 and SHA512 are standardized.
650             */
651            algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
652            break;
653      default:
654          goto loser;
655      }
656
657    /* Make sure token is initialized. */
658    rv = setPassword(slot, m_ctx);
659    if (NS_FAILED(rv))
660        goto loser;
661
662    sec_rv = PK11_Authenticate(slot, true, m_ctx);
663    if (sec_rv != SECSuccess) {
664        goto loser;
665    }
666
667    rv = getNSSDialogs((void**)&dialogs,
668                       NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
669                       NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
670
671    if (NS_SUCCEEDED(rv)) {
672        KeygenRunnable = new nsKeygenThread();
673        NS_IF_ADDREF(KeygenRunnable);
674    }
675
676    if (NS_FAILED(rv) || !KeygenRunnable) {
677        rv = NS_OK;
678        privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism, params,
679                                          &publicKey, true, true, m_ctx);
680    } else {
681        KeygenRunnable->SetParams( slot, keyGenMechanism, params, true, true, m_ctx );
682
683        runnable = do_QueryInterface(KeygenRunnable);
684        
685        if (runnable) {
686            {
687              nsPSMUITracker tracker;
688              if (tracker.isUIForbidden()) {
689                rv = NS_ERROR_NOT_AVAILABLE;
690              }
691              else {
692                rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable);
693                // We call join on the thread, 
694                // so we can be sure that no simultaneous access to the passed parameters will happen.
695                KeygenRunnable->Join();
696              }
697            }
698
699            NS_RELEASE(dialogs);
700            if (NS_SUCCEEDED(rv)) {
701                rv = KeygenRunnable->GetParams(&privateKey, &publicKey);
702            }
703        }
704    }
705    
706    if (NS_FAILED(rv) || !privateKey) {
707        goto loser;
708    }
709    // just in case we'll need to authenticate to the db -jp //
710    privateKey->wincx = m_ctx;
711
712    /*
713     * Create a subject public key info from the public key.
714     */
715    spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
716    if ( !spkInfo ) {
717        goto loser;
718    }
719    
720    /*
721     * Now DER encode the whole subjectPublicKeyInfo.
722     */
723    sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo);
724    if (sec_rv != SECSuccess) {
725        goto loser;
726    }
727
728    /*
729     * set up the PublicKeyAndChallenge data structure, then DER encode it
730     */
731    pkac.spki = spkiItem;
732    pkac.challenge.len = aChallenge.Length();
733    pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge);
734    if (!pkac.challenge.data) {
735        rv = NS_ERROR_OUT_OF_MEMORY;
736        goto loser;
737    }
738    
739    sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
740    if ( sec_rv != SECSuccess ) {
741        goto loser;
742    }
743
744    /*
745     * now sign the DER encoded PublicKeyAndChallenge
746     */
747    sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
748			 privateKey, algTag);
749    if ( sec_rv != SECSuccess ) {
750        goto loser;
751    }
752    
753    /*
754     * Convert the signed public key and challenge into base64/ascii.
755     */
756    keystring = BTOA_DataToAscii(signedItem.data, signedItem.len);
757    if (!keystring) {
758        rv = NS_ERROR_OUT_OF_MEMORY;
759        goto loser;
760    }
761
762    CopyASCIItoUTF16(keystring, aOutPublicKey);
763    nsCRT::free(keystring);
764
765    rv = NS_OK;
766loser:
767    if ( sec_rv != SECSuccess ) {
768        if ( privateKey ) {
769            PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
770        }
771        if ( publicKey ) {
772            PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
773        }
774    }
775    if ( spkInfo ) {
776        SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
777    }
778    if ( publicKey ) {
779        SECKEY_DestroyPublicKey(publicKey);
780    }
781    if ( privateKey ) {
782        SECKEY_DestroyPrivateKey(privateKey);
783    }
784    if ( arena ) {
785        PORT_FreeArena(arena, true);
786    }
787    if (slot != nsnull) {
788        PK11_FreeSlot(slot);
789    }
790    if (KeygenRunnable) {
791        NS_RELEASE(KeygenRunnable);
792    }
793    if (keyparamsString) {
794        nsMemory::Free(keyparamsString);
795    }
796    if (pkac.challenge.data) {
797        nsMemory::Free(pkac.challenge.data);
798    }
799    return rv;
800}
801
802NS_METHOD 
803nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement, 
804				    const nsAString& aName, 
805				    nsAString& aValue) 
806{ 
807    nsAutoString challengeValue;
808    nsAutoString keyTypeValue;
809    nsAutoString keyParamsValue;
810    
811    aElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
812    if (keyTypeValue.IsEmpty()) {
813        // If this field is not present, we default to rsa.
814        keyTypeValue.AssignLiteral("rsa");
815    }
816    
817    aElement->GetAttribute(NS_LITERAL_STRING("pqg"), 
818                           keyParamsValue);
819    /* XXX We can still support the pqg attribute in the keygen 
820     * tag for backward compatibility while introducing a more 
821     * general attribute named keyparams.
822     */
823    if (keyParamsValue.IsEmpty()) {
824        aElement->GetAttribute(NS_LITERAL_STRING("keyparams"), 
825                               keyParamsValue);
826    }
827
828    aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
829
830    return GetPublicKey(aValue, challengeValue, keyTypeValue, 
831                        aValue, keyParamsValue);
832} 
833
834NS_METHOD nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType, 
835						nsTArray<nsString>& aContent, 
836						nsAString& aAttribute) 
837{ 
838  if (Compare(aFormType, NS_LITERAL_STRING("SELECT"), 
839    nsCaseInsensitiveStringComparator()) == 0) {
840
841    for (size_t i = 0; i < number_of_key_size_choices; ++i) {
842      aContent.AppendElement(mSECKeySizeChoiceList[i].name);
843    }
844    aAttribute.AssignLiteral("-mozilla-keygen");
845  }
846  return NS_OK;
847} 
848