security/manager/ssl/src/nsKeygenHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     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"
    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
    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 };
    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 };
    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 };
    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 };
    71 static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
    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;
    82     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    83     if (!arena)
    84         return nullptr;
    86     params = static_cast<PQGParams*>(PORT_ArenaZAlloc(arena, sizeof(PQGParams)));
    87     if (!params)
    88         goto loser;
    89     params->arena = arena;
    91     buf = ATOB_AsciiToData(aStr, &len);
    92     if ((!buf) || (len == 0))
    93         goto loser;
    95     status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len);
    96     if (status != SECSuccess)
    97         goto loser;
    99     return params;
   101 loser:
   102     if (arena) {
   103       PORT_FreeArena(arena, false);
   104     }
   105     if (buf) {
   106       PR_Free(buf);
   107     }
   108     return nullptr;
   109 }
   111 static int
   112 pqg_prime_bits(char *str)
   113 {
   114     PQGParams *params = nullptr;
   115     int primeBits = 0, i;
   117     params = decode_pqg_params(str);
   118     if (!params)
   119         goto done; /* lose */
   121     for (i = 0; params->prime.data[i] == 0; i++)
   122         /* empty */;
   123     primeBits = (params->prime.len - i) * 8;
   125 done:
   126     if (params)
   127         PK11_PQG_DestroyParams(params);
   128     return primeBits;
   129 }
   131 typedef struct curveNameTagPairStr {
   132     const char *curveName;
   133     SECOidTag curveOidTag;
   134 } CurveNameTagPair;
   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 },
   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},
   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 },
   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},
   217 };
   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;
   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     }
   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     }
   242     ecparams = SECITEM_AllocItem(nullptr, nullptr, (2 + oidData->oid.len));
   244     if (!ecparams)
   245       return nullptr;
   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);
   256     return ecparams;
   257 }
   259 NS_IMPL_ISUPPORTS(nsKeygenFormProcessor, nsIFormProcessor)
   261 nsKeygenFormProcessor::nsKeygenFormProcessor()
   262 { 
   263    m_ctx = new PipUIContext();
   265 } 
   267 nsKeygenFormProcessor::~nsKeygenFormProcessor()
   268 {
   269 }
   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();
   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 }
   286 nsresult
   287 nsKeygenFormProcessor::Init()
   288 {
   289   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   291   nsresult rv;
   293   nsCOMPtr<nsINSSComponent> nssComponent;
   294   nssComponent = do_GetService(kNSSComponentCID, &rv);
   295   if (NS_FAILED(rv))
   296     return rv;
   298   // Init possible key size choices.
   299   nssComponent->GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name);
   300   mSECKeySizeChoiceList[0].size = 2048;
   302   nssComponent->GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name);
   303   mSECKeySizeChoiceList[1].size = 1024;
   305   return NS_OK;
   306 }
   308 nsresult
   309 nsKeygenFormProcessor::GetSlot(uint32_t aMechanism, PK11SlotInfo** aSlot)
   310 {
   311   return GetSlotWithMechanism(aMechanism,m_ctx,aSlot);
   312 }
   315 uint32_t MapGenMechToAlgoMech(uint32_t mechanism)
   316 {
   317     uint32_t searchMech;
   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 }
   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;
   366     *aSlot = nullptr;
   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     }
   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         }
   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         }
   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         }
   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);
   415 		if (NS_FAILED(rv)) goto loser;
   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;
   432 		if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
   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       }
   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 }
   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;
   493     // permanent and sensitive flags for keygen
   494     PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
   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     }
   507     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   508     if (!arena) {
   509         goto loser;
   510     }
   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         }
   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         }
   549         keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
   550         /* ecParams are initialized later */
   551     } else {
   552         goto loser;
   553     }
   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       }
   616     /* Make sure token is initialized. */
   617     rv = setPassword(slot, m_ctx);
   618     if (NS_FAILED(rv))
   619         goto loser;
   621     sec_rv = PK11_Authenticate(slot, true, m_ctx);
   622     if (sec_rv != SECSuccess) {
   623         goto loser;
   624     }
   626     rv = getNSSDialogs((void**)&dialogs,
   627                        NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
   628                        NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
   630     if (NS_SUCCEEDED(rv)) {
   631         KeygenRunnable = new nsKeygenThread();
   632         NS_IF_ADDREF(KeygenRunnable);
   633     }
   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 );
   643         runnable = do_QueryInterface(KeygenRunnable);
   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             }
   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     }
   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;
   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     }
   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     }
   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     }
   703     sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
   704     if ( sec_rv != SECSuccess ) {
   705         goto loser;
   706     }
   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     }
   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     }
   726     CopyASCIItoUTF16(keystring, aOutPublicKey);
   727     free(keystring);
   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 }
   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;
   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     }
   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     }
   792     aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
   794     return GetPublicKey(aValue, challengeValue, keyTypeValue, 
   795                         aValue, keyParamsValue);
   796 } 
   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) {
   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 } 

mercurial