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 :
41 : extern "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"
51 : extern "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 :
72 : DERTemplate 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 :
82 : DERTemplate 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 :
93 : DERTemplate 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 :
101 : const 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 :
110 : static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
111 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
112 :
113 : static PQGParams *
114 0 : decode_pqg_params(char *aStr)
115 : {
116 0 : unsigned char *buf = nsnull;
117 : unsigned int len;
118 0 : PRArenaPool *arena = nsnull;
119 0 : PQGParams *params = nsnull;
120 : SECStatus status;
121 :
122 0 : arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
123 0 : if (!arena)
124 0 : return nsnull;
125 :
126 0 : params = static_cast<PQGParams*>(PORT_ArenaZAlloc(arena, sizeof(PQGParams)));
127 0 : if (!params)
128 0 : goto loser;
129 0 : params->arena = arena;
130 :
131 0 : buf = ATOB_AsciiToData(aStr, &len);
132 0 : if ((!buf) || (len == 0))
133 : goto loser;
134 :
135 0 : status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len);
136 0 : if (status != SECSuccess)
137 0 : goto loser;
138 :
139 0 : return params;
140 :
141 : loser:
142 0 : if (arena) {
143 0 : PORT_FreeArena(arena, false);
144 : }
145 0 : if (buf) {
146 0 : PR_Free(buf);
147 : }
148 0 : return nsnull;
149 : }
150 :
151 : static int
152 0 : pqg_prime_bits(char *str)
153 : {
154 0 : PQGParams *params = nsnull;
155 0 : int primeBits = 0, i;
156 :
157 0 : params = decode_pqg_params(str);
158 0 : if (!params)
159 0 : goto done; /* lose */
160 :
161 0 : for (i = 0; params->prime.data[i] == 0; i++)
162 : /* empty */;
163 0 : primeBits = (params->prime.len - i) * 8;
164 :
165 : done:
166 0 : if (params)
167 0 : PK11_PQG_DestroyParams(params);
168 0 : return primeBits;
169 : }
170 :
171 : typedef struct curveNameTagPairStr {
172 : const char *curveName;
173 : SECOidTag curveOidTag;
174 : } CurveNameTagPair;
175 :
176 : static 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 :
259 : SECKEYECParams *
260 0 : decode_ec_params(const char *curve)
261 : {
262 : SECKEYECParams *ecparams;
263 0 : SECOidData *oidData = NULL;
264 0 : SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
265 : int i, numCurves;
266 :
267 0 : if (curve && *curve) {
268 0 : numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
269 0 : for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
270 : i++) {
271 0 : if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
272 0 : curveOidTag = nameTagPair[i].curveOidTag;
273 : }
274 : }
275 :
276 : /* Return NULL if curve name is not recognized */
277 0 : if ((curveOidTag == SEC_OID_UNKNOWN) ||
278 : (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
279 0 : return nsnull;
280 : }
281 :
282 0 : ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
283 :
284 0 : if (!ecparams)
285 0 : 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 0 : ecparams->data[0] = SEC_ASN1_OBJECT_ID;
293 0 : ecparams->data[1] = oidData->oid.len;
294 0 : memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
295 :
296 0 : return ecparams;
297 : }
298 :
299 0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor)
300 :
301 0 : nsKeygenFormProcessor::nsKeygenFormProcessor()
302 : {
303 0 : m_ctx = new PipUIContext();
304 :
305 0 : }
306 :
307 0 : nsKeygenFormProcessor::~nsKeygenFormProcessor()
308 : {
309 0 : }
310 :
311 : nsresult
312 0 : nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
313 : {
314 : nsresult rv;
315 0 : NS_ENSURE_NO_AGGREGATION(aOuter);
316 0 : nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
317 0 : if (!formProc)
318 0 : return NS_ERROR_OUT_OF_MEMORY;
319 :
320 0 : nsCOMPtr<nsISupports> stabilize = formProc;
321 0 : rv = formProc->Init();
322 0 : if (NS_SUCCEEDED(rv)) {
323 0 : rv = formProc->QueryInterface(aIID, aResult);
324 : }
325 0 : return rv;
326 : }
327 :
328 : nsresult
329 0 : nsKeygenFormProcessor::Init()
330 : {
331 : nsresult rv;
332 :
333 0 : nsCOMPtr<nsINSSComponent> nssComponent;
334 0 : nssComponent = do_GetService(kNSSComponentCID, &rv);
335 0 : if (NS_FAILED(rv))
336 0 : return rv;
337 :
338 : // Init possible key size choices.
339 0 : nssComponent->GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name);
340 0 : mSECKeySizeChoiceList[0].size = 2048;
341 :
342 0 : nssComponent->GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name);
343 0 : mSECKeySizeChoiceList[1].size = 1024;
344 :
345 0 : return NS_OK;
346 : }
347 :
348 : nsresult
349 0 : nsKeygenFormProcessor::GetSlot(PRUint32 aMechanism, PK11SlotInfo** aSlot)
350 : {
351 0 : return GetSlotWithMechanism(aMechanism,m_ctx,aSlot);
352 : }
353 :
354 :
355 0 : PRUint32 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 0 : switch(mechanism)
364 : {
365 : case CKM_RSA_PKCS_KEY_PAIR_GEN:
366 0 : searchMech = CKM_RSA_PKCS;
367 0 : break;
368 : case CKM_DSA_KEY_PAIR_GEN:
369 0 : searchMech = CKM_DSA;
370 0 : break;
371 : case CKM_RC4_KEY_GEN:
372 0 : searchMech = CKM_RC4;
373 0 : break;
374 : case CKM_DH_PKCS_KEY_PAIR_GEN:
375 0 : searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch is this right? */
376 0 : 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 0 : searchMech = mechanism;
385 0 : break;
386 : }
387 0 : return searchMech;
388 : }
389 :
390 :
391 : nsresult
392 0 : GetSlotWithMechanism(PRUint32 aMechanism,
393 : nsIInterfaceRequestor *m_ctx,
394 : PK11SlotInfo** aSlot)
395 : {
396 0 : nsNSSShutDownPreventionLock locker;
397 0 : PK11SlotList * slotList = nsnull;
398 0 : PRUnichar** tokenNameList = nsnull;
399 : nsITokenDialogs * dialogs;
400 : PRUnichar *unicodeTokenChosen;
401 : PK11SlotListElement *slotElement, *tmpSlot;
402 0 : PRUint32 numSlots = 0, i = 0;
403 : bool canceled;
404 0 : nsresult rv = NS_OK;
405 :
406 0 : *aSlot = nsnull;
407 :
408 : // Get the slot
409 0 : slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism),
410 0 : true, true, m_ctx);
411 0 : if (!slotList || !slotList->head) {
412 0 : rv = NS_ERROR_FAILURE;
413 0 : goto loser;
414 : }
415 :
416 0 : if (!slotList->head->next) {
417 : /* only one slot available, just return it */
418 0 : *aSlot = slotList->head->slot;
419 : } else {
420 : // Gerenate a list of slots and ask the user to choose //
421 0 : tmpSlot = slotList->head;
422 0 : while (tmpSlot) {
423 0 : numSlots++;
424 0 : tmpSlot = tmpSlot->next;
425 : }
426 :
427 : // Allocate the slot name buffer //
428 0 : tokenNameList = static_cast<PRUnichar**>(nsMemory::Alloc(sizeof(PRUnichar *) * numSlots));
429 0 : if (!tokenNameList) {
430 0 : rv = NS_ERROR_OUT_OF_MEMORY;
431 0 : goto loser;
432 : }
433 :
434 0 : i = 0;
435 0 : slotElement = PK11_GetFirstSafe(slotList);
436 0 : while (slotElement) {
437 0 : tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot)));
438 0 : slotElement = PK11_GetNextSafe(slotList, slotElement, false);
439 0 : if (tokenNameList[i])
440 0 : i++;
441 : else {
442 : // OOM. adjust numSlots so we don't free unallocated memory.
443 0 : numSlots = i;
444 0 : PK11_FreeSlotListElement(slotList, slotElement);
445 0 : rv = NS_ERROR_OUT_OF_MEMORY;
446 0 : 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 0 : NS_TOKENDIALOGS_CONTRACTID);
454 :
455 0 : if (NS_FAILED(rv)) goto loser;
456 :
457 : {
458 0 : nsPSMUITracker tracker;
459 0 : if (!tokenNameList || !*tokenNameList) {
460 0 : rv = NS_ERROR_OUT_OF_MEMORY;
461 : }
462 0 : else if (tracker.isUIForbidden()) {
463 0 : rv = NS_ERROR_NOT_AVAILABLE;
464 : }
465 : else {
466 0 : rv = dialogs->ChooseToken(m_ctx, (const PRUnichar**)tokenNameList, numSlots, &unicodeTokenChosen, &canceled);
467 : }
468 : }
469 0 : NS_RELEASE(dialogs);
470 0 : if (NS_FAILED(rv)) goto loser;
471 :
472 0 : if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
473 :
474 : // Get the slot //
475 0 : slotElement = PK11_GetFirstSafe(slotList);
476 0 : nsAutoString tokenStr(unicodeTokenChosen);
477 0 : while (slotElement) {
478 0 : if (tokenStr.Equals(NS_ConvertUTF8toUTF16(PK11_GetTokenName(slotElement->slot)))) {
479 0 : *aSlot = slotElement->slot;
480 0 : PK11_FreeSlotListElement(slotList, slotElement);
481 0 : break;
482 : }
483 0 : slotElement = PK11_GetNextSafe(slotList, slotElement, false);
484 : }
485 0 : if(!(*aSlot)) {
486 0 : rv = NS_ERROR_FAILURE;
487 : goto loser;
488 : }
489 : }
490 :
491 : // Get a reference to the slot //
492 0 : PK11_ReferenceSlot(*aSlot);
493 : loser:
494 0 : if (slotList) {
495 0 : PK11_FreeSlotList(slotList);
496 : }
497 0 : if (tokenNameList) {
498 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList);
499 : }
500 0 : return rv;
501 : }
502 :
503 : nsresult
504 0 : nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
505 : nsAFlatString& aKeyType,
506 : nsAString& aOutPublicKey, nsAString& aKeyParams)
507 : {
508 0 : nsNSSShutDownPreventionLock locker;
509 0 : nsresult rv = NS_ERROR_FAILURE;
510 0 : char *keystring = nsnull;
511 0 : char *keyparamsString = nsnull, *str = nsnull;
512 : PRUint32 keyGenMechanism;
513 : PRInt32 primeBits;
514 0 : PK11SlotInfo *slot = nsnull;
515 : PK11RSAGenParams rsaParams;
516 : SECOidTag algTag;
517 0 : int keysize = 0;
518 : void *params;
519 0 : SECKEYPrivateKey *privateKey = nsnull;
520 0 : SECKEYPublicKey *publicKey = nsnull;
521 0 : CERTSubjectPublicKeyInfo *spkInfo = nsnull;
522 0 : PRArenaPool *arena = nsnull;
523 0 : SECStatus sec_rv = SECFailure;
524 : SECItem spkiItem;
525 : SECItem pkacItem;
526 : SECItem signedItem;
527 : CERTPublicKeyAndChallenge pkac;
528 0 : pkac.challenge.data = nsnull;
529 : nsIGeneratingKeypairInfoDialogs * dialogs;
530 0 : nsKeygenThread *KeygenRunnable = 0;
531 0 : nsCOMPtr<nsIKeygenThread> runnable;
532 :
533 : // Get the key size //
534 0 : for (size_t i = 0; i < number_of_key_size_choices; ++i) {
535 0 : if (aValue.Equals(mSECKeySizeChoiceList[i].name)) {
536 0 : keysize = mSECKeySizeChoiceList[i].size;
537 0 : break;
538 : }
539 : }
540 0 : if (!keysize) {
541 0 : goto loser;
542 : }
543 :
544 0 : arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
545 0 : if (!arena) {
546 0 : goto loser;
547 : }
548 :
549 : // Set the keygen mechanism
550 0 : if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) {
551 0 : keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
552 0 : } else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
553 : char * end;
554 0 : keyparamsString = ToNewCString(aKeyParams);
555 0 : if (!keyparamsString) {
556 0 : rv = NS_ERROR_OUT_OF_MEMORY;
557 0 : goto loser;
558 : }
559 :
560 0 : keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
561 0 : if (strcmp(keyparamsString, "null") == 0)
562 0 : goto loser;
563 0 : str = keyparamsString;
564 0 : bool found_match = false;
565 0 : do {
566 0 : end = strchr(str, ',');
567 0 : if (end != nsnull)
568 0 : *end = '\0';
569 0 : primeBits = pqg_prime_bits(str);
570 0 : if (keysize == primeBits) {
571 0 : found_match = true;
572 0 : break;
573 : }
574 0 : str = end + 1;
575 : } while (end != nsnull);
576 0 : if (!found_match) {
577 0 : goto loser;
578 : }
579 0 : } else if (aKeyType.LowerCaseEqualsLiteral("ec")) {
580 0 : keyparamsString = ToNewCString(aKeyParams);
581 0 : if (!keyparamsString) {
582 0 : rv = NS_ERROR_OUT_OF_MEMORY;
583 0 : goto loser;
584 : }
585 :
586 0 : keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
587 : /* ecParams are initialized later */
588 : } else {
589 0 : goto loser;
590 : }
591 :
592 : // Get the slot
593 0 : rv = GetSlot(keyGenMechanism, &slot);
594 0 : if (NS_FAILED(rv)) {
595 0 : goto loser;
596 : }
597 0 : switch (keyGenMechanism) {
598 : case CKM_RSA_PKCS_KEY_PAIR_GEN:
599 0 : rsaParams.keySizeInBits = keysize;
600 0 : rsaParams.pe = DEFAULT_RSA_KEYGEN_PE;
601 0 : algTag = DEFAULT_RSA_KEYGEN_ALG;
602 0 : params = &rsaParams;
603 0 : break;
604 : case CKM_DSA_KEY_PAIR_GEN:
605 : // XXX Fix this! XXX //
606 0 : goto loser;
607 : case CKM_EC_KEY_PAIR_GEN:
608 : /* XXX We ought to rethink how the KEYGEN tag is
609 : * displayed. The pulldown selections presented
610 : * to the user must depend on the keytype.
611 : * The displayed selection could be picked
612 : * from the keyparams attribute (this is currently called
613 : * the pqg attribute).
614 : * For now, we pick ecparams from the keyparams field
615 : * if it specifies a valid supported curve, or else
616 : * we pick one of secp384r1, secp256r1 or secp192r1
617 : * respectively depending on the user's selection
618 : * (High, Medium, Low).
619 : * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical
620 : * reasons, while ECC choices represent a stronger mapping)
621 : * NOTE: The user's selection
622 : * is silently ignored when a valid curve is presented
623 : * in keyparams.
624 : */
625 0 : if ((params = decode_ec_params(keyparamsString)) == nsnull) {
626 : /* The keyparams attribute did not specify a valid
627 : * curve name so use a curve based on the keysize.
628 : * NOTE: Here keysize is used only as an indication of
629 : * High/Medium/Low strength; elliptic curve
630 : * cryptography uses smaller keys than RSA to provide
631 : * equivalent security.
632 : */
633 0 : switch (keysize) {
634 : case 2048:
635 0 : params = decode_ec_params("secp384r1");
636 0 : break;
637 : case 1024:
638 : case 512:
639 0 : params = decode_ec_params("secp256r1");
640 0 : break;
641 : }
642 : }
643 : /* XXX The signature algorithm ought to choose the hashing
644 : * algorithm based on key size once ECDSA variations based
645 : * on SHA256 SHA384 and SHA512 are standardized.
646 : */
647 0 : algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
648 0 : break;
649 : default:
650 0 : goto loser;
651 : }
652 :
653 : /* Make sure token is initialized. */
654 0 : rv = setPassword(slot, m_ctx);
655 0 : if (NS_FAILED(rv))
656 0 : goto loser;
657 :
658 0 : sec_rv = PK11_Authenticate(slot, true, m_ctx);
659 0 : if (sec_rv != SECSuccess) {
660 0 : goto loser;
661 : }
662 :
663 : rv = getNSSDialogs((void**)&dialogs,
664 : NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
665 0 : NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
666 :
667 0 : if (NS_SUCCEEDED(rv)) {
668 0 : KeygenRunnable = new nsKeygenThread();
669 0 : NS_IF_ADDREF(KeygenRunnable);
670 : }
671 :
672 0 : if (NS_FAILED(rv) || !KeygenRunnable) {
673 0 : rv = NS_OK;
674 : privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism, params,
675 0 : &publicKey, true, true, m_ctx);
676 : } else {
677 0 : KeygenRunnable->SetParams( slot, keyGenMechanism, params, true, true, m_ctx );
678 :
679 0 : runnable = do_QueryInterface(KeygenRunnable);
680 :
681 0 : if (runnable) {
682 : {
683 0 : nsPSMUITracker tracker;
684 0 : if (tracker.isUIForbidden()) {
685 0 : rv = NS_ERROR_NOT_AVAILABLE;
686 : }
687 : else {
688 0 : rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable);
689 : // We call join on the thread,
690 : // so we can be sure that no simultaneous access to the passed parameters will happen.
691 0 : KeygenRunnable->Join();
692 : }
693 : }
694 :
695 0 : NS_RELEASE(dialogs);
696 0 : if (NS_SUCCEEDED(rv)) {
697 0 : rv = KeygenRunnable->GetParams(&privateKey, &publicKey);
698 : }
699 : }
700 : }
701 :
702 0 : if (NS_FAILED(rv) || !privateKey) {
703 : goto loser;
704 : }
705 : // just in case we'll need to authenticate to the db -jp //
706 0 : privateKey->wincx = m_ctx;
707 :
708 : /*
709 : * Create a subject public key info from the public key.
710 : */
711 0 : spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
712 0 : if ( !spkInfo ) {
713 0 : goto loser;
714 : }
715 :
716 : /*
717 : * Now DER encode the whole subjectPublicKeyInfo.
718 : */
719 0 : sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo);
720 0 : if (sec_rv != SECSuccess) {
721 0 : goto loser;
722 : }
723 :
724 : /*
725 : * set up the PublicKeyAndChallenge data structure, then DER encode it
726 : */
727 0 : pkac.spki = spkiItem;
728 0 : pkac.challenge.len = aChallenge.Length();
729 0 : pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge);
730 0 : if (!pkac.challenge.data) {
731 0 : rv = NS_ERROR_OUT_OF_MEMORY;
732 0 : goto loser;
733 : }
734 :
735 0 : sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
736 0 : if ( sec_rv != SECSuccess ) {
737 0 : goto loser;
738 : }
739 :
740 : /*
741 : * now sign the DER encoded PublicKeyAndChallenge
742 : */
743 : sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
744 0 : privateKey, algTag);
745 0 : if ( sec_rv != SECSuccess ) {
746 0 : goto loser;
747 : }
748 :
749 : /*
750 : * Convert the signed public key and challenge into base64/ascii.
751 : */
752 0 : keystring = BTOA_DataToAscii(signedItem.data, signedItem.len);
753 0 : if (!keystring) {
754 0 : rv = NS_ERROR_OUT_OF_MEMORY;
755 0 : goto loser;
756 : }
757 :
758 0 : CopyASCIItoUTF16(keystring, aOutPublicKey);
759 0 : nsCRT::free(keystring);
760 :
761 0 : rv = NS_OK;
762 : loser:
763 0 : if ( sec_rv != SECSuccess ) {
764 0 : if ( privateKey ) {
765 0 : PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
766 : }
767 0 : if ( publicKey ) {
768 0 : PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
769 : }
770 : }
771 0 : if ( spkInfo ) {
772 0 : SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
773 : }
774 0 : if ( publicKey ) {
775 0 : SECKEY_DestroyPublicKey(publicKey);
776 : }
777 0 : if ( privateKey ) {
778 0 : SECKEY_DestroyPrivateKey(privateKey);
779 : }
780 0 : if ( arena ) {
781 0 : PORT_FreeArena(arena, true);
782 : }
783 0 : if (slot != nsnull) {
784 0 : PK11_FreeSlot(slot);
785 : }
786 0 : if (KeygenRunnable) {
787 0 : NS_RELEASE(KeygenRunnable);
788 : }
789 0 : if (keyparamsString) {
790 0 : nsMemory::Free(keyparamsString);
791 : }
792 0 : if (pkac.challenge.data) {
793 0 : nsMemory::Free(pkac.challenge.data);
794 : }
795 0 : return rv;
796 : }
797 :
798 : NS_METHOD
799 0 : nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement,
800 : const nsAString& aName,
801 : nsAString& aValue)
802 : {
803 0 : nsAutoString challengeValue;
804 0 : nsAutoString keyTypeValue;
805 0 : nsAutoString keyParamsValue;
806 :
807 0 : aElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
808 0 : if (keyTypeValue.IsEmpty()) {
809 : // If this field is not present, we default to rsa.
810 0 : keyTypeValue.AssignLiteral("rsa");
811 : }
812 :
813 0 : aElement->GetAttribute(NS_LITERAL_STRING("pqg"),
814 0 : keyParamsValue);
815 : /* XXX We can still support the pqg attribute in the keygen
816 : * tag for backward compatibility while introducing a more
817 : * general attribute named keyparams.
818 : */
819 0 : if (keyParamsValue.IsEmpty()) {
820 0 : aElement->GetAttribute(NS_LITERAL_STRING("keyparams"),
821 0 : keyParamsValue);
822 : }
823 :
824 0 : aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
825 :
826 : return GetPublicKey(aValue, challengeValue, keyTypeValue,
827 0 : aValue, keyParamsValue);
828 : }
829 :
830 0 : NS_METHOD nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType,
831 : nsTArray<nsString>& aContent,
832 : nsAString& aAttribute)
833 : {
834 0 : if (Compare(aFormType, NS_LITERAL_STRING("SELECT"),
835 0 : nsCaseInsensitiveStringComparator()) == 0) {
836 :
837 0 : for (size_t i = 0; i < number_of_key_size_choices; ++i) {
838 0 : aContent.AppendElement(mSECKeySizeChoiceList[i].name);
839 : }
840 0 : aAttribute.AssignLiteral("-mozilla-keygen");
841 : }
842 0 : return NS_OK;
843 : }
844 :
|