1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsKeygenHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,812 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "secdert.h" 1.11 +#include "nspr.h" 1.12 +#include "nsNSSComponent.h" // for PIPNSS string bundle calls. 1.13 +#include "keyhi.h" 1.14 +#include "secder.h" 1.15 +#include "cryptohi.h" 1.16 +#include "base64.h" 1.17 +#include "secasn1.h" 1.18 +#include "pk11pqg.h" 1.19 +#include "nsKeygenHandler.h" 1.20 +#include "nsIServiceManager.h" 1.21 +#include "nsIDOMHTMLSelectElement.h" 1.22 +#include "nsIContent.h" 1.23 +#include "nsKeygenThread.h" 1.24 +#include "nsReadableUtils.h" 1.25 +#include "nsUnicharUtils.h" 1.26 +#include "nsCRT.h" 1.27 +#include "nsITokenDialogs.h" 1.28 +#include "nsIGenKeypairInfoDlg.h" 1.29 +#include "nsNSSShutDown.h" 1.30 + 1.31 +//These defines are taken from the PKCS#11 spec 1.32 +#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 1.33 +#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 1.34 +#define CKM_DSA_KEY_PAIR_GEN 0x00000010 1.35 + 1.36 +DERTemplate SECAlgorithmIDTemplate[] = { 1.37 + { DER_SEQUENCE, 1.38 + 0, nullptr, sizeof(SECAlgorithmID) }, 1.39 + { DER_OBJECT_ID, 1.40 + offsetof(SECAlgorithmID,algorithm), }, 1.41 + { DER_OPTIONAL | DER_ANY, 1.42 + offsetof(SECAlgorithmID,parameters), }, 1.43 + { 0, } 1.44 +}; 1.45 + 1.46 +DERTemplate CERTSubjectPublicKeyInfoTemplate[] = { 1.47 + { DER_SEQUENCE, 1.48 + 0, nullptr, sizeof(CERTSubjectPublicKeyInfo) }, 1.49 + { DER_INLINE, 1.50 + offsetof(CERTSubjectPublicKeyInfo,algorithm), 1.51 + SECAlgorithmIDTemplate, }, 1.52 + { DER_BIT_STRING, 1.53 + offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), }, 1.54 + { 0, } 1.55 +}; 1.56 + 1.57 +DERTemplate CERTPublicKeyAndChallengeTemplate[] = 1.58 +{ 1.59 + { DER_SEQUENCE, 0, nullptr, sizeof(CERTPublicKeyAndChallenge) }, 1.60 + { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), }, 1.61 + { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), }, 1.62 + { 0, } 1.63 +}; 1.64 + 1.65 +const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = { 1.66 + { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PQGParams) }, 1.67 + { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) }, 1.68 + { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) }, 1.69 + { SEC_ASN1_INTEGER, offsetof(PQGParams,base) }, 1.70 + { 0, } 1.71 +}; 1.72 + 1.73 + 1.74 +static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); 1.75 + 1.76 +static PQGParams * 1.77 +decode_pqg_params(char *aStr) 1.78 +{ 1.79 + unsigned char *buf = nullptr; 1.80 + unsigned int len; 1.81 + PLArenaPool *arena = nullptr; 1.82 + PQGParams *params = nullptr; 1.83 + SECStatus status; 1.84 + 1.85 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.86 + if (!arena) 1.87 + return nullptr; 1.88 + 1.89 + params = static_cast<PQGParams*>(PORT_ArenaZAlloc(arena, sizeof(PQGParams))); 1.90 + if (!params) 1.91 + goto loser; 1.92 + params->arena = arena; 1.93 + 1.94 + buf = ATOB_AsciiToData(aStr, &len); 1.95 + if ((!buf) || (len == 0)) 1.96 + goto loser; 1.97 + 1.98 + status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len); 1.99 + if (status != SECSuccess) 1.100 + goto loser; 1.101 + 1.102 + return params; 1.103 + 1.104 +loser: 1.105 + if (arena) { 1.106 + PORT_FreeArena(arena, false); 1.107 + } 1.108 + if (buf) { 1.109 + PR_Free(buf); 1.110 + } 1.111 + return nullptr; 1.112 +} 1.113 + 1.114 +static int 1.115 +pqg_prime_bits(char *str) 1.116 +{ 1.117 + PQGParams *params = nullptr; 1.118 + int primeBits = 0, i; 1.119 + 1.120 + params = decode_pqg_params(str); 1.121 + if (!params) 1.122 + goto done; /* lose */ 1.123 + 1.124 + for (i = 0; params->prime.data[i] == 0; i++) 1.125 + /* empty */; 1.126 + primeBits = (params->prime.len - i) * 8; 1.127 + 1.128 +done: 1.129 + if (params) 1.130 + PK11_PQG_DestroyParams(params); 1.131 + return primeBits; 1.132 +} 1.133 + 1.134 +typedef struct curveNameTagPairStr { 1.135 + const char *curveName; 1.136 + SECOidTag curveOidTag; 1.137 +} CurveNameTagPair; 1.138 + 1.139 +static CurveNameTagPair nameTagPair[] = 1.140 +{ 1.141 + { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 }, 1.142 + { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 }, 1.143 + { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 }, 1.144 + { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 }, 1.145 + { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 }, 1.146 + { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 }, 1.147 + { "prime256v1", SEC_OID_ANSIX962_EC_PRIME256V1 }, 1.148 + 1.149 + { "secp112r1", SEC_OID_SECG_EC_SECP112R1}, 1.150 + { "secp112r2", SEC_OID_SECG_EC_SECP112R2}, 1.151 + { "secp128r1", SEC_OID_SECG_EC_SECP128R1}, 1.152 + { "secp128r2", SEC_OID_SECG_EC_SECP128R2}, 1.153 + { "secp160k1", SEC_OID_SECG_EC_SECP160K1}, 1.154 + { "secp160r1", SEC_OID_SECG_EC_SECP160R1}, 1.155 + { "secp160r2", SEC_OID_SECG_EC_SECP160R2}, 1.156 + { "secp192k1", SEC_OID_SECG_EC_SECP192K1}, 1.157 + { "secp192r1", SEC_OID_ANSIX962_EC_PRIME192V1 }, 1.158 + { "nistp192", SEC_OID_ANSIX962_EC_PRIME192V1 }, 1.159 + { "secp224k1", SEC_OID_SECG_EC_SECP224K1}, 1.160 + { "secp224r1", SEC_OID_SECG_EC_SECP224R1}, 1.161 + { "nistp224", SEC_OID_SECG_EC_SECP224R1}, 1.162 + { "secp256k1", SEC_OID_SECG_EC_SECP256K1}, 1.163 + { "secp256r1", SEC_OID_ANSIX962_EC_PRIME256V1 }, 1.164 + { "nistp256", SEC_OID_ANSIX962_EC_PRIME256V1 }, 1.165 + { "secp384r1", SEC_OID_SECG_EC_SECP384R1}, 1.166 + { "nistp384", SEC_OID_SECG_EC_SECP384R1}, 1.167 + { "secp521r1", SEC_OID_SECG_EC_SECP521R1}, 1.168 + { "nistp521", SEC_OID_SECG_EC_SECP521R1}, 1.169 + 1.170 + { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 }, 1.171 + { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 }, 1.172 + { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 }, 1.173 + { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 }, 1.174 + { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 }, 1.175 + { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 }, 1.176 + { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 }, 1.177 + { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 }, 1.178 + { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 }, 1.179 + { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 }, 1.180 + { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 }, 1.181 + { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 }, 1.182 + { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 }, 1.183 + { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 }, 1.184 + { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 }, 1.185 + { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 }, 1.186 + { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 }, 1.187 + { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 }, 1.188 + { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 }, 1.189 + { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 }, 1.190 + 1.191 + { "sect113r1", SEC_OID_SECG_EC_SECT113R1}, 1.192 + { "sect113r2", SEC_OID_SECG_EC_SECT113R2}, 1.193 + { "sect131r1", SEC_OID_SECG_EC_SECT131R1}, 1.194 + { "sect131r2", SEC_OID_SECG_EC_SECT131R2}, 1.195 + { "sect163k1", SEC_OID_SECG_EC_SECT163K1}, 1.196 + { "nistk163", SEC_OID_SECG_EC_SECT163K1}, 1.197 + { "sect163r1", SEC_OID_SECG_EC_SECT163R1}, 1.198 + { "sect163r2", SEC_OID_SECG_EC_SECT163R2}, 1.199 + { "nistb163", SEC_OID_SECG_EC_SECT163R2}, 1.200 + { "sect193r1", SEC_OID_SECG_EC_SECT193R1}, 1.201 + { "sect193r2", SEC_OID_SECG_EC_SECT193R2}, 1.202 + { "sect233k1", SEC_OID_SECG_EC_SECT233K1}, 1.203 + { "nistk233", SEC_OID_SECG_EC_SECT233K1}, 1.204 + { "sect233r1", SEC_OID_SECG_EC_SECT233R1}, 1.205 + { "nistb233", SEC_OID_SECG_EC_SECT233R1}, 1.206 + { "sect239k1", SEC_OID_SECG_EC_SECT239K1}, 1.207 + { "sect283k1", SEC_OID_SECG_EC_SECT283K1}, 1.208 + { "nistk283", SEC_OID_SECG_EC_SECT283K1}, 1.209 + { "sect283r1", SEC_OID_SECG_EC_SECT283R1}, 1.210 + { "nistb283", SEC_OID_SECG_EC_SECT283R1}, 1.211 + { "sect409k1", SEC_OID_SECG_EC_SECT409K1}, 1.212 + { "nistk409", SEC_OID_SECG_EC_SECT409K1}, 1.213 + { "sect409r1", SEC_OID_SECG_EC_SECT409R1}, 1.214 + { "nistb409", SEC_OID_SECG_EC_SECT409R1}, 1.215 + { "sect571k1", SEC_OID_SECG_EC_SECT571K1}, 1.216 + { "nistk571", SEC_OID_SECG_EC_SECT571K1}, 1.217 + { "sect571r1", SEC_OID_SECG_EC_SECT571R1}, 1.218 + { "nistb571", SEC_OID_SECG_EC_SECT571R1}, 1.219 + 1.220 +}; 1.221 + 1.222 +SECKEYECParams * 1.223 +decode_ec_params(const char *curve) 1.224 +{ 1.225 + SECKEYECParams *ecparams; 1.226 + SECOidData *oidData = nullptr; 1.227 + SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */ 1.228 + int i, numCurves; 1.229 + 1.230 + if (curve && *curve) { 1.231 + numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair); 1.232 + for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); 1.233 + i++) { 1.234 + if (PL_strcmp(curve, nameTagPair[i].curveName) == 0) 1.235 + curveOidTag = nameTagPair[i].curveOidTag; 1.236 + } 1.237 + } 1.238 + 1.239 + /* Return nullptr if curve name is not recognized */ 1.240 + if ((curveOidTag == SEC_OID_UNKNOWN) || 1.241 + (oidData = SECOID_FindOIDByTag(curveOidTag)) == nullptr) { 1.242 + return nullptr; 1.243 + } 1.244 + 1.245 + ecparams = SECITEM_AllocItem(nullptr, nullptr, (2 + oidData->oid.len)); 1.246 + 1.247 + if (!ecparams) 1.248 + return nullptr; 1.249 + 1.250 + /* 1.251 + * ecparams->data needs to contain the ASN encoding of an object ID (OID) 1.252 + * representing the named curve. The actual OID is in 1.253 + * oidData->oid.data so we simply prepend 0x06 and OID length 1.254 + */ 1.255 + ecparams->data[0] = SEC_ASN1_OBJECT_ID; 1.256 + ecparams->data[1] = oidData->oid.len; 1.257 + memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len); 1.258 + 1.259 + return ecparams; 1.260 +} 1.261 + 1.262 +NS_IMPL_ISUPPORTS(nsKeygenFormProcessor, nsIFormProcessor) 1.263 + 1.264 +nsKeygenFormProcessor::nsKeygenFormProcessor() 1.265 +{ 1.266 + m_ctx = new PipUIContext(); 1.267 + 1.268 +} 1.269 + 1.270 +nsKeygenFormProcessor::~nsKeygenFormProcessor() 1.271 +{ 1.272 +} 1.273 + 1.274 +nsresult 1.275 +nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) 1.276 +{ 1.277 + nsresult rv; 1.278 + NS_ENSURE_NO_AGGREGATION(aOuter); 1.279 + nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor(); 1.280 + 1.281 + nsCOMPtr<nsISupports> stabilize = formProc; 1.282 + rv = formProc->Init(); 1.283 + if (NS_SUCCEEDED(rv)) { 1.284 + rv = formProc->QueryInterface(aIID, aResult); 1.285 + } 1.286 + return rv; 1.287 +} 1.288 + 1.289 +nsresult 1.290 +nsKeygenFormProcessor::Init() 1.291 +{ 1.292 + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.293 + 1.294 + nsresult rv; 1.295 + 1.296 + nsCOMPtr<nsINSSComponent> nssComponent; 1.297 + nssComponent = do_GetService(kNSSComponentCID, &rv); 1.298 + if (NS_FAILED(rv)) 1.299 + return rv; 1.300 + 1.301 + // Init possible key size choices. 1.302 + nssComponent->GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name); 1.303 + mSECKeySizeChoiceList[0].size = 2048; 1.304 + 1.305 + nssComponent->GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name); 1.306 + mSECKeySizeChoiceList[1].size = 1024; 1.307 + 1.308 + return NS_OK; 1.309 +} 1.310 + 1.311 +nsresult 1.312 +nsKeygenFormProcessor::GetSlot(uint32_t aMechanism, PK11SlotInfo** aSlot) 1.313 +{ 1.314 + return GetSlotWithMechanism(aMechanism,m_ctx,aSlot); 1.315 +} 1.316 + 1.317 + 1.318 +uint32_t MapGenMechToAlgoMech(uint32_t mechanism) 1.319 +{ 1.320 + uint32_t searchMech; 1.321 + 1.322 + /* We are interested in slots based on the ability to perform 1.323 + a given algorithm, not on their ability to generate keys usable 1.324 + by that algorithm. Therefore, map keygen-specific mechanism tags 1.325 + to tags for the corresponding crypto algorthm. */ 1.326 + switch(mechanism) 1.327 + { 1.328 + case CKM_RSA_PKCS_KEY_PAIR_GEN: 1.329 + searchMech = CKM_RSA_PKCS; 1.330 + break; 1.331 + case CKM_DSA_KEY_PAIR_GEN: 1.332 + searchMech = CKM_DSA; 1.333 + break; 1.334 + case CKM_RC4_KEY_GEN: 1.335 + searchMech = CKM_RC4; 1.336 + break; 1.337 + case CKM_DH_PKCS_KEY_PAIR_GEN: 1.338 + searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch is this right? */ 1.339 + break; 1.340 + case CKM_DES_KEY_GEN: 1.341 + /* What do we do about DES keygen? Right now, we're just using 1.342 + DES_KEY_GEN to look for tokens, because otherwise we'll have 1.343 + to search the token list three times. */ 1.344 + case CKM_EC_KEY_PAIR_GEN: 1.345 + /* The default should also work for EC key pair generation. */ 1.346 + default: 1.347 + searchMech = mechanism; 1.348 + break; 1.349 + } 1.350 + return searchMech; 1.351 +} 1.352 + 1.353 + 1.354 +nsresult 1.355 +GetSlotWithMechanism(uint32_t aMechanism, 1.356 + nsIInterfaceRequestor *m_ctx, 1.357 + PK11SlotInfo** aSlot) 1.358 +{ 1.359 + nsNSSShutDownPreventionLock locker; 1.360 + PK11SlotList * slotList = nullptr; 1.361 + char16_t** tokenNameList = nullptr; 1.362 + nsITokenDialogs * dialogs; 1.363 + char16_t *unicodeTokenChosen; 1.364 + PK11SlotListElement *slotElement, *tmpSlot; 1.365 + uint32_t numSlots = 0, i = 0; 1.366 + bool canceled; 1.367 + nsresult rv = NS_OK; 1.368 + 1.369 + *aSlot = nullptr; 1.370 + 1.371 + // Get the slot 1.372 + slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism), 1.373 + true, true, m_ctx); 1.374 + if (!slotList || !slotList->head) { 1.375 + rv = NS_ERROR_FAILURE; 1.376 + goto loser; 1.377 + } 1.378 + 1.379 + if (!slotList->head->next) { 1.380 + /* only one slot available, just return it */ 1.381 + *aSlot = slotList->head->slot; 1.382 + } else { 1.383 + // Gerenate a list of slots and ask the user to choose // 1.384 + tmpSlot = slotList->head; 1.385 + while (tmpSlot) { 1.386 + numSlots++; 1.387 + tmpSlot = tmpSlot->next; 1.388 + } 1.389 + 1.390 + // Allocate the slot name buffer // 1.391 + tokenNameList = static_cast<char16_t**>(nsMemory::Alloc(sizeof(char16_t *) * numSlots)); 1.392 + if (!tokenNameList) { 1.393 + rv = NS_ERROR_OUT_OF_MEMORY; 1.394 + goto loser; 1.395 + } 1.396 + 1.397 + i = 0; 1.398 + slotElement = PK11_GetFirstSafe(slotList); 1.399 + while (slotElement) { 1.400 + tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot))); 1.401 + slotElement = PK11_GetNextSafe(slotList, slotElement, false); 1.402 + if (tokenNameList[i]) 1.403 + i++; 1.404 + else { 1.405 + // OOM. adjust numSlots so we don't free unallocated memory. 1.406 + numSlots = i; 1.407 + PK11_FreeSlotListElement(slotList, slotElement); 1.408 + rv = NS_ERROR_OUT_OF_MEMORY; 1.409 + goto loser; 1.410 + } 1.411 + } 1.412 + 1.413 + /* Throw up the token list dialog and get back the token */ 1.414 + rv = getNSSDialogs((void**)&dialogs, 1.415 + NS_GET_IID(nsITokenDialogs), 1.416 + NS_TOKENDIALOGS_CONTRACTID); 1.417 + 1.418 + if (NS_FAILED(rv)) goto loser; 1.419 + 1.420 + { 1.421 + nsPSMUITracker tracker; 1.422 + if (!tokenNameList || !*tokenNameList) { 1.423 + rv = NS_ERROR_OUT_OF_MEMORY; 1.424 + } 1.425 + else if (tracker.isUIForbidden()) { 1.426 + rv = NS_ERROR_NOT_AVAILABLE; 1.427 + } 1.428 + else { 1.429 + rv = dialogs->ChooseToken(m_ctx, (const char16_t**)tokenNameList, numSlots, &unicodeTokenChosen, &canceled); 1.430 + } 1.431 + } 1.432 + NS_RELEASE(dialogs); 1.433 + if (NS_FAILED(rv)) goto loser; 1.434 + 1.435 + if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; } 1.436 + 1.437 + // Get the slot // 1.438 + slotElement = PK11_GetFirstSafe(slotList); 1.439 + nsAutoString tokenStr(unicodeTokenChosen); 1.440 + while (slotElement) { 1.441 + if (tokenStr.Equals(NS_ConvertUTF8toUTF16(PK11_GetTokenName(slotElement->slot)))) { 1.442 + *aSlot = slotElement->slot; 1.443 + PK11_FreeSlotListElement(slotList, slotElement); 1.444 + break; 1.445 + } 1.446 + slotElement = PK11_GetNextSafe(slotList, slotElement, false); 1.447 + } 1.448 + if(!(*aSlot)) { 1.449 + rv = NS_ERROR_FAILURE; 1.450 + goto loser; 1.451 + } 1.452 + } 1.453 + 1.454 + // Get a reference to the slot // 1.455 + PK11_ReferenceSlot(*aSlot); 1.456 +loser: 1.457 + if (slotList) { 1.458 + PK11_FreeSlotList(slotList); 1.459 + } 1.460 + if (tokenNameList) { 1.461 + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList); 1.462 + } 1.463 + return rv; 1.464 +} 1.465 + 1.466 +nsresult 1.467 +nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge, 1.468 + nsAFlatString& aKeyType, 1.469 + nsAString& aOutPublicKey, nsAString& aKeyParams) 1.470 +{ 1.471 + nsNSSShutDownPreventionLock locker; 1.472 + nsresult rv = NS_ERROR_FAILURE; 1.473 + char *keystring = nullptr; 1.474 + char *keyparamsString = nullptr, *str = nullptr; 1.475 + uint32_t keyGenMechanism; 1.476 + int32_t primeBits; 1.477 + PK11SlotInfo *slot = nullptr; 1.478 + PK11RSAGenParams rsaParams; 1.479 + SECOidTag algTag; 1.480 + int keysize = 0; 1.481 + void *params; 1.482 + SECKEYPrivateKey *privateKey = nullptr; 1.483 + SECKEYPublicKey *publicKey = nullptr; 1.484 + CERTSubjectPublicKeyInfo *spkInfo = nullptr; 1.485 + PLArenaPool *arena = nullptr; 1.486 + SECStatus sec_rv = SECFailure; 1.487 + SECItem spkiItem; 1.488 + SECItem pkacItem; 1.489 + SECItem signedItem; 1.490 + CERTPublicKeyAndChallenge pkac; 1.491 + pkac.challenge.data = nullptr; 1.492 + nsIGeneratingKeypairInfoDialogs * dialogs; 1.493 + nsKeygenThread *KeygenRunnable = 0; 1.494 + nsCOMPtr<nsIKeygenThread> runnable; 1.495 + 1.496 + // permanent and sensitive flags for keygen 1.497 + PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE; 1.498 + 1.499 + // Get the key size // 1.500 + for (size_t i = 0; i < number_of_key_size_choices; ++i) { 1.501 + if (aValue.Equals(mSECKeySizeChoiceList[i].name)) { 1.502 + keysize = mSECKeySizeChoiceList[i].size; 1.503 + break; 1.504 + } 1.505 + } 1.506 + if (!keysize) { 1.507 + goto loser; 1.508 + } 1.509 + 1.510 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.511 + if (!arena) { 1.512 + goto loser; 1.513 + } 1.514 + 1.515 + // Set the keygen mechanism 1.516 + if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) { 1.517 + keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; 1.518 + } else if (aKeyType.LowerCaseEqualsLiteral("dsa")) { 1.519 + char * end; 1.520 + keyparamsString = ToNewCString(aKeyParams); 1.521 + if (!keyparamsString) { 1.522 + rv = NS_ERROR_OUT_OF_MEMORY; 1.523 + goto loser; 1.524 + } 1.525 + 1.526 + keyGenMechanism = CKM_DSA_KEY_PAIR_GEN; 1.527 + if (strcmp(keyparamsString, "null") == 0) 1.528 + goto loser; 1.529 + str = keyparamsString; 1.530 + bool found_match = false; 1.531 + do { 1.532 + end = strchr(str, ','); 1.533 + if (end) 1.534 + *end = '\0'; 1.535 + primeBits = pqg_prime_bits(str); 1.536 + if (keysize == primeBits) { 1.537 + found_match = true; 1.538 + break; 1.539 + } 1.540 + str = end + 1; 1.541 + } while (end); 1.542 + if (!found_match) { 1.543 + goto loser; 1.544 + } 1.545 + } else if (aKeyType.LowerCaseEqualsLiteral("ec")) { 1.546 + keyparamsString = ToNewCString(aKeyParams); 1.547 + if (!keyparamsString) { 1.548 + rv = NS_ERROR_OUT_OF_MEMORY; 1.549 + goto loser; 1.550 + } 1.551 + 1.552 + keyGenMechanism = CKM_EC_KEY_PAIR_GEN; 1.553 + /* ecParams are initialized later */ 1.554 + } else { 1.555 + goto loser; 1.556 + } 1.557 + 1.558 + // Get the slot 1.559 + rv = GetSlot(keyGenMechanism, &slot); 1.560 + if (NS_FAILED(rv)) { 1.561 + goto loser; 1.562 + } 1.563 + switch (keyGenMechanism) { 1.564 + case CKM_RSA_PKCS_KEY_PAIR_GEN: 1.565 + rsaParams.keySizeInBits = keysize; 1.566 + rsaParams.pe = DEFAULT_RSA_KEYGEN_PE; 1.567 + algTag = DEFAULT_RSA_KEYGEN_ALG; 1.568 + params = &rsaParams; 1.569 + break; 1.570 + case CKM_DSA_KEY_PAIR_GEN: 1.571 + // XXX Fix this! XXX // 1.572 + goto loser; 1.573 + case CKM_EC_KEY_PAIR_GEN: 1.574 + /* XXX We ought to rethink how the KEYGEN tag is 1.575 + * displayed. The pulldown selections presented 1.576 + * to the user must depend on the keytype. 1.577 + * The displayed selection could be picked 1.578 + * from the keyparams attribute (this is currently called 1.579 + * the pqg attribute). 1.580 + * For now, we pick ecparams from the keyparams field 1.581 + * if it specifies a valid supported curve, or else 1.582 + * we pick one of secp384r1, secp256r1 or secp192r1 1.583 + * respectively depending on the user's selection 1.584 + * (High, Medium, Low). 1.585 + * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical 1.586 + * reasons, while ECC choices represent a stronger mapping) 1.587 + * NOTE: The user's selection 1.588 + * is silently ignored when a valid curve is presented 1.589 + * in keyparams. 1.590 + */ 1.591 + if ((params = decode_ec_params(keyparamsString)) == nullptr) { 1.592 + /* The keyparams attribute did not specify a valid 1.593 + * curve name so use a curve based on the keysize. 1.594 + * NOTE: Here keysize is used only as an indication of 1.595 + * High/Medium/Low strength; elliptic curve 1.596 + * cryptography uses smaller keys than RSA to provide 1.597 + * equivalent security. 1.598 + */ 1.599 + switch (keysize) { 1.600 + case 2048: 1.601 + params = decode_ec_params("secp384r1"); 1.602 + break; 1.603 + case 1024: 1.604 + case 512: 1.605 + params = decode_ec_params("secp256r1"); 1.606 + break; 1.607 + } 1.608 + } 1.609 + /* XXX The signature algorithm ought to choose the hashing 1.610 + * algorithm based on key size once ECDSA variations based 1.611 + * on SHA256 SHA384 and SHA512 are standardized. 1.612 + */ 1.613 + algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; 1.614 + break; 1.615 + default: 1.616 + goto loser; 1.617 + } 1.618 + 1.619 + /* Make sure token is initialized. */ 1.620 + rv = setPassword(slot, m_ctx); 1.621 + if (NS_FAILED(rv)) 1.622 + goto loser; 1.623 + 1.624 + sec_rv = PK11_Authenticate(slot, true, m_ctx); 1.625 + if (sec_rv != SECSuccess) { 1.626 + goto loser; 1.627 + } 1.628 + 1.629 + rv = getNSSDialogs((void**)&dialogs, 1.630 + NS_GET_IID(nsIGeneratingKeypairInfoDialogs), 1.631 + NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID); 1.632 + 1.633 + if (NS_SUCCEEDED(rv)) { 1.634 + KeygenRunnable = new nsKeygenThread(); 1.635 + NS_IF_ADDREF(KeygenRunnable); 1.636 + } 1.637 + 1.638 + if (NS_FAILED(rv) || !KeygenRunnable) { 1.639 + rv = NS_OK; 1.640 + privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism, params, 1.641 + &publicKey, attrFlags, m_ctx); 1.642 + } else { 1.643 + KeygenRunnable->SetParams( slot, attrFlags, nullptr, 0, 1.644 + keyGenMechanism, params, m_ctx ); 1.645 + 1.646 + runnable = do_QueryInterface(KeygenRunnable); 1.647 + 1.648 + if (runnable) { 1.649 + { 1.650 + nsPSMUITracker tracker; 1.651 + if (tracker.isUIForbidden()) { 1.652 + rv = NS_ERROR_NOT_AVAILABLE; 1.653 + } 1.654 + else { 1.655 + rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable); 1.656 + // We call join on the thread, 1.657 + // so we can be sure that no simultaneous access to the passed parameters will happen. 1.658 + KeygenRunnable->Join(); 1.659 + } 1.660 + } 1.661 + 1.662 + NS_RELEASE(dialogs); 1.663 + if (NS_SUCCEEDED(rv)) { 1.664 + PK11SlotInfo *used_slot = nullptr; 1.665 + rv = KeygenRunnable->ConsumeResult(&used_slot, &privateKey, &publicKey); 1.666 + if (NS_SUCCEEDED(rv) && used_slot) { 1.667 + PK11_FreeSlot(used_slot); 1.668 + } 1.669 + } 1.670 + } 1.671 + } 1.672 + 1.673 + if (NS_FAILED(rv) || !privateKey) { 1.674 + goto loser; 1.675 + } 1.676 + // just in case we'll need to authenticate to the db -jp // 1.677 + privateKey->wincx = m_ctx; 1.678 + 1.679 + /* 1.680 + * Create a subject public key info from the public key. 1.681 + */ 1.682 + spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey); 1.683 + if ( !spkInfo ) { 1.684 + goto loser; 1.685 + } 1.686 + 1.687 + /* 1.688 + * Now DER encode the whole subjectPublicKeyInfo. 1.689 + */ 1.690 + sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo); 1.691 + if (sec_rv != SECSuccess) { 1.692 + goto loser; 1.693 + } 1.694 + 1.695 + /* 1.696 + * set up the PublicKeyAndChallenge data structure, then DER encode it 1.697 + */ 1.698 + pkac.spki = spkiItem; 1.699 + pkac.challenge.len = aChallenge.Length(); 1.700 + pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge); 1.701 + if (!pkac.challenge.data) { 1.702 + rv = NS_ERROR_OUT_OF_MEMORY; 1.703 + goto loser; 1.704 + } 1.705 + 1.706 + sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac); 1.707 + if ( sec_rv != SECSuccess ) { 1.708 + goto loser; 1.709 + } 1.710 + 1.711 + /* 1.712 + * now sign the DER encoded PublicKeyAndChallenge 1.713 + */ 1.714 + sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len, 1.715 + privateKey, algTag); 1.716 + if ( sec_rv != SECSuccess ) { 1.717 + goto loser; 1.718 + } 1.719 + 1.720 + /* 1.721 + * Convert the signed public key and challenge into base64/ascii. 1.722 + */ 1.723 + keystring = BTOA_DataToAscii(signedItem.data, signedItem.len); 1.724 + if (!keystring) { 1.725 + rv = NS_ERROR_OUT_OF_MEMORY; 1.726 + goto loser; 1.727 + } 1.728 + 1.729 + CopyASCIItoUTF16(keystring, aOutPublicKey); 1.730 + free(keystring); 1.731 + 1.732 + rv = NS_OK; 1.733 +loser: 1.734 + if ( sec_rv != SECSuccess ) { 1.735 + if ( privateKey ) { 1.736 + PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID); 1.737 + } 1.738 + if ( publicKey ) { 1.739 + PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID); 1.740 + } 1.741 + } 1.742 + if ( spkInfo ) { 1.743 + SECKEY_DestroySubjectPublicKeyInfo(spkInfo); 1.744 + } 1.745 + if ( publicKey ) { 1.746 + SECKEY_DestroyPublicKey(publicKey); 1.747 + } 1.748 + if ( privateKey ) { 1.749 + SECKEY_DestroyPrivateKey(privateKey); 1.750 + } 1.751 + if ( arena ) { 1.752 + PORT_FreeArena(arena, true); 1.753 + } 1.754 + if (slot) { 1.755 + PK11_FreeSlot(slot); 1.756 + } 1.757 + if (KeygenRunnable) { 1.758 + NS_RELEASE(KeygenRunnable); 1.759 + } 1.760 + if (keyparamsString) { 1.761 + nsMemory::Free(keyparamsString); 1.762 + } 1.763 + if (pkac.challenge.data) { 1.764 + nsMemory::Free(pkac.challenge.data); 1.765 + } 1.766 + return rv; 1.767 +} 1.768 + 1.769 +NS_METHOD 1.770 +nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement, 1.771 + const nsAString& aName, 1.772 + nsAString& aValue) 1.773 +{ 1.774 + nsAutoString challengeValue; 1.775 + nsAutoString keyTypeValue; 1.776 + nsAutoString keyParamsValue; 1.777 + 1.778 + aElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue); 1.779 + if (keyTypeValue.IsEmpty()) { 1.780 + // If this field is not present, we default to rsa. 1.781 + keyTypeValue.AssignLiteral("rsa"); 1.782 + } 1.783 + 1.784 + aElement->GetAttribute(NS_LITERAL_STRING("pqg"), 1.785 + keyParamsValue); 1.786 + /* XXX We can still support the pqg attribute in the keygen 1.787 + * tag for backward compatibility while introducing a more 1.788 + * general attribute named keyparams. 1.789 + */ 1.790 + if (keyParamsValue.IsEmpty()) { 1.791 + aElement->GetAttribute(NS_LITERAL_STRING("keyparams"), 1.792 + keyParamsValue); 1.793 + } 1.794 + 1.795 + aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue); 1.796 + 1.797 + return GetPublicKey(aValue, challengeValue, keyTypeValue, 1.798 + aValue, keyParamsValue); 1.799 +} 1.800 + 1.801 +NS_METHOD nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType, 1.802 + nsTArray<nsString>& aContent, 1.803 + nsAString& aAttribute) 1.804 +{ 1.805 + if (Compare(aFormType, NS_LITERAL_STRING("SELECT"), 1.806 + nsCaseInsensitiveStringComparator()) == 0) { 1.807 + 1.808 + for (size_t i = 0; i < number_of_key_size_choices; ++i) { 1.809 + aContent.AppendElement(mSECKeySizeChoiceList[i].name); 1.810 + } 1.811 + aAttribute.AssignLiteral("-mozilla-keygen"); 1.812 + } 1.813 + return NS_OK; 1.814 +} 1.815 +