LCOV - code coverage report
Current view: top level - security/manager/ssl - nsKeygenHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 288 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13