security/manager/ssl/src/nsCrypto.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsCrypto.h"
     7 #include "nsNSSComponent.h"
     8 #include "secmod.h"
    10 #include "nsReadableUtils.h"
    11 #include "nsCRT.h"
    12 #include "nsXPIDLString.h"
    13 #include "nsISaveAsCharset.h"
    14 #include "nsNativeCharsetUtils.h"
    15 #include "nsServiceManagerUtils.h"
    17 #ifndef MOZ_DISABLE_CRYPTOLEGACY
    18 #include "nsKeygenHandler.h"
    19 #include "nsKeygenThread.h"
    20 #include "nsNSSCertificate.h"
    21 #include "nsNSSCertificateDB.h"
    22 #include "nsPKCS12Blob.h"
    23 #include "nsPK11TokenDB.h"
    24 #include "nsThreadUtils.h"
    25 #include "nsIServiceManager.h"
    26 #include "nsIMemory.h"
    27 #include "nsAlgorithm.h"
    28 #include "prprf.h"
    29 #include "nsDOMCID.h"
    30 #include "nsIDOMWindow.h"
    31 #include "nsIDOMClassInfo.h"
    32 #include "nsIDOMDocument.h"
    33 #include "nsIDocument.h"
    34 #include "nsIScriptObjectPrincipal.h"
    35 #include "nsIScriptContext.h"
    36 #include "nsIScriptGlobalObject.h"
    37 #include "nsContentUtils.h"
    38 #include "nsCxPusher.h"
    39 #include "nsDOMJSUtils.h"
    40 #include "nsJSUtils.h"
    41 #include "nsIXPConnect.h"
    42 #include "nsIRunnable.h"
    43 #include "nsIWindowWatcher.h"
    44 #include "nsIPrompt.h"
    45 #include "nsIFilePicker.h"
    46 #include "nsJSPrincipals.h"
    47 #include "nsJSUtils.h"
    48 #include "nsIPrincipal.h"
    49 #include "nsIScriptSecurityManager.h"
    50 #include "nsIGenKeypairInfoDlg.h"
    51 #include "nsIDOMCryptoDialogs.h"
    52 #include "nsIFormSigningDialog.h"
    53 #include "nsIContentSecurityPolicy.h"
    54 #include "nsIURI.h"
    55 #include "jsapi.h"
    56 #include "js/OldDebugAPI.h"
    57 #include <ctype.h>
    58 #include "pk11func.h"
    59 #include "keyhi.h"
    60 #include "cryptohi.h"
    61 #include "seccomon.h"
    62 #include "secerr.h"
    63 #include "sechash.h"
    64 #include "crmf.h"
    65 #include "pk11pqg.h"
    66 #include "cmmf.h"
    67 #include "nssb64.h"
    68 #include "base64.h"
    69 #include "cert.h"
    70 #include "certdb.h"
    71 #include "secmod.h"
    72 #include "ScopedNSSTypes.h"
    73 #include "pkix/pkixtypes.h"
    75 #include "ssl.h" // For SSL_ClearSessionCache
    77 #include "nsNSSCleaner.h"
    79 #include "nsNSSCertHelper.h"
    80 #include <algorithm>
    81 #include "nsWrapperCacheInlines.h"
    82 #endif
    83 #ifndef MOZ_DISABLE_CRYPTOLEGACY
    84 #include "mozilla/dom/CRMFObjectBinding.h"
    85 #endif
    87 using namespace mozilla;
    88 using namespace mozilla::dom;
    90 /*
    91  * These are the most common error strings that are returned
    92  * by the JavaScript methods in case of error.
    93  */
    95 #define JS_ERROR       "error:"
    96 #define JS_ERROR_INTERNAL  JS_ERROR"internalError"
    98 #undef REPORT_INCORRECT_NUM_ARGS
   100 #define JS_OK_ADD_MOD                      3
   101 #define JS_OK_DEL_EXTERNAL_MOD             2
   102 #define JS_OK_DEL_INTERNAL_MOD             1
   104 #define JS_ERR_INTERNAL                   -1
   105 #define JS_ERR_USER_CANCEL_ACTION         -2
   106 #define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
   107 #define JS_ERR_DEL_MOD                    -4
   108 #define JS_ERR_ADD_MOD                    -5
   109 #define JS_ERR_BAD_MODULE_NAME            -6
   110 #define JS_ERR_BAD_DLL_NAME               -7
   111 #define JS_ERR_BAD_MECHANISM_FLAGS        -8
   112 #define JS_ERR_BAD_CIPHER_ENABLE_FLAGS    -9
   113 #define JS_ERR_ADD_DUPLICATE_MOD          -10
   115 #ifndef MOZ_DISABLE_CRYPTOLEGACY
   117 NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
   119 /*
   120  * This structure is used to store information for one key generation.
   121  * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
   122  * stores one of these structures for every key generation that happens.
   123  * The information stored in this structure is then used to set some
   124  * values in the CRMF request.
   125  */
   126 typedef enum {
   127   rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
   128   ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
   129   dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
   130 } nsKeyGenType;
   132 bool isECKeyGenType(nsKeyGenType kgt)
   133 {
   134   switch (kgt)
   135   {
   136     case ecEnc:
   137     case ecDualUse:
   138     case ecSign:
   139     case ecNonrepudiation:
   140     case ecSignNonrepudiation:
   141       return true;
   143     default:
   144       break;
   145   }
   147   return false;
   148 }
   150 typedef struct nsKeyPairInfoStr {
   151   SECKEYPublicKey  *pubKey;     /* The putlic key associated with gen'd 
   152                                    priv key. */
   153   SECKEYPrivateKey *privKey;    /* The private key we generated */ 
   154   nsKeyGenType      keyGenType; /* What type of key gen are we doing.*/
   156   CERTCertificate *ecPopCert;
   157                    /* null: use signing for pop
   158                       other than null: a cert that defines EC keygen params
   159                                        and will be used for dhMac PoP. */
   161   SECKEYPublicKey  *ecPopPubKey;
   162                    /* extracted public key from ecPopCert */
   163 } nsKeyPairInfo;
   166 //This class is just used to pass arguments
   167 //to the nsCryptoRunnable event.
   168 class nsCryptoRunArgs : public nsISupports {
   169 public:
   170   nsCryptoRunArgs(JSContext *aCx);
   171   virtual ~nsCryptoRunArgs();
   172   nsCOMPtr<nsISupports> m_kungFuDeathGrip;
   173   JSContext *m_cx;
   174   JS::PersistentRooted<JSObject*> m_scope;
   175   nsCOMPtr<nsIPrincipal> m_principals;
   176   nsXPIDLCString m_jsCallback;
   177   NS_DECL_ISUPPORTS
   178 };
   180 //This class is used to run the callback code
   181 //passed to crypto.generateCRMFRequest
   182 //We have to do that for backwards compatibility
   183 //reasons w/ PSM 1.x and Communciator 4.x
   184 class nsCryptoRunnable : public nsIRunnable {
   185 public:
   186   nsCryptoRunnable(nsCryptoRunArgs *args);
   187   virtual ~nsCryptoRunnable();
   189   NS_IMETHOD Run ();
   190   NS_DECL_ISUPPORTS
   191 private:
   192   nsCryptoRunArgs *m_args;
   193 };
   196 //We're going to inherit the memory passed
   197 //into us.
   198 //This class backs up an array of certificates
   199 //as an event.
   200 class nsP12Runnable : public nsIRunnable {
   201 public:
   202   nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, nsIPK11Token *token);
   203   virtual ~nsP12Runnable();
   205   NS_IMETHOD Run();
   206   NS_DECL_ISUPPORTS
   207 private:
   208   nsCOMPtr<nsIPK11Token> mToken;
   209   nsIX509Cert **mCertArr;
   210   int32_t       mNumCerts;
   211 };
   213 // QueryInterface implementation for nsCrypto
   214 NS_INTERFACE_MAP_BEGIN(nsCrypto)
   215   NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
   216 NS_INTERFACE_MAP_END_INHERITING(mozilla::dom::Crypto)
   218 NS_IMPL_ADDREF_INHERITED(nsCrypto, mozilla::dom::Crypto)
   219 NS_IMPL_RELEASE_INHERITED(nsCrypto, mozilla::dom::Crypto)
   221 // QueryInterface implementation for nsPkcs11
   222 #endif // MOZ_DISABLE_CRYPTOLEGACY
   224 NS_INTERFACE_MAP_BEGIN(nsPkcs11)
   225   NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
   226   NS_INTERFACE_MAP_ENTRY(nsISupports)
   227 NS_INTERFACE_MAP_END
   229 NS_IMPL_ADDREF(nsPkcs11)
   230 NS_IMPL_RELEASE(nsPkcs11)
   232 #ifndef MOZ_DISABLE_CRYPTOLEGACY
   234 // ISupports implementation for nsCryptoRunnable
   235 NS_IMPL_ISUPPORTS(nsCryptoRunnable, nsIRunnable)
   237 // ISupports implementation for nsP12Runnable
   238 NS_IMPL_ISUPPORTS(nsP12Runnable, nsIRunnable)
   240 // ISupports implementation for nsCryptoRunArgs
   241 NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
   243 nsCrypto::nsCrypto() :
   244   mEnableSmartCardEvents(false)
   245 {
   246 }
   248 nsCrypto::~nsCrypto()
   249 {
   250 }
   252 void
   253 nsCrypto::Init(nsIDOMWindow* aWindow)
   254 {
   255   mozilla::dom::Crypto::Init(aWindow);
   256 }
   258 void
   259 nsCrypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv)
   260 {
   261   NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   263   nsresult rv = NS_OK;
   265   // this has the side effect of starting the nssComponent (and initializing
   266   // NSS) even if it isn't already going. Starting the nssComponent is a
   267   // prerequisite for getting smartCard events.
   268   if (aEnable) {
   269     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   270   }
   272   if (NS_FAILED(rv)) {
   273     aRv.Throw(rv);
   274     return;
   275   }
   277   mEnableSmartCardEvents = aEnable;
   278 }
   280 NS_IMETHODIMP
   281 nsCrypto::SetEnableSmartCardEvents(bool aEnable)
   282 {
   283   ErrorResult rv;
   284   SetEnableSmartCardEvents(aEnable, rv);
   285   return rv.ErrorCode();
   286 }
   288 bool
   289 nsCrypto::EnableSmartCardEvents()
   290 {
   291   return mEnableSmartCardEvents;
   292 }
   294 NS_IMETHODIMP
   295 nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
   296 {
   297   *aEnable = EnableSmartCardEvents();
   298   return NS_OK;
   299 }
   301 //A quick function to let us know if the key we're trying to generate
   302 //can be escrowed.
   303 static bool
   304 ns_can_escrow(nsKeyGenType keyGenType)
   305 {
   306   /* For now, we only escrow rsa-encryption and ec-encryption keys. */
   307   return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
   308 }
   310 //Retrieve crypto.version so that callers know what
   311 //version of PSM this is.
   312 void
   313 nsCrypto::GetVersion(nsString& aVersion)
   314 {
   315   aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING));
   316 }
   318 /*
   319  * Given an nsKeyGenType, return the PKCS11 mechanism that will
   320  * perform the correct key generation.
   321  */
   322 static uint32_t
   323 cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
   324 {
   325   uint32_t retMech;
   327   switch (keyGenType) {
   328   case rsaEnc:
   329   case rsaDualUse:
   330   case rsaSign:
   331   case rsaNonrepudiation:
   332   case rsaSignNonrepudiation:
   333     retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
   334     break;
   335   case ecEnc:
   336   case ecDualUse:
   337   case ecSign:
   338   case ecNonrepudiation:
   339   case ecSignNonrepudiation:
   340     retMech = CKM_EC_KEY_PAIR_GEN;
   341     break;
   342   case dhEx:
   343     retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
   344     break;
   345   case dsaSign:
   346   case dsaSignNonrepudiation:
   347   case dsaNonrepudiation:
   348     retMech = CKM_DSA_KEY_PAIR_GEN;
   349     break;
   350   default:
   351     retMech = CKM_INVALID_MECHANISM;
   352   }
   353   return retMech;
   354 }
   356 /*
   357  * This function takes a string read through JavaScript parameters
   358  * and translates it to the internal enumeration representing the
   359  * key gen type. Leading and trailing whitespace must be already removed.
   360  */
   361 static nsKeyGenType
   362 cryptojs_interpret_key_gen_type(const nsAString& keyAlg)
   363 {
   364   if (keyAlg.EqualsLiteral("rsa-ex")) {
   365     return rsaEnc;
   366   }
   367   if (keyAlg.EqualsLiteral("rsa-dual-use")) {
   368     return rsaDualUse;
   369   }
   370   if (keyAlg.EqualsLiteral("rsa-sign")) {
   371     return rsaSign;
   372   }
   373   if (keyAlg.EqualsLiteral("rsa-sign-nonrepudiation")) {
   374     return rsaSignNonrepudiation;
   375   }
   376   if (keyAlg.EqualsLiteral("rsa-nonrepudiation")) {
   377     return rsaNonrepudiation;
   378   }
   379   if (keyAlg.EqualsLiteral("ec-ex")) {
   380     return ecEnc;
   381   }
   382   if (keyAlg.EqualsLiteral("ec-dual-use")) {
   383     return ecDualUse;
   384   }
   385   if (keyAlg.EqualsLiteral("ec-sign")) {
   386     return ecSign;
   387   }
   388   if (keyAlg.EqualsLiteral("ec-sign-nonrepudiation")) {
   389     return ecSignNonrepudiation;
   390   }
   391   if (keyAlg.EqualsLiteral("ec-nonrepudiation")) {
   392     return ecNonrepudiation;
   393   }
   394   if (keyAlg.EqualsLiteral("dsa-sign-nonrepudiation")) {
   395     return dsaSignNonrepudiation;
   396   }
   397   if (keyAlg.EqualsLiteral("dsa-sign")) {
   398     return dsaSign;
   399   }
   400   if (keyAlg.EqualsLiteral("dsa-nonrepudiation")) {
   401     return dsaNonrepudiation;
   402   }
   403   if (keyAlg.EqualsLiteral("dh-ex")) {
   404     return dhEx;
   405   }
   406   return invalidKeyGen;
   407 }
   409 /* 
   410  * input: null terminated char* pointing to (the remainder of) an
   411  * EC key param string.
   412  *
   413  * bool return value, false means "no more name=value pair found",
   414  *                    true means "found, see out params"
   415  * 
   416  * out param name: char * pointing to name (not zero terminated)
   417  * out param name_len: length of found name
   418  * out param value: char * pointing to value (not zero terminated)
   419  * out param value_len: length of found value
   420  * out param next_pair: to be used for a follow up call to this function
   421  */
   423 bool getNextNameValueFromECKeygenParamString(char *input,
   424                                                char *&name,
   425                                                int &name_len,
   426                                                char *&value,
   427                                                int &value_len,
   428                                                char *&next_call)
   429 {
   430   if (!input || !*input)
   431     return false;
   433   // we allow leading ; and leading space in front of each name value pair
   435   while (*input && *input == ';')
   436     ++input;
   438   while (*input && *input == ' ')
   439     ++input;
   441   name = input;
   443   while (*input && *input != '=')
   444     ++input;
   446   if (*input != '=')
   447     return false;
   449   name_len = input - name;
   450   ++input;
   452   value = input;
   454   while (*input && *input != ';')
   455     ++input;
   457   value_len = input - value;
   458   next_call = input;
   460   return true;
   461 }
   463 //Take the string passed into us via crypto.generateCRMFRequest
   464 //as the keygen type parameter and convert it to parameters 
   465 //we can actually pass to the PKCS#11 layer.
   466 static void*
   467 nsConvertToActualKeyGenParams(uint32_t keyGenMech, char *params,
   468                               uint32_t paramLen, int32_t keySize,
   469                               nsKeyPairInfo *keyPairInfo)
   470 {
   471   void *returnParams = nullptr;
   474   switch (keyGenMech) {
   475   case CKM_RSA_PKCS_KEY_PAIR_GEN:
   476   {
   477     // For RSA, we don't support passing in key generation arguments from
   478     // the JS code just yet.
   479     if (params)
   480       return nullptr;
   482     PK11RSAGenParams *rsaParams;
   483     rsaParams = static_cast<PK11RSAGenParams*>
   484                            (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
   486     if (!rsaParams) {
   487       return nullptr;
   488     }
   489     /* I'm just taking the same parameters used in 
   490      * certdlgs.c:GenKey
   491      */
   492     if (keySize > 0) {
   493       rsaParams->keySizeInBits = keySize;
   494     } else {
   495       rsaParams->keySizeInBits = 1024;
   496     }
   497     rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
   498     returnParams = rsaParams;
   499     break;
   500   }
   501   case CKM_EC_KEY_PAIR_GEN:
   502   {
   503     /*
   504      * keygen params for generating EC keys must be composed of name=value pairs,
   505      * multiple pairs allowed, separated using semicolon ;
   506      *
   507      * Either param "curve" or param "popcert" must be specified.
   508      * curve=name-of-curve
   509      * popcert=base64-encoded-cert
   510      *
   511      * When both params are specified, popcert will be used.
   512      * If no popcert param is given, or if popcert can not be decoded,
   513      * we will fall back to the curve param.
   514      *
   515      * Additional name=value pairs may be defined in the future.
   516      *
   517      * If param popcert is present and valid, the given certificate will be used
   518      * to determine the key generation params. In addition the certificate
   519      * will be used to produce a dhMac based Proof of Posession,
   520      * using the cert's public key, subject and issuer names,
   521      * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
   522      *
   523      * If neither param popcert nor param curve could be used,
   524      * tse a curve based on the keysize param.
   525      * NOTE: Here keysize is used only as an indication of
   526      * High/Medium/Low strength; elliptic curve
   527      * cryptography uses smaller keys than RSA to provide
   528      * equivalent security.
   529      */
   531     char *curve = nullptr;
   533     {
   534       // extract components of name=value list
   536       char *next_input = params;
   537       char *name = nullptr;
   538       char *value = nullptr;
   539       int name_len = 0;
   540       int value_len = 0;
   542       while (getNextNameValueFromECKeygenParamString(
   543               next_input, name, name_len, value, value_len,
   544               next_input))
   545       {
   546         // use only the first specified curve
   547         if (!curve && PL_strncmp(name, "curve", std::min(name_len, 5)) == 0)
   548         {
   549           curve = PL_strndup(value, value_len);
   550         }
   551         // use only the first specified popcert
   552         else if (!keyPairInfo->ecPopCert &&
   553                  PL_strncmp(name, "popcert", std::min(name_len, 7)) == 0)
   554         {
   555           char *certstr = PL_strndup(value, value_len);
   556           if (certstr) {
   557             keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
   558             PL_strfree(certstr);
   560             if (keyPairInfo->ecPopCert)
   561             {
   562               keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
   563             }
   564           }
   565         }
   566       }
   567     }
   569     // first try to use the params of the provided CA cert
   570     if (keyPairInfo->ecPopPubKey && keyPairInfo->ecPopPubKey->keyType == ecKey)
   571     {
   572       returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
   573     }
   575     // if we did not yet find good params, do we have a curve name?
   576     if (!returnParams && curve)
   577     {
   578       returnParams = decode_ec_params(curve);
   579     }
   581     // if we did not yet find good params, do something based on keysize
   582     if (!returnParams)
   583     {
   584       switch (keySize) {
   585       case 512:
   586       case 1024:
   587           returnParams = decode_ec_params("secp256r1");
   588           break;
   589       case 2048:
   590       default:
   591           returnParams = decode_ec_params("secp384r1");
   592           break;
   593       }
   594     }
   596     if (curve)
   597       PL_strfree(curve);
   599     break;
   600   }
   601   case CKM_DSA_KEY_PAIR_GEN:
   602   {
   603     // For DSA, we don't support passing in key generation arguments from
   604     // the JS code just yet.
   605     if (params)
   606       return nullptr;
   608     PQGParams *pqgParams = nullptr;
   609     PQGVerify *vfy = nullptr;
   610     SECStatus  rv;
   611     int        index;
   613     index = PQG_PBITS_TO_INDEX(keySize);
   614     if (index == -1) {
   615       returnParams = nullptr;
   616       break;
   617     }
   618     rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
   619     if (vfy) {
   620       PK11_PQG_DestroyVerify(vfy);
   621     }
   622     if (rv != SECSuccess) {
   623       if (pqgParams) {
   624         PK11_PQG_DestroyParams(pqgParams);
   625       }
   626       return nullptr;
   627     }
   628     returnParams = pqgParams;
   629     break;
   630   }
   631   default:
   632     returnParams = nullptr;
   633   }
   634   return returnParams;
   635 }
   637 //We need to choose which PKCS11 slot we're going to generate
   638 //the key on.  Calls the default implementation provided by
   639 //nsKeygenHandler.cpp
   640 static PK11SlotInfo*
   641 nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
   642 {
   643   nsNSSShutDownPreventionLock locker;
   644   uint32_t mechanism = cryptojs_convert_to_mechanism(keyGenType);
   645   PK11SlotInfo *slot = nullptr;
   646   nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
   647   if (NS_FAILED(rv)) {
   648     if (slot)
   649       PK11_FreeSlot(slot);
   650     slot = nullptr;
   651   }
   652   return slot;
   653 }
   655 //Free the parameters that were passed into PK11_GenerateKeyPair
   656 //depending on the mechanism type used.
   657 static void
   658 nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
   659 {
   660   switch (keyGenMechanism) {
   661   case CKM_RSA_PKCS_KEY_PAIR_GEN:
   662     nsMemory::Free(params);
   663     break;
   664   case CKM_EC_KEY_PAIR_GEN:
   665     SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
   666     break;
   667   case CKM_DSA_KEY_PAIR_GEN:
   668     PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
   669     break;
   670   }
   671 }
   673 //Function that is used to generate a single key pair.
   674 //Once all the arguments have been parsed and processed, this
   675 //function gets called and takes care of actually generating
   676 //the key pair passing the appopriate parameters to the NSS
   677 //functions.
   678 static nsresult
   679 cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 
   680                             int32_t keySize, char *params, 
   681                             nsIInterfaceRequestor *uiCxt,
   682                             PK11SlotInfo *slot, bool willEscrow)
   684 {
   685   const PK11AttrFlags sensitiveFlags = (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
   686   const PK11AttrFlags temporarySessionFlags = PK11_ATTR_SESSION;
   687   const PK11AttrFlags permanentTokenFlags = PK11_ATTR_TOKEN;
   688   const PK11AttrFlags extractableFlags = PK11_ATTR_EXTRACTABLE;
   690   nsIGeneratingKeypairInfoDialogs * dialogs;
   691   nsKeygenThread *KeygenRunnable = 0;
   692   nsCOMPtr<nsIKeygenThread> runnable;
   694   uint32_t mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
   695   void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 
   696                                                      (params) ? strlen(params):0, 
   697                                                      keySize, keyPairInfo);
   699   if (!keyGenParams || !slot) {
   700     return NS_ERROR_INVALID_ARG;
   701   }
   703   // Make sure the token has password already set on it before trying
   704   // to generate the key.
   706   nsresult rv = setPassword(slot, uiCxt);
   707   if (NS_FAILED(rv))
   708     return rv;
   710   if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
   711     return NS_ERROR_FAILURE;
   713   // Smart cards will not let you extract a private key once 
   714   // it is on the smart card.  If we've been told to escrow
   715   // a private key that will be stored on a smart card,
   716   // then we'll use the following strategy to ensure we can escrow it.
   717   // We'll attempt to generate the key on our internal token,
   718   // because this is expected to avoid some problems.
   719   // If it works, we'll escrow, move the key to the smartcard, done.
   720   // If it didn't work (or the internal key doesn't support the desired
   721   // mechanism), then we'll attempt to generate the key on
   722   // the destination token, with the EXTRACTABLE flag set.
   723   // If it works, we'll extract, escrow, done.
   724   // If it failed, then we're unable to escrow and return failure.
   725   // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
   726   //       so that the key has zero chance of being store in the
   727   //       user's key3.db file.  Which the slot returned by
   728   //       PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
   729   //       does not.
   730   ScopedPK11SlotInfo intSlot;
   732   if (willEscrow && !PK11_IsInternal(slot)) {
   733     intSlot = PK11_GetInternalSlot();
   734     NS_ASSERTION(intSlot,"Couldn't get the internal slot");
   736     if (!PK11_DoesMechanism(intSlot, mechanism)) {
   737       // Set to null, and the subsequent code will not attempt to use it.
   738       intSlot = nullptr;
   739     }
   740   }
   742   rv = getNSSDialogs((void**)&dialogs,
   743                      NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
   744                      NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
   746   if (NS_SUCCEEDED(rv)) {
   747     KeygenRunnable = new nsKeygenThread();
   748     if (KeygenRunnable) {
   749       NS_ADDREF(KeygenRunnable);
   750     }
   751   }
   753   // "firstAttemptSlot" and "secondAttemptSlot" are alternative names
   754   // for better code readability, we don't increase the reference counts.
   756   PK11SlotInfo *firstAttemptSlot = nullptr;
   757   PK11AttrFlags firstAttemptFlags = 0;
   759   PK11SlotInfo *secondAttemptSlot = slot;
   760   PK11AttrFlags secondAttemptFlags = sensitiveFlags | permanentTokenFlags;
   762   if (willEscrow) {
   763     secondAttemptFlags |= extractableFlags;
   764   }
   766   if (!intSlot || PK11_IsInternal(slot)) {
   767     // if we cannot use the internal slot, then there is only one attempt
   768     // if the destination slot is the internal slot, then there is only one attempt
   769     firstAttemptSlot = secondAttemptSlot;
   770     firstAttemptFlags = secondAttemptFlags;
   771     secondAttemptSlot = nullptr;
   772     secondAttemptFlags = 0;
   773   }
   774   else {
   775     firstAttemptSlot = intSlot;
   776     firstAttemptFlags = sensitiveFlags | temporarySessionFlags;
   778     // We always need the extractable flag on the first attempt,
   779     // because we want to move the key to another slot - ### is this correct?
   780     firstAttemptFlags |= extractableFlags;
   781   }
   783   bool mustMoveKey = false;
   785   if (NS_FAILED(rv) || !KeygenRunnable) {
   786     /* execute key generation on this thread */
   787     rv = NS_OK;
   789     keyPairInfo->privKey = 
   790       PK11_GenerateKeyPairWithFlags(firstAttemptSlot, mechanism,
   791                                     keyGenParams, &keyPairInfo->pubKey,
   792                                     firstAttemptFlags, uiCxt);
   794     if (keyPairInfo->privKey) {
   795       // success on first attempt
   796       if (secondAttemptSlot) {
   797         mustMoveKey = true;
   798       }
   799     }
   800     else {
   801       keyPairInfo->privKey = 
   802         PK11_GenerateKeyPairWithFlags(secondAttemptSlot, mechanism,
   803                                       keyGenParams, &keyPairInfo->pubKey,
   804                                       secondAttemptFlags, uiCxt);
   805     }
   807   } else {
   808     /* execute key generation on separate thread */
   809     KeygenRunnable->SetParams( firstAttemptSlot, firstAttemptFlags,
   810                                secondAttemptSlot, secondAttemptFlags,
   811                                mechanism, keyGenParams, uiCxt );
   813     runnable = do_QueryInterface(KeygenRunnable);
   815     if (runnable) {
   816       {
   817         nsPSMUITracker tracker;
   818         if (tracker.isUIForbidden()) {
   819           rv = NS_ERROR_NOT_AVAILABLE;
   820         }
   821         else {
   822           rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
   823           // We call join on the thread, 
   824           // so we can be sure that no simultaneous access to the passed parameters will happen.
   825           KeygenRunnable->Join();
   826         }
   827       }
   829       NS_RELEASE(dialogs);
   830       if (NS_SUCCEEDED(rv)) {
   831         PK11SlotInfo *used_slot = nullptr;
   832         rv = KeygenRunnable->ConsumeResult(&used_slot, 
   833                                            &keyPairInfo->privKey, &keyPairInfo->pubKey);
   835         if (NS_SUCCEEDED(rv)) {
   836           if ((used_slot == firstAttemptSlot) && secondAttemptSlot) {
   837             mustMoveKey = true;
   838           }
   840           if (used_slot) {
   841             PK11_FreeSlot(used_slot);
   842           }
   843         }
   844       }
   845     }
   846   }
   848   firstAttemptSlot = nullptr;
   849   secondAttemptSlot = nullptr;
   851   nsFreeKeyGenParams(mechanism, keyGenParams);
   853   if (KeygenRunnable) {
   854     NS_RELEASE(KeygenRunnable);
   855   }
   857   if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
   858     return NS_ERROR_FAILURE;
   859   }
   861   //If we generated the key pair on the internal slot because the
   862   // keys were going to be escrowed, move the keys over right now.
   863   if (mustMoveKey) {
   864     ScopedSECKEYPrivateKey newPrivKey(PK11_LoadPrivKey(slot,
   865                                                     keyPairInfo->privKey,
   866                                                     keyPairInfo->pubKey,
   867                                                     true, true));
   868     if (!newPrivKey)
   869       return NS_ERROR_FAILURE;
   871     // The private key is stored on the selected slot now, and the copy we
   872     // ultimately use for escrowing when the time comes lives 
   873     // in the internal slot.  We will delete it from that slot
   874     // after the requests are made.
   875   }  
   877   return NS_OK;
   878 }
   880 /*
   881  * FUNCTION: cryptojs_ReadArgsAndGenerateKey
   882  * -------------------------------------
   883  * INPUTS:
   884  *  cx
   885  *    The JSContext associated with the execution of the corresponging
   886  *    crypto.generateCRMFRequest call
   887  *  argv
   888  *    A pointer to an array of JavaScript parameters passed to the
   889  *    method crypto.generateCRMFRequest.  The array should have the
   890  *    3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
   891  *    the definition of crypto.generateCRMFRequest at the following
   892  *    document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
   893  *  keyGenType
   894  *    A structure used to store the information about the newly created
   895  *    key pair.
   896  *  uiCxt
   897  *    An interface requestor that would be used to get an nsIPrompt
   898  *    if we need to ask the user for a password.
   899  *  slotToUse
   900  *    The PKCS11 slot to use for generating the key pair. If nullptr, then
   901  *    this function should select a slot that can do the key generation 
   902  *    from the keytype associted with the keyPairInfo, and pass it back to
   903  *    the caller so that subsequence key generations can use the same slot. 
   904  *  willEscrow
   905  *    If true, then that means we will try to escrow the generated
   906  *    private key when building the CRMF request.  If false, then
   907  *    we will not try to escrow the private key.
   908  *
   909  * NOTES:
   910  * This function takes care of reading a set of 3 parameters that define
   911  * one key generation.  The argv pointer should be one that originates
   912  * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
   913  * The function interprets the argument in the first index as an integer and
   914  * passes that as the key size for the key generation-this parameter is
   915  * mandatory.  The second parameter is read in as a string.  This value can
   916  * be null in JavaScript world and everything will still work.  The third
   917  * parameter is a mandatory string that indicates what kind of key to generate.
   918  * There should always be 1-to-1 correspondence between the strings compared
   919  * in the function cryptojs_interpret_key_gen_type and the strings listed in
   920  * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
   921  * under the definition of the method generateCRMFRequest, for the parameter
   922  * "keyGenAlgN".  After reading the parameters, the function then 
   923  * generates the key pairs passing the parameters parsed from the JavaScript i
   924  * routine.  
   925  *
   926  * RETURN:
   927  * NS_OK if creating the Key was successful.  Any other return value
   928  * indicates an error.
   929  */
   931 static nsresult
   932 cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
   933                                 JS::Value *argv,
   934                                 nsKeyPairInfo *keyGenType,
   935                                 nsIInterfaceRequestor *uiCxt,
   936                                 PK11SlotInfo **slot, bool willEscrow)
   937 {
   938   JSString  *jsString;
   939   JSAutoByteString params;
   940   int    keySize;
   941   nsresult  rv;
   943   if (!JSVAL_IS_INT(argv[0])) {
   944     JS_ReportError(cx, "%s%s", JS_ERROR,
   945                    "passed in non-integer for key size");
   946     return NS_ERROR_FAILURE;
   947   }
   948   keySize = JSVAL_TO_INT(argv[0]);
   949   if (!JSVAL_IS_NULL(argv[1])) {
   950     JS::Rooted<JS::Value> v(cx, argv[1]);
   951     jsString = JS::ToString(cx, v);
   952     NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
   953     argv[1] = STRING_TO_JSVAL(jsString);
   954     params.encodeLatin1(cx, jsString);
   955     NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
   956   }
   958   if (JSVAL_IS_NULL(argv[2])) {
   959     JS_ReportError(cx,"%s%s", JS_ERROR,
   960              "key generation type not specified");
   961     return NS_ERROR_FAILURE;
   962   }
   963   JS::Rooted<JS::Value> v(cx, argv[2]);
   964   jsString = JS::ToString(cx, v);
   965   NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
   966   argv[2] = STRING_TO_JSVAL(jsString);
   967   nsDependentJSString dependentKeyGenAlg;
   968   NS_ENSURE_TRUE(dependentKeyGenAlg.init(cx, jsString), NS_ERROR_UNEXPECTED);
   969   nsAutoString keyGenAlg(dependentKeyGenAlg);
   970   keyGenAlg.Trim("\r\n\t ");
   971   keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg);
   972   if (keyGenType->keyGenType == invalidKeyGen) {
   973     NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
   974     JS_ReportError(cx, "%s%s%s", JS_ERROR,
   975                    "invalid key generation argument:",
   976                    keyGenAlgNarrow.get());
   977     goto loser;
   978   }
   979   if (!*slot) {
   980     *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
   981     if (!*slot)
   982       goto loser;
   983   }
   985   rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
   986                                    *slot,willEscrow);
   988   if (rv != NS_OK) {
   989     NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
   990     JS_ReportError(cx,"%s%s%s", JS_ERROR,
   991                    "could not generate the key for algorithm ",
   992                    keyGenAlgNarrow.get());
   993     goto loser;
   994   }
   995   return NS_OK;
   996 loser:
   997   return NS_ERROR_FAILURE;
   998 }
  1000 //Utility funciton to free up the memory used by nsKeyPairInfo
  1001 //arrays.
  1002 static void
  1003 nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
  1005   NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
  1006   if (!keyids)
  1007     return;
  1008   int i;
  1009   for (i=0; i<numIDs; i++) {
  1010     if (keyids[i].pubKey)
  1011       SECKEY_DestroyPublicKey(keyids[i].pubKey);
  1012     if (keyids[i].privKey)
  1013       SECKEY_DestroyPrivateKey(keyids[i].privKey);
  1014     if (keyids[i].ecPopCert)
  1015       CERT_DestroyCertificate(keyids[i].ecPopCert);
  1016     if (keyids[i].ecPopPubKey)
  1017       SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
  1019   delete []keyids;
  1022 //Utility funciton used to free the genertaed cert request messages
  1023 static void
  1024 nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, int32_t numMessages)
  1026   int32_t i;
  1027   for (i=0; i<numMessages && certReqMsgs[i]; i++) {
  1028     CRMF_DestroyCertReqMsg(certReqMsgs[i]);
  1030   delete []certReqMsgs;
  1033 //If the form called for escrowing the private key we just generated,
  1034 //this function adds all the correct elements to the request.
  1035 //That consists of adding CRMFEncryptedKey to the reques as part
  1036 //of the CRMFPKIArchiveOptions Control.
  1037 static nsresult
  1038 nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
  1039                      nsNSSCertificate *wrappingCert)
  1041   if (!wrappingCert ||
  1042       CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
  1043     return NS_ERROR_FAILURE;
  1045   mozilla::pkix::ScopedCERTCertificate cert(wrappingCert->GetCert());
  1046   if (!cert)
  1047     return NS_ERROR_FAILURE;
  1049   CRMFEncryptedKey *encrKey = 
  1050       CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert.get());
  1051   if (!encrKey)
  1052     return NS_ERROR_FAILURE;
  1054   CRMFPKIArchiveOptions *archOpt = 
  1055       CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
  1056   if (!archOpt) {
  1057     CRMF_DestroyEncryptedKey(encrKey);
  1058     return NS_ERROR_FAILURE;
  1060   SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
  1061   CRMF_DestroyEncryptedKey(encrKey);
  1062   CRMF_DestroyPKIArchiveOptions(archOpt);
  1063   if (srv != SECSuccess)
  1064     return NS_ERROR_FAILURE;
  1066   return NS_OK;
  1069 //Set the Distinguished Name (Subject Name) for the cert
  1070 //being requested.
  1071 static nsresult
  1072 nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
  1074   if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
  1075     return NS_ERROR_FAILURE;
  1077   ScopedCERTName subjectName(CERT_AsciiToName(reqDN));
  1078   if (!subjectName) {
  1079     return NS_ERROR_FAILURE;
  1081   SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
  1082                                                    static_cast<void*>
  1083                                                               (subjectName));
  1084   return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
  1087 //Set Registration Token Control on the request.
  1088 static nsresult
  1089 nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
  1091   // this should never happen, but might as well add this.
  1092   NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
  1093   if (regToken){
  1094     if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
  1095       return NS_ERROR_FAILURE;
  1097     SECItem src;
  1098     src.data = (unsigned char*)regToken;
  1099     src.len  = strlen(regToken);
  1100     SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src, 
  1101                                         SEC_ASN1_GET(SEC_UTF8StringTemplate));
  1103     if (!derEncoded)
  1104       return NS_ERROR_FAILURE;
  1106     SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
  1107     SECITEM_FreeItem(derEncoded,true);
  1108     if (srv != SECSuccess)
  1109       return NS_ERROR_FAILURE;
  1111   return NS_OK;
  1114 //Set the Authenticator control on the cert reuest.  It's just
  1115 //a string that gets passed along.
  1116 static nsresult
  1117 nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
  1119   //This should never happen, but might as well check.
  1120   NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
  1121   if (authenticator) {
  1122     if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
  1123       return NS_ERROR_FAILURE;
  1125     SECItem src;
  1126     src.data = (unsigned char*)authenticator;
  1127     src.len  = strlen(authenticator);
  1128     SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src,
  1129                                      SEC_ASN1_GET(SEC_UTF8StringTemplate));
  1130     if (!derEncoded)
  1131       return NS_ERROR_FAILURE;
  1133     SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 
  1134                                                             derEncoded);
  1135     SECITEM_FreeItem(derEncoded, true);
  1136     if (srv != SECSuccess)
  1137       return NS_ERROR_FAILURE;
  1139   return NS_OK;
  1142 // ASN1 DER encoding rules say that when encoding a BIT string,
  1143 // the length in the header for the bit string is the number 
  1144 // of "useful" bits in the BIT STRING.  So the function finds
  1145 // it and sets accordingly for the returned item.
  1146 static void
  1147 nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
  1149   unsigned char onebyte;
  1150   unsigned int i, len = 0;
  1152   /* to prevent warning on some platform at compile time */
  1153   onebyte = '\0';
  1154   /* Get the position of the right-most turn-on bit */
  1155   for (i = 0; i < (value->len ) * 8; ++i) {
  1156     if (i % 8 == 0)
  1157       onebyte = value->data[i/8];
  1158     if (onebyte & 0x80)
  1159       len = i;
  1160     onebyte <<= 1;
  1163   bitsmap->data = value->data;
  1164   /* Add one here since we work with base 1 */
  1165   bitsmap->len = len + 1;
  1168 //This next section defines all the functions that sets the 
  1169 //keyUsageExtension for all the different types of key gens
  1170 //we handle.  The keyUsageExtension is just a bit flag extension
  1171 //that we set in wrapper functions that call straight into
  1172 //nsSetKeyUsageExtension.  There is one wrapper funciton for each
  1173 //keyGenType.  The correct function will eventually be called 
  1174 //by going through a switch statement based on the nsKeyGenType
  1175 //in the nsKeyPairInfo struct.
  1176 static nsresult
  1177 nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
  1178                        unsigned char   keyUsage)
  1180   SECItem                 *encodedExt= nullptr;
  1181   SECItem                  keyUsageValue = { (SECItemType) 0, nullptr, 0 };
  1182   SECItem                  bitsmap = { (SECItemType) 0, nullptr, 0 };
  1183   SECStatus                srv;
  1184   CRMFCertExtension       *ext = nullptr;
  1185   CRMFCertExtCreationInfo  extAddParams;
  1186   SEC_ASN1Template         bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nullptr,
  1187                                              sizeof(SECItem)};
  1189   keyUsageValue.data = &keyUsage;
  1190   keyUsageValue.len  = 1;
  1191   nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
  1193   encodedExt = SEC_ASN1EncodeItem(nullptr, nullptr, &bitsmap,&bitStrTemplate);
  1194   if (!encodedExt) {
  1195     goto loser;
  1197   ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
  1198   if (!ext) {
  1199       goto loser;
  1201   extAddParams.numExtensions = 1;
  1202   extAddParams.extensions = &ext;
  1203   srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
  1204                                          &extAddParams);
  1205   if (srv != SECSuccess) {
  1206       goto loser;
  1208   CRMF_DestroyCertExtension(ext);
  1209   SECITEM_FreeItem(encodedExt, true);
  1210   return NS_OK;
  1211  loser:
  1212   if (ext) {
  1213     CRMF_DestroyCertExtension(ext);
  1215   if (encodedExt) {
  1216       SECITEM_FreeItem(encodedExt, true);
  1218   return NS_ERROR_FAILURE;
  1221 static nsresult
  1222 nsSetRSADualUse(CRMFCertRequest *crmfReq)
  1224   unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
  1225                            | KU_NON_REPUDIATION
  1226                            | KU_KEY_ENCIPHERMENT;
  1228   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1231 static nsresult
  1232 nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
  1234   unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
  1236   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1239 static nsresult
  1240 nsSetRSASign(CRMFCertRequest *crmfReq)
  1242   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1245   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1248 static nsresult
  1249 nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
  1251   unsigned char keyUsage = KU_NON_REPUDIATION;
  1253   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1256 static nsresult
  1257 nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
  1259   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1260                            KU_NON_REPUDIATION;
  1262   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1265 static nsresult
  1266 nsSetECDualUse(CRMFCertRequest *crmfReq)
  1268   unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
  1269                            | KU_NON_REPUDIATION
  1270                            | KU_KEY_AGREEMENT;
  1272   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1275 static nsresult
  1276 nsSetECKeyEx(CRMFCertRequest *crmfReq)
  1278   unsigned char keyUsage = KU_KEY_AGREEMENT;
  1280   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1283 static nsresult
  1284 nsSetECSign(CRMFCertRequest *crmfReq)
  1286   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1289   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1292 static nsresult
  1293 nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
  1295   unsigned char keyUsage = KU_NON_REPUDIATION;
  1297   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1300 static nsresult
  1301 nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
  1303   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1304                            KU_NON_REPUDIATION;
  1306   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1309 static nsresult
  1310 nsSetDH(CRMFCertRequest *crmfReq)
  1312   unsigned char keyUsage = KU_KEY_AGREEMENT;
  1314   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1317 static nsresult
  1318 nsSetDSASign(CRMFCertRequest *crmfReq)
  1320   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1322   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1325 static nsresult
  1326 nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
  1328   unsigned char keyUsage = KU_NON_REPUDIATION;
  1330   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1333 static nsresult
  1334 nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
  1336   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1337                            KU_NON_REPUDIATION;
  1339   return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1342 static nsresult
  1343 nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
  1345   nsresult rv;
  1347   switch (keyGenType) {
  1348   case rsaDualUse:
  1349     rv = nsSetRSADualUse(crmfReq);
  1350     break;
  1351   case rsaEnc:
  1352     rv = nsSetRSAKeyEx(crmfReq);
  1353     break;
  1354   case rsaSign:
  1355     rv = nsSetRSASign(crmfReq);
  1356     break;
  1357   case rsaNonrepudiation:
  1358     rv = nsSetRSANonRepudiation(crmfReq);
  1359     break;
  1360   case rsaSignNonrepudiation:
  1361     rv = nsSetRSASignNonRepudiation(crmfReq);
  1362     break;
  1363   case ecDualUse:
  1364     rv = nsSetECDualUse(crmfReq);
  1365     break;
  1366   case ecEnc:
  1367     rv = nsSetECKeyEx(crmfReq);
  1368     break;
  1369   case ecSign:
  1370     rv = nsSetECSign(crmfReq);
  1371     break;
  1372   case ecNonrepudiation:
  1373     rv = nsSetECNonRepudiation(crmfReq);
  1374     break;
  1375   case ecSignNonrepudiation:
  1376     rv = nsSetECSignNonRepudiation(crmfReq);
  1377     break;
  1378   case dhEx:
  1379     rv = nsSetDH(crmfReq);
  1380     break;
  1381   case dsaSign:
  1382     rv = nsSetDSASign(crmfReq);
  1383     break;
  1384   case dsaNonrepudiation:
  1385     rv = nsSetDSANonRepudiation(crmfReq);
  1386     break;
  1387   case dsaSignNonrepudiation:
  1388     rv = nsSetDSASignNonRepudiation(crmfReq);
  1389     break;
  1390   default:
  1391     rv = NS_ERROR_FAILURE;
  1392     break;
  1394   return rv;
  1397 //Create a single CRMFCertRequest with all of the necessary parts 
  1398 //already installed.  The request returned by this function will
  1399 //have all the parts necessary and can just be added to a 
  1400 //Certificate Request Message.
  1401 static CRMFCertRequest*
  1402 nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 
  1403                       char *authenticator, nsNSSCertificate *wrappingCert)
  1405   uint32_t reqID;
  1406   nsresult rv;
  1408   //The draft says the ID of the request should be a random
  1409   //number.  We don't have a way of tracking this number
  1410   //to compare when the reply actually comes back,though.
  1411   PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
  1412   CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
  1413   if (!certReq)
  1414     return nullptr;
  1416   long version = SEC_CERTIFICATE_VERSION_3;
  1417   SECStatus srv;
  1418   CERTSubjectPublicKeyInfo *spki = nullptr;
  1419   srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
  1420   if (srv != SECSuccess)
  1421     goto loser;
  1423   spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
  1424   if (!spki)
  1425     goto loser;
  1427   srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
  1428   SECKEY_DestroySubjectPublicKeyInfo(spki);
  1429   if (srv != SECSuccess)
  1430     goto loser;
  1432   if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
  1433     rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
  1434     if (NS_FAILED(rv))
  1435       goto loser;
  1437   rv = nsSetDNForRequest(certReq, reqDN);
  1438   if (NS_FAILED(rv))
  1439     goto loser;
  1441   rv = nsSetRegToken(certReq, regToken);
  1442   if (NS_FAILED(rv))
  1443     goto loser;
  1445   rv = nsSetAuthenticator(certReq, authenticator);
  1446   if (NS_FAILED(rv))
  1447     goto loser;
  1449  rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 
  1450   if (NS_FAILED(rv))
  1451     goto loser;
  1453   return certReq;
  1454 loser:
  1455   if (certReq) {
  1456     CRMF_DestroyCertRequest(certReq);
  1458   return nullptr;
  1461 /*
  1462  * This function will set the Proof Of Possession (POP) for a request
  1463  * associated with a key pair intended to do Key Encipherment.  Currently
  1464  * this means encryption only keys.
  1465  */
  1466 static nsresult
  1467 nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
  1469   SECItem       bitString;
  1470   unsigned char der[2];
  1471   SECStatus     srv;
  1473   if (isEscrowed) {
  1474     /* For proof of possession on escrowed keys, we use the
  1475      * this Message option of POPOPrivKey and include a zero
  1476      * length bit string in the POP field.  This is OK because the encrypted
  1477      * private key already exists as part of the PKIArchiveOptions
  1478      * Control and that for all intents and purposes proves that
  1479      * we do own the private key.
  1480      */
  1481     der[0] = 0x03; /*We've got a bit string          */
  1482     der[1] = 0x00; /*We've got a 0 length bit string */
  1483     bitString.data = der;
  1484     bitString.len  = 2;
  1485     srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
  1486                                               crmfNoSubseqMess, &bitString);
  1487   } else {
  1488     /* If the encryption key is not being escrowed, then we set the 
  1489      * Proof Of Possession to be a Challenge Response mechanism.
  1490      */
  1491     srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
  1492                                               crmfSubsequentMessage,
  1493                                               crmfChallengeResp, nullptr);
  1495   return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
  1498 static void
  1499 nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
  1501 static void
  1502 nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
  1504 static nsresult
  1505 nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 
  1506                                  nsKeyPairInfo  *keyInfo,
  1507                                  CRMFCertRequest *certReq)
  1509   // RFC 2511 Appendix A section 2 a) defines,
  1510   // the "text" input for HMAC shall be the DER encoded version of
  1511   // of the single cert request.
  1512   // We'll produce that encoding and destroy it afterwards,
  1513   // because when sending the complete package to the CA,
  1514   // we'll use a different encoding, one that includes POP and
  1515   // allows multiple requests to be sent in one step.
  1517   unsigned long der_request_len = 0;
  1518   ScopedSECItem der_request;
  1520   if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
  1521                                            nsCRMFEncoderItemCount, 
  1522                                            &der_request_len))
  1523     return NS_ERROR_FAILURE;
  1525   der_request = SECITEM_AllocItem(nullptr, nullptr, der_request_len);
  1526   if (!der_request)
  1527     return NS_ERROR_FAILURE;
  1529   // set len in returned SECItem back to zero, because it will
  1530   // be used as the destination offset inside the 
  1531   // nsCRMFEncoderItemStore callback.
  1533   der_request->len = 0;
  1535   if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
  1536                                            nsCRMFEncoderItemStore, 
  1537                                            der_request))
  1538     return NS_ERROR_FAILURE;
  1540   // RFC 2511 Appendix A section 2 c):
  1541   // "A key K is derived from the shared secret Kec and the subject and
  1542   //  issuer names in the CA's certificate as follows:
  1543   //  K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
  1545   ScopedPK11SymKey shared_secret;
  1546   ScopedPK11SymKey subject_and_secret;
  1547   ScopedPK11SymKey subject_and_secret_and_issuer;
  1548   ScopedPK11SymKey sha1_of_subject_and_secret_and_issuer;
  1550   shared_secret = 
  1551     PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
  1552                           keyInfo->ecPopPubKey,  // SECKEYPublicKey *pubKey
  1553                           false, // bool isSender
  1554                           nullptr, // SECItem *randomA
  1555                           nullptr, // SECItem *randomB
  1556                           CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
  1557                           CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
  1558                           CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1559                           0, // int keySize
  1560                           CKD_NULL, // CK_ULONG kdf
  1561                           nullptr, // SECItem *sharedData
  1562                           nullptr); // void *wincx
  1564   if (!shared_secret)
  1565     return NS_ERROR_FAILURE;
  1567   CK_KEY_DERIVATION_STRING_DATA concat_data_base;
  1568   concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
  1569   concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
  1570   SECItem concat_data_base_item;
  1571   concat_data_base_item.data = (unsigned char*)&concat_data_base;
  1572   concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
  1574   subject_and_secret =
  1575     PK11_Derive(shared_secret, // PK11SymKey *baseKey
  1576                 CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
  1577                 &concat_data_base_item, // SECItem *param
  1578                 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
  1579                 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1580                 0); // int keySize
  1582   if (!subject_and_secret)
  1583     return NS_ERROR_FAILURE;
  1585   CK_KEY_DERIVATION_STRING_DATA concat_base_data;
  1586   concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
  1587   concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
  1588   SECItem concat_base_data_item;
  1589   concat_base_data_item.data = (unsigned char*)&concat_base_data;
  1590   concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
  1592   subject_and_secret_and_issuer =
  1593     PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
  1594                 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
  1595                 &concat_base_data_item, // SECItem *param
  1596                 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
  1597                 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1598                 0); // int keySize
  1600   if (!subject_and_secret_and_issuer)
  1601     return NS_ERROR_FAILURE;
  1603   sha1_of_subject_and_secret_and_issuer =
  1604     PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
  1605                 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
  1606                 nullptr, // SECItem *param
  1607                 CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
  1608                 CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
  1609                 0); // int keySize
  1611   if (!sha1_of_subject_and_secret_and_issuer)
  1612     return NS_ERROR_FAILURE;
  1614   PK11Context *context = nullptr;
  1615   PK11ContextCleanerTrueParam context_cleaner(context);
  1617   SECItem ignore;
  1618   ignore.data = 0;
  1619   ignore.len = 0;
  1621   context = 
  1622     PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
  1623                                CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
  1624                                sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
  1625                                &ignore); // SECItem *param
  1627   if (!context)
  1628     return NS_ERROR_FAILURE;
  1630   if (SECSuccess != PK11_DigestBegin(context))
  1631     return NS_ERROR_FAILURE;
  1633   if (SECSuccess != 
  1634       PK11_DigestOp(context, der_request->data, der_request->len))
  1635     return NS_ERROR_FAILURE;
  1637   ScopedAutoSECItem result_hmac_sha1_item(SHA1_LENGTH);
  1639   if (SECSuccess !=
  1640       PK11_DigestFinal(context, 
  1641                        result_hmac_sha1_item.data, 
  1642                        &result_hmac_sha1_item.len, 
  1643                        SHA1_LENGTH))
  1644     return NS_ERROR_FAILURE;
  1646   if (SECSuccess !=
  1647       CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
  1648                                         crmfNoSubseqMess, &result_hmac_sha1_item))
  1649     return NS_ERROR_FAILURE;
  1651   return NS_OK;
  1654 static nsresult
  1655 nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 
  1656                        nsKeyPairInfo  *keyInfo,
  1657                        CRMFCertRequest *certReq)
  1659   // Depending on the type of cert request we'll try
  1660   // POP mechanisms in different order,
  1661   // and add the result to the cert request message.
  1662   //
  1663   // For any signing or dual use cert,
  1664   //   try signing first,
  1665   //   fall back to DHMAC if we can
  1666   //     (EC cert requests that provide keygen param "popcert"),
  1667   //   otherwise fail.
  1668   //
  1669   // For encryption only certs that get escrowed, this is sufficient.
  1670   //
  1671   // For encryption only certs, that are not being escrowed, 
  1672   //   try DHMAC if we can 
  1673   //     (EC cert requests that provide keygen param "popcert"),
  1674   //   otherwise we'll indicate challenge response should be used.
  1676   bool isEncryptionOnlyCertRequest = false;
  1677   bool escrowEncryptionOnlyCert = false;
  1679   switch (keyInfo->keyGenType)
  1681     case rsaEnc:
  1682     case ecEnc:
  1683       isEncryptionOnlyCertRequest = true;
  1684       break;
  1686     case rsaSign:
  1687     case rsaDualUse:
  1688     case rsaNonrepudiation:
  1689     case rsaSignNonrepudiation:
  1690     case ecSign:
  1691     case ecDualUse:
  1692     case ecNonrepudiation:
  1693     case ecSignNonrepudiation:
  1694     case dsaSign:
  1695     case dsaNonrepudiation:
  1696     case dsaSignNonrepudiation:
  1697       break;
  1699     case dhEx:
  1700     /* This case may be supported in the future, but for now, we just fall 
  1701       * though to the default case and return an error for diffie-hellman keys.
  1702     */
  1703     default:
  1704       return NS_ERROR_FAILURE;
  1705   };
  1707   if (isEncryptionOnlyCertRequest)
  1709     escrowEncryptionOnlyCert = 
  1710       CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
  1713   bool gotDHMACParameters = false;
  1715   if (isECKeyGenType(keyInfo->keyGenType) && 
  1716       keyInfo->ecPopCert && 
  1717       keyInfo->ecPopPubKey)
  1719     gotDHMACParameters = true;
  1722   if (isEncryptionOnlyCertRequest)
  1724     if (escrowEncryptionOnlyCert)
  1725       return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
  1727     if (gotDHMACParameters)
  1728       return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1730     return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
  1733   // !isEncryptionOnlyCertRequest
  1735   SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
  1736                                                  keyInfo->privKey,
  1737                                                  keyInfo->pubKey, nullptr,
  1738                                                  nullptr, nullptr);
  1740   if (srv == SECSuccess)
  1741     return NS_OK;
  1743   if (!gotDHMACParameters)
  1744     return NS_ERROR_FAILURE;
  1746   return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1749 static void
  1750 nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
  1752   unsigned long *count = (unsigned long *)arg;
  1753   *count += len;
  1756 static void
  1757 nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
  1759   SECItem *dest = (SECItem *)arg;
  1760   memcpy(dest->data + dest->len, buf, len);
  1761   dest->len += len;
  1764 static SECItem*
  1765 nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
  1767   unsigned long len = 0;
  1768   if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
  1769       != SECSuccess) {
  1770     return nullptr;
  1772   SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
  1773   if (!dest) {
  1774     return nullptr;
  1776   dest->type = siBuffer;
  1777   dest->data = (unsigned char *)PORT_Alloc(len);
  1778   if (!dest->data) {
  1779     PORT_Free(dest);
  1780     return nullptr;
  1782   dest->len = 0;
  1784   if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
  1785       != SECSuccess) {
  1786     SECITEM_FreeItem(dest, true);
  1787     return nullptr;
  1789   return dest;
  1792 //Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
  1793 //requesting one or more certificates to be issued.  This function
  1794 //creates a single cert request per key pair and then appends it to
  1795 //a message that is ultimately sent off to a CA.
  1796 static char*
  1797 nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, int32_t numRequests,
  1798                         char *reqDN, char *regToken, char *authenticator,
  1799                         nsNSSCertificate *wrappingCert) 
  1801   // We'use the goto notation for clean-up purposes in this function
  1802   // that calls the C API of NSS.
  1803   int32_t i;
  1804   // The ASN1 encoder in NSS wants the last entry in the array to be
  1805   // nullptr so that it knows when the last element is.
  1806   CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
  1807   CRMFCertRequest *certReq;
  1808   if (!certReqMsgs)
  1809     return nullptr;
  1810   memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
  1811   SECStatus srv;
  1812   nsresult rv;
  1813   SECItem *encodedReq;
  1814   char *retString;
  1815   for (i=0; i<numRequests; i++) {
  1816     certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
  1817                                     wrappingCert);
  1818     if (!certReq)
  1819       goto loser;
  1821     certReqMsgs[i] = CRMF_CreateCertReqMsg();
  1822     if (!certReqMsgs[i])
  1823       goto loser;
  1824     srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
  1825     if (srv != SECSuccess)
  1826       goto loser;
  1828     rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
  1829     if (NS_FAILED(rv))
  1830       goto loser;
  1831     CRMF_DestroyCertRequest(certReq);
  1833   encodedReq = nsEncodeCertReqMessages(certReqMsgs);
  1834   nsFreeCertReqMessages(certReqMsgs, numRequests);
  1836   retString = NSSBase64_EncodeItem (nullptr, nullptr, 0, encodedReq);
  1837   SECITEM_FreeItem(encodedReq, true);
  1838   return retString;
  1839 loser:
  1840   nsFreeCertReqMessages(certReqMsgs,numRequests);
  1841   return nullptr;
  1844 static nsISupports *
  1845 GetISupportsFromContext(JSContext *cx)
  1847     if (JS::ContextOptionsRef(cx).privateIsNSISupports())
  1848         return static_cast<nsISupports *>(JS_GetContextPrivate(cx));
  1850     return nullptr;
  1853 //The top level method which is a member of nsIDOMCrypto
  1854 //for generate a base64 encoded CRMF request.
  1855 CRMFObject*
  1856 nsCrypto::GenerateCRMFRequest(JSContext* aContext,
  1857                               const nsCString& aReqDN,
  1858                               const nsCString& aRegToken,
  1859                               const nsCString& aAuthenticator,
  1860                               const nsCString& aEaCert,
  1861                               const nsCString& aJsCallback,
  1862                               const Sequence<JS::Value>& aArgs,
  1863                               ErrorResult& aRv)
  1865   nsNSSShutDownPreventionLock locker;
  1866   nsresult nrv;
  1868   uint32_t argc = aArgs.Length();
  1870   /*
  1871    * Get all of the parameters.
  1872    */
  1873   if (argc % 3 != 0) {
  1874     aRv.ThrowNotEnoughArgsError();
  1875     return nullptr;
  1878   if (aReqDN.IsVoid()) {
  1879     NS_WARNING("no DN specified");
  1880     aRv.Throw(NS_ERROR_FAILURE);
  1881     return nullptr;
  1884   if (aJsCallback.IsVoid()) {
  1885     NS_WARNING("no completion function specified");
  1886     aRv.Throw(NS_ERROR_FAILURE);
  1887     return nullptr;
  1890   JS::RootedObject script_obj(aContext, GetWrapper());
  1891   if (MOZ_UNLIKELY(!script_obj)) {
  1892     aRv.Throw(NS_ERROR_UNEXPECTED);
  1893     return nullptr;
  1896   nsCOMPtr<nsIContentSecurityPolicy> csp;
  1897   if (!nsContentUtils::GetContentSecurityPolicy(aContext, getter_AddRefs(csp))) {
  1898     NS_ERROR("Error: failed to get CSP");
  1899     aRv.Throw(NS_ERROR_FAILURE);
  1900     return nullptr;
  1903   bool evalAllowed = true;
  1904   bool reportEvalViolations = false;
  1905   if (csp && NS_FAILED(csp->GetAllowsEval(&reportEvalViolations, &evalAllowed))) {
  1906     NS_WARNING("CSP: failed to get allowsEval");
  1907     aRv.Throw(NS_ERROR_FAILURE);
  1908     return nullptr;
  1911   if (reportEvalViolations) {
  1912     NS_NAMED_LITERAL_STRING(scriptSample, "window.crypto.generateCRMFRequest: call to eval() or related function blocked by CSP");
  1914     const char *fileName;
  1915     uint32_t lineNum;
  1916     nsJSUtils::GetCallingLocation(aContext, &fileName, &lineNum);
  1917     csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
  1918                              NS_ConvertASCIItoUTF16(fileName),
  1919                              scriptSample,
  1920                              lineNum,
  1921                              EmptyString(),
  1922                              EmptyString());
  1925   if (!evalAllowed) {
  1926     NS_WARNING("eval() not allowed by Content Security Policy");
  1927     aRv.Throw(NS_ERROR_FAILURE);
  1928     return nullptr;
  1931   //Put up some UI warning that someone is trying to
  1932   //escrow the private key.
  1933   //Don't addref this copy.  That way ths reference goes away
  1934   //at the same the nsIX09Cert ref goes away.
  1935   nsNSSCertificate *escrowCert = nullptr;
  1936   nsCOMPtr<nsIX509Cert> nssCert;
  1937   bool willEscrow = false;
  1938   if (!aEaCert.IsVoid()) {
  1939     SECItem certDer = {siBuffer, nullptr, 0};
  1940     SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, aEaCert.get());
  1941     if (srv != SECSuccess) {
  1942       aRv.Throw(NS_ERROR_FAILURE);
  1943       return nullptr;
  1945     mozilla::pkix::ScopedCERTCertificate cert(
  1946       CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1947                               &certDer, nullptr, false, true));
  1948     if (!cert) {
  1949       aRv.Throw(NS_ERROR_FAILURE);
  1950       return nullptr;
  1953     escrowCert = nsNSSCertificate::Create(cert.get());
  1954     nssCert = escrowCert;
  1955     if (!nssCert) {
  1956       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  1957       return nullptr;
  1960     nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
  1961     nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
  1962                                 NS_GET_IID(nsIDOMCryptoDialogs),
  1963                                 NS_DOMCRYPTODIALOGS_CONTRACTID);
  1964     if (NS_FAILED(rv)) {
  1965       aRv.Throw(rv);
  1966       return nullptr;
  1969     bool okay=false;
  1971       nsPSMUITracker tracker;
  1972       if (tracker.isUIForbidden()) {
  1973         okay = false;
  1975       else {
  1976         dialogs->ConfirmKeyEscrow(nssCert, &okay);
  1979     if (!okay) {
  1980       aRv.Throw(NS_ERROR_FAILURE);
  1981       return nullptr;
  1983     willEscrow = true;
  1985   nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
  1986   int32_t numRequests = argc / 3;
  1987   nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
  1988   memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
  1989   int keyInfoIndex;
  1990   uint32_t i;
  1991   PK11SlotInfo *slot = nullptr;
  1992   // Go through all of the arguments and generate the appropriate key pairs.
  1993   for (i=0,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
  1994     nrv = cryptojs_ReadArgsAndGenerateKey(aContext,
  1995                                           const_cast<JS::Value*>(&aArgs[i]),
  1996                                           &keyids[keyInfoIndex],
  1997                                           uiCxt, &slot, willEscrow);
  1999     if (NS_FAILED(nrv)) {
  2000       if (slot)
  2001         PK11_FreeSlot(slot);
  2002       nsFreeKeyPairInfo(keyids,numRequests);
  2003       aRv.Throw(nrv);
  2004       return nullptr;
  2007   // By this time we'd better have a slot for the key gen.
  2008   NS_ASSERTION(slot, "There was no slot selected for key generation");
  2009   if (slot)
  2010     PK11_FreeSlot(slot);
  2012   char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
  2013                                                  const_cast<char*>(aReqDN.get()),
  2014                                                  const_cast<char*>(aRegToken.get()),
  2015                                                  const_cast<char*>(aAuthenticator.get()),
  2016                                                  escrowCert);
  2017 #ifdef DEBUG_javi
  2018   printf ("Created the folloing CRMF request:\n%s\n", encodedRequest);
  2019 #endif
  2020   if (!encodedRequest) {
  2021     nsFreeKeyPairInfo(keyids, numRequests);
  2022     aRv.Throw(NS_ERROR_FAILURE);
  2023     return nullptr;
  2025   CRMFObject* newObject = new CRMFObject();
  2026   newObject->SetCRMFRequest(encodedRequest);
  2027   PORT_Free(encodedRequest);
  2028   nsFreeKeyPairInfo(keyids, numRequests);
  2030   // Post an event on the UI queue so that the JS gets called after
  2031   // we return control to the JS layer.  Why do we have to this?
  2032   // Because when this API was implemented for PSM 1.x w/ Communicator,
  2033   // the only way to make this method work was to have a callback
  2034   // in the JS layer that got called after key generation had happened.
  2035   // So for backwards compatibility, we return control and then just post
  2036   // an event to call the JS the script provides as the code to execute
  2037   // when the request has been generated.
  2038   //
  2040   nsCOMPtr<nsIScriptSecurityManager> secMan =
  2041     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
  2042   if (MOZ_UNLIKELY(!secMan)) {
  2043     aRv.Throw(NS_ERROR_UNEXPECTED);
  2044     return nullptr;
  2047   nsCOMPtr<nsIPrincipal> principals;
  2048   nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals));
  2049   if (NS_FAILED(nrv)) {
  2050     aRv.Throw(nrv);
  2051     return nullptr;
  2053   if (MOZ_UNLIKELY(!principals)) {
  2054     aRv.Throw(NS_ERROR_UNEXPECTED);
  2055     return nullptr;
  2058   nsCryptoRunArgs *args = new nsCryptoRunArgs(aContext);
  2060   args->m_kungFuDeathGrip = GetISupportsFromContext(aContext);
  2061   args->m_scope      = JS_GetParent(script_obj);
  2062   if (!aJsCallback.IsVoid()) {
  2063     args->m_jsCallback = aJsCallback;
  2065   args->m_principals = principals;
  2067   nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args);
  2069   rv = NS_DispatchToMainThread(cryptoRunnable);
  2070   if (NS_FAILED(rv)) {
  2071     aRv.Throw(rv);
  2072     delete cryptoRunnable;
  2075   return newObject;
  2078 // Reminder that we inherit the memory passed into us here.
  2079 // An implementation to let us back up certs as an event.
  2080 nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts,
  2081                              nsIPK11Token *token)
  2083   mCertArr  = certArr;
  2084   mNumCerts = numCerts;
  2085   mToken = token;
  2088 nsP12Runnable::~nsP12Runnable()
  2090   int32_t i;
  2091   for (i=0; i<mNumCerts; i++) {
  2092       NS_IF_RELEASE(mCertArr[i]);
  2094   delete []mCertArr;
  2098 //Implementation that backs cert(s) into a PKCS12 file
  2099 NS_IMETHODIMP
  2100 nsP12Runnable::Run()
  2102   NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  2104   NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
  2106   nsNSSShutDownPreventionLock locker;
  2107   NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
  2109   nsString final;
  2110   nsString temp;
  2111   nsresult rv;
  2113   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2114   if (NS_FAILED(rv))
  2115     return rv;
  2117   //Build up the message that let's the user know we're trying to 
  2118   //make PKCS12 backups of the new certs.
  2119   nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
  2120   final.Append(MOZ_UTF16("\n\n"));
  2121   nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
  2122   final.Append(temp.get());
  2123   final.Append(MOZ_UTF16("\n\n"));
  2125   nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
  2127   final.Append(temp.get());
  2128   nsNSSComponent::ShowAlertWithConstructedString(final);
  2130   nsCOMPtr<nsIFilePicker> filePicker = 
  2131                         do_CreateInstance("@mozilla.org/filepicker;1", &rv);
  2132   if (!filePicker) {
  2133     NS_ERROR("Could not create a file picker when backing up certs.");
  2134     return rv;
  2137   nsCOMPtr<nsIWindowWatcher> wwatch =
  2138     (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
  2139   NS_ENSURE_SUCCESS(rv, rv);
  2141   nsCOMPtr<nsIDOMWindow> window;
  2142   wwatch->GetActiveWindow(getter_AddRefs(window));
  2144   nsString filePickMessage;
  2145   nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
  2146                                       filePickMessage);
  2147   rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
  2148   NS_ENSURE_SUCCESS(rv, rv);
  2150   filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
  2151                            NS_LITERAL_STRING("*.p12"));
  2152   filePicker->AppendFilters(nsIFilePicker::filterAll);
  2154   int16_t dialogReturn;
  2155   filePicker->Show(&dialogReturn);
  2156   if (dialogReturn == nsIFilePicker::returnCancel)
  2157     return NS_OK;  //User canceled.  It'd be nice if they couldn't, 
  2158                    //but oh well.
  2160   nsCOMPtr<nsIFile> localFile;
  2161   rv = filePicker->GetFile(getter_AddRefs(localFile));
  2162   if (NS_FAILED(rv))
  2163     return NS_ERROR_FAILURE;
  2165   nsPKCS12Blob p12Cxt;
  2167   p12Cxt.SetToken(mToken);
  2168   p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
  2169   return NS_OK;
  2172 nsCryptoRunArgs::nsCryptoRunArgs(JSContext *cx) : m_cx(cx), m_scope(cx) {}
  2174 nsCryptoRunArgs::~nsCryptoRunArgs() {}
  2176 nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
  2178   nsNSSShutDownPreventionLock locker;
  2179   NS_ASSERTION(args,"Passed nullptr to nsCryptoRunnable constructor.");
  2180   m_args = args;
  2181   NS_IF_ADDREF(m_args);
  2184 nsCryptoRunnable::~nsCryptoRunnable()
  2186   nsNSSShutDownPreventionLock locker;
  2187   NS_IF_RELEASE(m_args);
  2190 //Implementation that runs the callback passed to 
  2191 //crypto.generateCRMFRequest as an event.
  2192 NS_IMETHODIMP
  2193 nsCryptoRunnable::Run()
  2195   nsNSSShutDownPreventionLock locker;
  2196   AutoPushJSContext cx(m_args->m_cx);
  2197   JSAutoRequest ar(cx);
  2198   JS::Rooted<JSObject*> scope(cx, m_args->m_scope);
  2199   JSAutoCompartment ac(cx, scope);
  2201   bool ok =
  2202     JS_EvaluateScript(cx, scope, m_args->m_jsCallback,
  2203                       strlen(m_args->m_jsCallback), nullptr, 0);
  2204   return ok ? NS_OK : NS_ERROR_FAILURE;
  2207 //Quick helper function to check if a newly issued cert
  2208 //already exists in the user's database.
  2209 static bool
  2210 nsCertAlreadyExists(SECItem *derCert)
  2212   CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
  2213   bool retVal = false;
  2215   mozilla::pkix::ScopedCERTCertificate cert(
  2216     CERT_FindCertByDERCert(handle, derCert));
  2217   if (cert) {
  2218     if (cert->isperm && !cert->nickname && !cert->emailAddr) {
  2219       //If the cert doesn't have a nickname or email addr, it is
  2220       //bogus cruft, so delete it.
  2221       SEC_DeletePermCertificate(cert.get());
  2222     } else if (cert->isperm) {
  2223       retVal = true;
  2226   return retVal;
  2229 static int32_t
  2230 nsCertListCount(CERTCertList *certList)
  2232   int32_t numCerts = 0;
  2233   CERTCertListNode *node;
  2235   node = CERT_LIST_HEAD(certList);
  2236   while (!CERT_LIST_END(node, certList)) {
  2237     numCerts++;
  2238     node = CERT_LIST_NEXT(node);
  2240   return numCerts;
  2243 //Import user certificates that arrive as a CMMF base64 encoded
  2244 //string.
  2245 void
  2246 nsCrypto::ImportUserCertificates(const nsAString& aNickname,
  2247                                  const nsAString& aCmmfResponse,
  2248                                  bool aDoForcedBackup,
  2249                                  nsAString& aReturn,
  2250                                  ErrorResult& aRv)
  2252   nsNSSShutDownPreventionLock locker;
  2253   char *nickname=nullptr, *cmmfResponse=nullptr;
  2254   CMMFCertRepContent *certRepContent = nullptr;
  2255   int numResponses = 0;
  2256   nsIX509Cert **certArr = nullptr;
  2257   int i;
  2258   CMMFCertResponse *currResponse;
  2259   CMMFPKIStatus reqStatus;
  2260   CERTCertificate *currCert;
  2261   PK11SlotInfo *slot;
  2262   nsAutoCString localNick;
  2263   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  2264   nsresult rv = NS_OK;
  2265   nsCOMPtr<nsIPK11Token> token;
  2267   nickname = ToNewCString(aNickname);
  2268   cmmfResponse = ToNewCString(aCmmfResponse);
  2269   if (nsCRT::strcmp("null", nickname) == 0) {
  2270     nsMemory::Free(nickname);
  2271     nickname = nullptr;
  2274   SECItem cmmfDer = {siBuffer, nullptr, 0};
  2275   SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
  2277   if (srv != SECSuccess) {
  2278     rv = NS_ERROR_FAILURE;
  2279     goto loser;
  2282   certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
  2283                                                     (const char*)cmmfDer.data,
  2284                                                     cmmfDer.len);
  2285   if (!certRepContent) {
  2286     rv = NS_ERROR_FAILURE;
  2287     goto loser;
  2290   numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
  2292   if (aDoForcedBackup) {
  2293     //We've been asked to force the user to back up these
  2294     //certificates.  Let's keep an array of them around which
  2295     //we pass along to the nsP12Runnable to use.
  2296     certArr = new nsIX509Cert*[numResponses];
  2297     // If this is nullptr, chances are we're gonna fail really
  2298     // soon, but let's try to keep going just in case.
  2299     if (!certArr)
  2300       aDoForcedBackup = false;
  2302     memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
  2304   for (i=0; i<numResponses; i++) {
  2305     currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
  2306     if (!currResponse) {
  2307       rv = NS_ERROR_FAILURE;
  2308       goto loser;
  2310     reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
  2311     if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
  2312       // The CA didn't give us the cert we requested.
  2313       rv = NS_ERROR_FAILURE;
  2314       goto loser;
  2316     currCert = CMMF_CertResponseGetCertificate(currResponse, 
  2317                                                CERT_GetDefaultCertDB());
  2318     if (!currCert) {
  2319       rv = NS_ERROR_FAILURE;
  2320       goto loser;
  2323     if (nsCertAlreadyExists(&currCert->derCert)) {
  2324       if (aDoForcedBackup) {
  2325         certArr[i] = nsNSSCertificate::Create(currCert);
  2326         if (!certArr[i])
  2327           goto loser;
  2328         NS_ADDREF(certArr[i]);
  2330       CERT_DestroyCertificate(currCert);
  2331       CMMF_DestroyCertResponse(currResponse);
  2332       continue;
  2334     // Let's figure out which nickname to give the cert.  If 
  2335     // a certificate with the same subject name already exists,
  2336     // then just use that one, otherwise, get the default nickname.
  2337     if (currCert->nickname) {
  2338       localNick = currCert->nickname;
  2340     else if (!nickname || nickname[0] == '\0') {
  2341       nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick, locker);
  2342     } else {
  2343       //This is the case where we're getting a brand new
  2344       //cert that doesn't have the same subjectName as a cert
  2345       //that already exists in our db and the CA page has 
  2346       //designated a nickname to use for the newly issued cert.
  2347       localNick = nickname;
  2350       char *cast_const_away = const_cast<char*>(localNick.get());
  2351       slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
  2353     if (!slot) {
  2354       rv = NS_ERROR_FAILURE;
  2355       goto loser;
  2357     if (aDoForcedBackup) {
  2358       certArr[i] = nsNSSCertificate::Create(currCert);
  2359       if (!certArr[i])
  2360         goto loser;
  2361       NS_ADDREF(certArr[i]);
  2363     CERT_DestroyCertificate(currCert);
  2365     if (!token)
  2366       token = new nsPK11Token(slot);
  2368     PK11_FreeSlot(slot);
  2369     CMMF_DestroyCertResponse(currResponse);
  2371   //Let the loser: label take care of freeing up our reference to
  2372   //nickname (This way we don't free it twice and avoid crashing.
  2373   //That would be a good thing.
  2375   //Import the root chain into the cert db.
  2377   mozilla::pkix::ScopedCERTCertList
  2378     caPubs(CMMF_CertRepContentGetCAPubs(certRepContent));
  2379   if (caPubs) {
  2380     int32_t numCAs = nsCertListCount(caPubs.get());
  2382     NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
  2383     if (numCAs > 0) {
  2384       CERTCertListNode *node;
  2385       SECItem *derCerts;
  2387       derCerts = static_cast<SECItem*>
  2388                             (nsMemory::Alloc(sizeof(SECItem)*numCAs));
  2389       if (!derCerts) {
  2390         rv = NS_ERROR_OUT_OF_MEMORY;
  2391         goto loser;
  2393       for (node = CERT_LIST_HEAD(caPubs), i=0; 
  2394            !CERT_LIST_END(node, caPubs);
  2395            node = CERT_LIST_NEXT(node), i++) {
  2396         derCerts[i] = node->cert->derCert;
  2398       nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx, locker);
  2399       nsMemory::Free(derCerts);
  2404   if (aDoForcedBackup) {
  2405     // I can't pop up a file picker from the depths of JavaScript,
  2406     // so I'll just post an event on the UI queue to do the backups
  2407     // later.
  2408     nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
  2409                                                           token);
  2410     if (!p12Runnable) {
  2411       rv = NS_ERROR_FAILURE;
  2412       goto loser;
  2415     // null out the certArr pointer which has now been inherited by
  2416     // the nsP12Runnable instance so that we don't free up the
  2417     // memory on the way out.
  2418     certArr = nullptr;
  2420     rv = NS_DispatchToMainThread(p12Runnable);
  2421     if (NS_FAILED(rv))
  2422       goto loser;
  2425  loser:
  2426   if (certArr) {
  2427     for (i=0; i<numResponses; i++) {
  2428       NS_IF_RELEASE(certArr[i]);
  2430     delete []certArr;
  2432   aReturn.Assign(EmptyString());
  2433   if (nickname) {
  2434     NS_Free(nickname);
  2436   if (cmmfResponse) {
  2437     NS_Free(cmmfResponse);
  2439   if (certRepContent) {
  2440     CMMF_DestroyCertRepContent(certRepContent);
  2443   if (NS_FAILED(rv)) {
  2444     aRv.Throw(rv);
  2448 static void
  2449 GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
  2451   // Get the script context.
  2452   nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
  2453   if (!scriptContext) {
  2454     return;
  2457   nsCOMPtr<nsIDOMWindow> domWindow = 
  2458     do_QueryInterface(scriptContext->GetGlobalObject());
  2459   if (!domWindow) {
  2460     return;
  2463   nsCOMPtr<nsIDOMDocument> domDocument;
  2464   domWindow->GetDocument(getter_AddRefs(domDocument));
  2465   if (!domDocument) {
  2466     return;
  2469   CallQueryInterface(domDocument, aDocument);
  2471   return;
  2474 void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
  2476   ((nsCString*)arg)->Append(buf, len);
  2479 void
  2480 nsCrypto::SignText(JSContext* aContext,
  2481                    const nsAString& aStringToSign,
  2482                    const nsAString& aCaOption,
  2483                    const Sequence<nsCString>& aArgs,
  2484                    nsAString& aReturn)
  2486   // XXX This code should return error codes, but we're keeping this
  2487   //     backwards compatible with NS4.x and so we can't throw exceptions.
  2488   NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
  2490   aReturn.Truncate();
  2492   uint32_t argc = aArgs.Length();
  2494   if (!aCaOption.EqualsLiteral("auto") &&
  2495       !aCaOption.EqualsLiteral("ask")) {
  2496     NS_WARNING("caOption argument must be ask or auto");
  2497     aReturn.Append(internalError);
  2499     return;
  2502   // It was decided to always behave as if "ask" were specified.
  2503   // XXX Should we warn in the JS Console for auto?
  2505   nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
  2506   if (!uiContext) {
  2507     aReturn.Append(internalError);
  2509     return;
  2512   bool bestOnly = true;
  2513   bool validOnly = true;
  2514   CERTCertList* certList =
  2515     CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
  2516                               bestOnly, validOnly, uiContext);
  2518   uint32_t numCAs = argc;
  2519   if (numCAs > 0) {
  2520     nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
  2521     if (!caNames) {
  2522       aReturn.Append(internalError);
  2523       return;
  2526     uint32_t i;
  2527     for (i = 0; i < numCAs; ++i)
  2528       caNames[i] = const_cast<char*>(aArgs[i].get());
  2530     if (certList &&
  2531         CERT_FilterCertListByCANames(certList, numCAs, caNames,
  2532                                      certUsageEmailSigner) != SECSuccess) {
  2533       aReturn.Append(internalError);
  2535       return;
  2539   if (!certList || CERT_LIST_EMPTY(certList)) {
  2540     aReturn.AppendLiteral("error:noMatchingCert");
  2542     return;
  2545   nsCOMPtr<nsIFormSigningDialog> fsd =
  2546     do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
  2547   if (!fsd) {
  2548     aReturn.Append(internalError);
  2550     return;
  2553   nsCOMPtr<nsIDocument> document;
  2554   GetDocumentFromContext(aContext, getter_AddRefs(document));
  2555   if (!document) {
  2556     aReturn.Append(internalError);
  2558     return;
  2561   // Get the hostname from the URL of the document.
  2562   nsIURI* uri = document->GetDocumentURI();
  2563   if (!uri) {
  2564     aReturn.Append(internalError);
  2566     return;
  2569   nsresult rv;
  2571   nsCString host;
  2572   rv = uri->GetHost(host);
  2573   if (NS_FAILED(rv)) {
  2574     aReturn.Append(internalError);
  2576     return;
  2579   int32_t numberOfCerts = 0;
  2580   CERTCertListNode* node;
  2581   for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  2582        node = CERT_LIST_NEXT(node)) {
  2583     ++numberOfCerts;
  2586   ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList));
  2588   if (!nicknames) {
  2589     aReturn.Append(internalError);
  2591     return;
  2594   NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
  2595                "nicknames->numnicknames != numberOfCerts");
  2597   nsAutoArrayPtr<char16_t*> certNicknameList(new char16_t*[nicknames->numnicknames * 2]);
  2598   if (!certNicknameList) {
  2599     aReturn.Append(internalError);
  2601     return;
  2604   char16_t** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
  2606   int32_t certsToUse;
  2607   for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
  2608        !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
  2609        node = CERT_LIST_NEXT(node)) {
  2610     RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
  2611     if (tempCert) {
  2612       nsAutoString nickWithSerial, details;
  2613       rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
  2614                                      nickWithSerial, details);
  2615       if (NS_SUCCEEDED(rv)) {
  2616         certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
  2617         if (certNicknameList[certsToUse]) {
  2618           certDetailsList[certsToUse] = ToNewUnicode(details);
  2619           if (!certDetailsList[certsToUse]) {
  2620             nsMemory::Free(certNicknameList[certsToUse]);
  2621             continue;
  2623           ++certsToUse;
  2629   if (certsToUse == 0) {
  2630     aReturn.Append(internalError);
  2632     return;
  2635   NS_ConvertUTF8toUTF16 utf16Host(host);
  2637   CERTCertificate *signingCert = nullptr;
  2638   bool tryAgain, canceled;
  2639   nsAutoString password;
  2640   do {
  2641     // Throw up the form signing confirmation dialog and get back the index
  2642     // of the selected cert.
  2643     int32_t selectedIndex = -1;
  2644     rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
  2645                               const_cast<const char16_t**>(certNicknameList.get()),
  2646                               const_cast<const char16_t**>(certDetailsList),
  2647                               certsToUse, &selectedIndex, password,
  2648                               &canceled);
  2649     if (NS_FAILED(rv) || canceled) {
  2650       break; // out of tryAgain loop
  2653     int32_t j = 0;
  2654     for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  2655          node = CERT_LIST_NEXT(node)) {
  2656       if (j == selectedIndex) {
  2657         signingCert = CERT_DupCertificate(node->cert);
  2658         break; // out of cert list iteration loop
  2660       ++j;
  2663     if (!signingCert) {
  2664       rv = NS_ERROR_FAILURE;
  2665       break; // out of tryAgain loop
  2668     NS_ConvertUTF16toUTF8 pwUtf8(password);
  2670     tryAgain =
  2671       PK11_CheckUserPassword(signingCert->slot,
  2672                              const_cast<char *>(pwUtf8.get())) != SECSuccess;
  2673     // XXX we should show an error dialog before retrying
  2674   } while (tryAgain);
  2676   int32_t k;
  2677   for (k = 0; k < certsToUse; ++k) {
  2678     nsMemory::Free(certNicknameList[k]);
  2679     nsMemory::Free(certDetailsList[k]);
  2682   if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
  2683     aReturn.Append(internalError);
  2685     return;
  2688   if (canceled) {
  2689     aReturn.AppendLiteral("error:userCancel");
  2691     return;
  2694   SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
  2695   if (!privKey) {
  2696     aReturn.Append(internalError);
  2698     return;
  2701   nsAutoCString charset(document->GetDocumentCharacterSet());
  2703   // XXX Doing what nsFormSubmission::GetEncoder does (see
  2704   //     http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
  2705   if (charset.EqualsLiteral("ISO-8859-1")) {
  2706     charset.AssignLiteral("windows-1252");
  2709   nsCOMPtr<nsISaveAsCharset> encoder =
  2710     do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
  2711   if (encoder) {
  2712     rv = encoder->Init(charset.get(),
  2713                        (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
  2714                        nsISaveAsCharset::attr_FallbackDecimalNCR),
  2715                        0);
  2718   nsXPIDLCString buffer;
  2719   if (aStringToSign.Length() > 0) {
  2720     if (encoder && NS_SUCCEEDED(rv)) {
  2721       rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
  2722                             getter_Copies(buffer));
  2723       if (NS_FAILED(rv)) {
  2724         aReturn.Append(internalError);
  2726         return;
  2729     else {
  2730       AppendUTF16toUTF8(aStringToSign, buffer);
  2734   HASHContext *hc = HASH_Create(HASH_AlgSHA1);
  2735   if (!hc) {
  2736     aReturn.Append(internalError);
  2738     return;
  2741   unsigned char hash[SHA1_LENGTH];
  2743   SECItem digest;
  2744   digest.data = hash;
  2746   HASH_Begin(hc);
  2747   HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
  2748               buffer.Length());
  2749   HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
  2750   HASH_Destroy(hc);
  2752   nsCString p7;
  2753   SECStatus srv = SECFailure;
  2755   SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
  2756                                                        certUsageEmailSigner,
  2757                                                        nullptr, SEC_OID_SHA1,
  2758                                                        &digest, nullptr, uiContext);
  2759   if (ci) {
  2760     srv = SEC_PKCS7IncludeCertChain(ci, nullptr);
  2761     if (srv == SECSuccess) {
  2762       srv = SEC_PKCS7AddSigningTime(ci);
  2763       if (srv == SECSuccess) {
  2764         srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nullptr, nullptr,
  2765                               uiContext);
  2769     SEC_PKCS7DestroyContentInfo(ci);
  2772   if (srv != SECSuccess) {
  2773     aReturn.Append(internalError);
  2775     return;
  2778   SECItem binary_item;
  2779   binary_item.data = reinterpret_cast<unsigned char*>
  2780                                      (const_cast<char*>(p7.get()));
  2781   binary_item.len = p7.Length();
  2783   char *result = NSSBase64_EncodeItem(nullptr, nullptr, 0, &binary_item);
  2784   if (result) {
  2785     AppendASCIItoUTF16(result, aReturn);
  2787   else {
  2788     aReturn.Append(internalError);
  2791   PORT_Free(result);
  2793   return;
  2796 void
  2797 nsCrypto::Logout(ErrorResult& aRv)
  2799   NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  2801   nsresult rv;
  2802   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2803   if (NS_FAILED(rv)) {
  2804     aRv.Throw(rv);
  2805     return;
  2809     nsNSSShutDownPreventionLock locker;
  2810     PK11_LogoutAll();
  2811     SSL_ClearSessionCache();
  2814   rv = nssComponent->LogoutAuthenticatedPK11();
  2815   if (NS_FAILED(rv)) {
  2816     aRv.Throw(rv);
  2820 CRMFObject::CRMFObject()
  2822   MOZ_COUNT_CTOR(CRMFObject);
  2825 CRMFObject::~CRMFObject()
  2827   MOZ_COUNT_DTOR(CRMFObject);
  2830 JSObject*
  2831 CRMFObject::WrapObject(JSContext *aCx, bool* aTookOwnership)
  2833   return CRMFObjectBinding::Wrap(aCx, this, aTookOwnership);
  2836 void
  2837 CRMFObject::GetRequest(nsAString& aRequest)
  2839   aRequest.Assign(mBase64Request);
  2842 nsresult
  2843 CRMFObject::SetCRMFRequest(char *inRequest)
  2845   mBase64Request.AssignWithConversion(inRequest);  
  2846   return NS_OK;
  2849 #endif // MOZ_DISABLE_CRYPTOLEGACY
  2851 nsPkcs11::nsPkcs11()
  2855 nsPkcs11::~nsPkcs11()
  2859 //Delete a PKCS11 module from the user's profile.
  2860 NS_IMETHODIMP
  2861 nsPkcs11::DeleteModule(const nsAString& aModuleName)
  2863   NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  2865   nsNSSShutDownPreventionLock locker;
  2866   nsresult rv;
  2867   nsString errorMessage;
  2869   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2870   if (NS_FAILED(rv))
  2871     return rv;
  2873   if (aModuleName.IsEmpty()) {
  2874     return NS_ERROR_ILLEGAL_VALUE;
  2877   NS_ConvertUTF16toUTF8 modName(aModuleName);
  2878   int32_t modType;
  2879   SECStatus srv = SECMOD_DeleteModule(modName.get(), &modType);
  2880   if (srv == SECSuccess) {
  2881     SECMODModule *module = SECMOD_FindModule(modName.get());
  2882     if (module) {
  2883 #ifndef MOZ_DISABLE_CRYPTOLEGACY
  2884       nssComponent->ShutdownSmartCardThread(module);
  2885 #endif
  2886       SECMOD_DestroyModule(module);
  2888     rv = NS_OK;
  2889   } else {
  2890     rv = NS_ERROR_FAILURE;
  2892   return rv;
  2895 //Add a new PKCS11 module to the user's profile.
  2896 NS_IMETHODIMP
  2897 nsPkcs11::AddModule(const nsAString& aModuleName, 
  2898                     const nsAString& aLibraryFullPath, 
  2899                     int32_t aCryptoMechanismFlags, 
  2900                     int32_t aCipherFlags)
  2902   NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  2904   nsNSSShutDownPreventionLock locker;
  2905   nsresult rv;
  2906   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2908   NS_ConvertUTF16toUTF8 moduleName(aModuleName);
  2909   nsCString fullPath;
  2910   // NSS doesn't support Unicode path.  Use native charset
  2911   NS_CopyUnicodeToNative(aLibraryFullPath, fullPath);
  2912   uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
  2913   uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
  2914   SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(), 
  2915                                       mechFlags, cipherFlags);
  2916   if (srv == SECSuccess) {
  2917     SECMODModule *module = SECMOD_FindModule(moduleName.get());
  2918     if (module) {
  2919 #ifndef MOZ_DISABLE_CRYPTOLEGACY
  2920       nssComponent->LaunchSmartCardThread(module);
  2921 #endif
  2922       SECMOD_DestroyModule(module);
  2926   // The error message we report to the user depends directly on 
  2927   // what the return value for SEDMOD_AddNewModule is
  2928   switch (srv) {
  2929   case SECSuccess:
  2930     return NS_OK;
  2931   case SECFailure:
  2932     return NS_ERROR_FAILURE;
  2933   case -2:
  2934     return NS_ERROR_ILLEGAL_VALUE;
  2936   NS_ERROR("Bogus return value, this should never happen");
  2937   return NS_ERROR_FAILURE;

mercurial