security/manager/ssl/src/nsKeygenHandler.cpp

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

mercurial