LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsCrypto.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1315 0 0.0 %
Date: 2012-06-02 Functions: 112 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Javier Delgadillo <javi@netscape.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : #include "nsNSSComponent.h"
      40                 : #include "nsCrypto.h"
      41                 : #include "nsKeygenHandler.h"
      42                 : #include "nsKeygenThread.h"
      43                 : #include "nsNSSCertificate.h"
      44                 : #include "nsNSSCertificateDB.h"
      45                 : #include "nsPKCS12Blob.h"
      46                 : #include "nsPK11TokenDB.h"
      47                 : #include "nsThreadUtils.h"
      48                 : #include "nsIServiceManager.h"
      49                 : #include "nsIMemory.h"
      50                 : #include "nsAutoPtr.h"
      51                 : #include "nsAlgorithm.h"
      52                 : #include "nsCRT.h"
      53                 : #include "prprf.h"
      54                 : #include "prmem.h"
      55                 : #include "nsDOMCID.h"
      56                 : #include "nsIDOMWindow.h"
      57                 : #include "nsIDOMClassInfo.h"
      58                 : #include "nsIDOMDocument.h"
      59                 : #include "nsIDocument.h"
      60                 : #include "nsIScriptObjectPrincipal.h"
      61                 : #include "nsIScriptContext.h"
      62                 : #include "nsIScriptGlobalObject.h"
      63                 : #include "nsDOMJSUtils.h"
      64                 : #include "nsIXPConnect.h"
      65                 : #include "nsIRunnable.h"
      66                 : #include "nsIWindowWatcher.h"
      67                 : #include "nsIPrompt.h"
      68                 : #include "nsIFilePicker.h"
      69                 : #include "nsJSPrincipals.h"
      70                 : #include "nsIPrincipal.h"
      71                 : #include "nsIScriptSecurityManager.h"
      72                 : #include "nsXPIDLString.h"
      73                 : #include "nsIGenKeypairInfoDlg.h"
      74                 : #include "nsIDOMCryptoDialogs.h"
      75                 : #include "nsIFormSigningDialog.h"
      76                 : #include "nsIJSContextStack.h"
      77                 : #include "jsapi.h"
      78                 : #include "jsdbgapi.h"
      79                 : #include <ctype.h>
      80                 : #include "nsReadableUtils.h"
      81                 : #include "pk11func.h"
      82                 : #include "keyhi.h"
      83                 : #include "cryptohi.h"
      84                 : #include "seccomon.h"
      85                 : #include "secerr.h"
      86                 : #include "sechash.h"
      87                 : extern "C" {
      88                 : #include "crmf.h"
      89                 : #include "pk11pqg.h"
      90                 : }
      91                 : #include "cmmf.h"
      92                 : #include "nssb64.h"
      93                 : #include "base64.h"
      94                 : #include "cert.h"
      95                 : #include "certdb.h"
      96                 : #include "secmod.h"
      97                 : #include "nsISaveAsCharset.h"
      98                 : 
      99                 : #include "ssl.h" // For SSL_ClearSessionCache
     100                 : 
     101                 : #include "nsNSSCleaner.h"
     102               0 : NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
     103               0 : NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
     104               0 : NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
     105               0 : NSSCleanupAutoPtrClass(PK11SymKey, PK11_FreeSymKey)
     106               0 : NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
     107               0 : NSSCleanupAutoPtrClass_WithParam(SECItem, SECITEM_FreeItem, TrueParam, true)
     108                 : 
     109                 : #include "nsNSSShutDown.h"
     110                 : #include "nsNSSCertHelper.h"
     111                 : 
     112                 : /*
     113                 :  * These are the most common error strings that are returned
     114                 :  * by the JavaScript methods in case of error.
     115                 :  */
     116                 : 
     117                 : #define JS_ERROR       "error:"
     118                 : #define JS_ERROR_INTERNAL  JS_ERROR"internalError"
     119                 : 
     120                 : #undef REPORT_INCORRECT_NUM_ARGS
     121                 : 
     122                 : #define JS_OK_ADD_MOD                      3
     123                 : #define JS_OK_DEL_EXTERNAL_MOD             2
     124                 : #define JS_OK_DEL_INTERNAL_MOD             1
     125                 : 
     126                 : #define JS_ERR_INTERNAL                   -1
     127                 : #define JS_ERR_USER_CANCEL_ACTION         -2
     128                 : #define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
     129                 : #define JS_ERR_DEL_MOD                    -4
     130                 : #define JS_ERR_ADD_MOD                    -5
     131                 : #define JS_ERR_BAD_MODULE_NAME            -6
     132                 : #define JS_ERR_BAD_DLL_NAME               -7
     133                 : #define JS_ERR_BAD_MECHANISM_FLAGS        -8
     134                 : #define JS_ERR_BAD_CIPHER_ENABLE_FLAGS    -9
     135                 : #define JS_ERR_ADD_DUPLICATE_MOD          -10
     136                 : 
     137                 : /*
     138                 :  * This structure is used to store information for one key generation.
     139                 :  * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
     140                 :  * stores one of these structures for every key generation that happens.
     141                 :  * The information stored in this structure is then used to set some
     142                 :  * values in the CRMF request.
     143                 :  */
     144                 : typedef enum {
     145                 :   rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
     146                 :   ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
     147                 :   dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
     148                 : } nsKeyGenType;
     149                 : 
     150               0 : bool isECKeyGenType(nsKeyGenType kgt)
     151                 : {
     152               0 :   switch (kgt)
     153                 :   {
     154                 :     case ecEnc:
     155                 :     case ecDualUse:
     156                 :     case ecSign:
     157                 :     case ecNonrepudiation:
     158                 :     case ecSignNonrepudiation:
     159               0 :       return true;
     160                 :     
     161                 :     default:
     162                 :       break;
     163                 :   }
     164                 : 
     165               0 :   return false;
     166                 : }
     167                 : 
     168                 : typedef struct nsKeyPairInfoStr {
     169                 :   SECKEYPublicKey  *pubKey;     /* The putlic key associated with gen'd 
     170                 :                                    priv key. */
     171                 :   SECKEYPrivateKey *privKey;    /* The private key we generated */ 
     172                 :   nsKeyGenType      keyGenType; /* What type of key gen are we doing.*/
     173                 : 
     174                 :   CERTCertificate *ecPopCert;
     175                 :                    /* null: use signing for pop
     176                 :                       other than null: a cert that defines EC keygen params
     177                 :                                        and will be used for dhMac PoP. */
     178                 : 
     179                 :   SECKEYPublicKey  *ecPopPubKey;
     180                 :                    /* extracted public key from ecPopCert */
     181                 : } nsKeyPairInfo;
     182                 : 
     183                 : 
     184                 : //This class is just used to pass arguments
     185                 : //to the nsCryptoRunnable event.
     186                 : class nsCryptoRunArgs : public nsISupports {
     187                 : public:
     188                 :   nsCryptoRunArgs();
     189                 :   virtual ~nsCryptoRunArgs();
     190                 :   nsCOMPtr<nsISupports> m_kungFuDeathGrip;
     191                 :   JSContext *m_cx;
     192                 :   JSObject  *m_scope;
     193                 :   nsCOMPtr<nsIPrincipal> m_principals;
     194                 :   nsXPIDLCString m_jsCallback;
     195                 :   NS_DECL_ISUPPORTS
     196                 : };
     197                 : 
     198                 : //This class is used to run the callback code
     199                 : //passed to crypto.generateCRMFRequest
     200                 : //We have to do that for backwards compatibility
     201                 : //reasons w/ PSM 1.x and Communciator 4.x
     202                 : class nsCryptoRunnable : public nsIRunnable {
     203                 : public:
     204                 :   nsCryptoRunnable(nsCryptoRunArgs *args);
     205                 :   virtual ~nsCryptoRunnable();
     206                 : 
     207                 :   NS_IMETHOD Run ();
     208                 :   NS_DECL_ISUPPORTS
     209                 : private:
     210                 :   nsCryptoRunArgs *m_args;
     211                 : };
     212                 : 
     213                 : 
     214                 : //We're going to inherit the memory passed
     215                 : //into us.
     216                 : //This class backs up an array of certificates
     217                 : //as an event.
     218                 : class nsP12Runnable : public nsIRunnable {
     219                 : public:
     220                 :   nsP12Runnable(nsIX509Cert **certArr, PRInt32 numCerts, nsIPK11Token *token);
     221                 :   virtual ~nsP12Runnable();
     222                 : 
     223                 :   NS_IMETHOD Run();
     224                 :   NS_DECL_ISUPPORTS
     225                 : private:
     226                 :   nsCOMPtr<nsIPK11Token> mToken;
     227                 :   nsIX509Cert **mCertArr;
     228                 :   PRInt32       mNumCerts;
     229                 : };
     230                 : 
     231                 : // QueryInterface implementation for nsCrypto
     232               0 : NS_INTERFACE_MAP_BEGIN(nsCrypto)
     233               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
     234               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     235               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Crypto)
     236               0 : NS_INTERFACE_MAP_END
     237                 : 
     238               0 : NS_IMPL_ADDREF(nsCrypto)
     239               0 : NS_IMPL_RELEASE(nsCrypto)
     240                 : 
     241                 : // QueryInterface implementation for nsCRMFObject
     242               0 : NS_INTERFACE_MAP_BEGIN(nsCRMFObject)
     243               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMCRMFObject)
     244               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     245               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CRMFObject)
     246               0 : NS_INTERFACE_MAP_END
     247                 : 
     248               0 : NS_IMPL_ADDREF(nsCRMFObject)
     249               0 : NS_IMPL_RELEASE(nsCRMFObject)
     250                 : 
     251                 : // QueryInterface implementation for nsPkcs11
     252               0 : NS_INTERFACE_MAP_BEGIN(nsPkcs11)
     253               0 :   NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
     254               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     255               0 : NS_INTERFACE_MAP_END
     256                 : 
     257               0 : NS_IMPL_ADDREF(nsPkcs11)
     258               0 : NS_IMPL_RELEASE(nsPkcs11)
     259                 : 
     260                 : // ISupports implementation for nsCryptoRunnable
     261               0 : NS_IMPL_ISUPPORTS1(nsCryptoRunnable, nsIRunnable)
     262                 : 
     263                 : // ISupports implementation for nsP12Runnable
     264               0 : NS_IMPL_ISUPPORTS1(nsP12Runnable, nsIRunnable)
     265                 : 
     266                 : // ISupports implementation for nsCryptoRunArgs
     267               0 : NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
     268                 : 
     269                 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     270                 : 
     271               0 : nsCrypto::nsCrypto() :
     272               0 :   mEnableSmartCardEvents(false)
     273                 : {
     274               0 : }
     275                 : 
     276               0 : nsCrypto::~nsCrypto()
     277                 : {
     278               0 : }
     279                 : 
     280                 : NS_IMETHODIMP
     281               0 : nsCrypto::SetEnableSmartCardEvents(bool aEnable)
     282                 : {
     283               0 :   nsresult rv = NS_OK;
     284                 : 
     285                 :   // this has the side effect of starting the nssComponent (and initializing
     286                 :   // NSS) even if it isn't already going. Starting the nssComponent is a 
     287                 :   // prerequisite for getting smartCard events.
     288               0 :   if (aEnable) {
     289               0 :     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
     290                 :   }
     291                 : 
     292               0 :   if (NS_FAILED(rv)) {
     293               0 :     return rv;
     294                 :   }
     295                 : 
     296               0 :   mEnableSmartCardEvents = aEnable;
     297               0 :   return NS_OK;
     298                 : }
     299                 : 
     300                 : NS_IMETHODIMP
     301               0 : nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
     302                 : {
     303               0 :   *aEnable = mEnableSmartCardEvents;
     304               0 :   return NS_OK;
     305                 : }
     306                 : 
     307                 : //A quick function to let us know if the key we're trying to generate
     308                 : //can be escrowed.
     309                 : static bool
     310               0 : ns_can_escrow(nsKeyGenType keyGenType)
     311                 : {
     312                 :   /* For now, we only escrow rsa-encryption and ec-encryption keys. */
     313               0 :   return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
     314                 : }
     315                 : 
     316                 : //Retrieve crypto.version so that callers know what
     317                 : //version of PSM this is.
     318                 : NS_IMETHODIMP
     319               0 : nsCrypto::GetVersion(nsAString& aVersion)
     320                 : {
     321               0 :   aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING).get());
     322               0 :   return NS_OK;
     323                 : }
     324                 : 
     325                 : /*
     326                 :  * Given an nsKeyGenType, return the PKCS11 mechanism that will
     327                 :  * perform the correct key generation.
     328                 :  */
     329                 : static PRUint32
     330               0 : cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
     331                 : {
     332                 :   PRUint32 retMech;
     333                 : 
     334               0 :   switch (keyGenType) {
     335                 :   case rsaEnc:
     336                 :   case rsaDualUse:
     337                 :   case rsaSign:
     338                 :   case rsaNonrepudiation:
     339                 :   case rsaSignNonrepudiation:
     340               0 :     retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
     341               0 :     break;
     342                 :   case ecEnc:
     343                 :   case ecDualUse:
     344                 :   case ecSign:
     345                 :   case ecNonrepudiation:
     346                 :   case ecSignNonrepudiation:
     347               0 :     retMech = CKM_EC_KEY_PAIR_GEN;
     348               0 :     break;
     349                 :   case dhEx:
     350               0 :     retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
     351               0 :     break;
     352                 :   case dsaSign:
     353                 :   case dsaSignNonrepudiation:
     354                 :   case dsaNonrepudiation:
     355               0 :     retMech = CKM_DSA_KEY_PAIR_GEN;
     356               0 :     break;
     357                 :   default:
     358               0 :     retMech = CKM_INVALID_MECHANISM;
     359                 :   }
     360               0 :   return retMech;
     361                 : }
     362                 : 
     363                 : /*
     364                 :  * This function converts a string read through JavaScript parameters
     365                 :  * and translates it to the internal enumeration representing the
     366                 :  * key gen type.
     367                 :  */
     368                 : static nsKeyGenType
     369               0 : cryptojs_interpret_key_gen_type(char *keyAlg)
     370                 : {
     371                 :   char *end;
     372               0 :   if (keyAlg == nsnull) {
     373               0 :     return invalidKeyGen;
     374                 :   }
     375                 :   /* First let's remove all leading and trailing white space */
     376               0 :   while (isspace(keyAlg[0])) keyAlg++;
     377               0 :   end = strchr(keyAlg, '\0');
     378               0 :   if (end == nsnull) {
     379               0 :     return invalidKeyGen;
     380                 :   }
     381               0 :   end--;
     382               0 :   while (isspace(*end)) end--;
     383               0 :   end[1] = '\0';
     384               0 :   if (strcmp(keyAlg, "rsa-ex") == 0) {
     385               0 :     return rsaEnc;
     386               0 :   } else if (strcmp(keyAlg, "rsa-dual-use") == 0) {
     387               0 :     return rsaDualUse;
     388               0 :   } else if (strcmp(keyAlg, "rsa-sign") == 0) {
     389               0 :     return rsaSign;
     390               0 :   } else if (strcmp(keyAlg, "rsa-sign-nonrepudiation") == 0) {
     391               0 :     return rsaSignNonrepudiation;
     392               0 :   } else if (strcmp(keyAlg, "rsa-nonrepudiation") == 0) {
     393               0 :     return rsaNonrepudiation;
     394               0 :   } else if (strcmp(keyAlg, "ec-ex") == 0) {
     395               0 :     return ecEnc;
     396               0 :   } else if (strcmp(keyAlg, "ec-dual-use") == 0) {
     397               0 :     return ecDualUse;
     398               0 :   } else if (strcmp(keyAlg, "ec-sign") == 0) {
     399               0 :     return ecSign;
     400               0 :   } else if (strcmp(keyAlg, "ec-sign-nonrepudiation") == 0) {
     401               0 :     return ecSignNonrepudiation;
     402               0 :   } else if (strcmp(keyAlg, "ec-nonrepudiation") == 0) {
     403               0 :     return ecNonrepudiation;
     404               0 :   } else if (strcmp(keyAlg, "dsa-sign-nonrepudiation") == 0) {
     405               0 :     return dsaSignNonrepudiation;
     406               0 :   } else if (strcmp(keyAlg, "dsa-sign") ==0 ){
     407               0 :     return dsaSign;
     408               0 :   } else if (strcmp(keyAlg, "dsa-nonrepudiation") == 0) {
     409               0 :     return dsaNonrepudiation;
     410               0 :   } else if (strcmp(keyAlg, "dh-ex") == 0) {
     411               0 :     return dhEx;
     412                 :   }
     413               0 :   return invalidKeyGen;
     414                 : }
     415                 : 
     416                 : /* 
     417                 :  * input: null terminated char* pointing to (the remainder of) an
     418                 :  * EC key param string.
     419                 :  *
     420                 :  * bool return value, false means "no more name=value pair found",
     421                 :  *                    true means "found, see out params"
     422                 :  * 
     423                 :  * out param name: char * pointing to name (not zero terminated)
     424                 :  * out param name_len: length of found name
     425                 :  * out param value: char * pointing to value (not zero terminated)
     426                 :  * out param value_len: length of found value
     427                 :  * out param next_pair: to be used for a follow up call to this function
     428                 :  */
     429                 : 
     430               0 : bool getNextNameValueFromECKeygenParamString(char *input,
     431                 :                                                char *&name,
     432                 :                                                int &name_len,
     433                 :                                                char *&value,
     434                 :                                                int &value_len,
     435                 :                                                char *&next_call)
     436                 : {
     437               0 :   if (!input || !*input)
     438               0 :     return false;
     439                 : 
     440                 :   // we allow leading ; and leading space in front of each name value pair
     441                 : 
     442               0 :   while (*input && *input == ';')
     443               0 :     ++input;
     444                 : 
     445               0 :   while (*input && *input == ' ')
     446               0 :     ++input;
     447                 : 
     448               0 :   name = input;
     449                 : 
     450               0 :   while (*input && *input != '=')
     451               0 :     ++input;
     452                 : 
     453               0 :   if (*input != '=')
     454               0 :     return false;
     455                 : 
     456               0 :   name_len = input - name;
     457               0 :   ++input;
     458                 : 
     459               0 :   value = input;
     460                 : 
     461               0 :   while (*input && *input != ';')
     462               0 :     ++input;
     463                 : 
     464               0 :   value_len = input - value;
     465               0 :   next_call = input;
     466                 : 
     467               0 :   return true;
     468                 : }
     469                 : 
     470                 : //Take the string passed into us via crypto.generateCRMFRequest
     471                 : //as the keygen type parameter and convert it to parameters 
     472                 : //we can actually pass to the PKCS#11 layer.
     473                 : static void*
     474               0 : nsConvertToActualKeyGenParams(PRUint32 keyGenMech, char *params,
     475                 :                               PRUint32 paramLen, PRInt32 keySize,
     476                 :                               nsKeyPairInfo *keyPairInfo)
     477                 : {
     478               0 :   void *returnParams = nsnull;
     479                 : 
     480                 : 
     481               0 :   switch (keyGenMech) {
     482                 :   case CKM_RSA_PKCS_KEY_PAIR_GEN:
     483                 :   {
     484                 :     // For RSA, we don't support passing in key generation arguments from
     485                 :     // the JS code just yet.
     486               0 :     if (params)
     487               0 :       return nsnull;
     488                 : 
     489                 :     PK11RSAGenParams *rsaParams;
     490                 :     rsaParams = static_cast<PK11RSAGenParams*>
     491               0 :                            (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
     492                 :                               
     493               0 :     if (rsaParams == nsnull) {
     494               0 :       return nsnull;
     495                 :     }
     496                 :     /* I'm just taking the same parameters used in 
     497                 :      * certdlgs.c:GenKey
     498                 :      */
     499               0 :     if (keySize > 0) {
     500               0 :       rsaParams->keySizeInBits = keySize;
     501                 :     } else {
     502               0 :       rsaParams->keySizeInBits = 1024;
     503                 :     }
     504               0 :     rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
     505               0 :     returnParams = rsaParams;
     506               0 :     break;
     507                 :   }
     508                 :   case CKM_EC_KEY_PAIR_GEN:
     509                 :   {
     510                 :     /*
     511                 :      * keygen params for generating EC keys must be composed of name=value pairs,
     512                 :      * multiple pairs allowed, separated using semicolon ;
     513                 :      *
     514                 :      * Either param "curve" or param "popcert" must be specified.
     515                 :      * curve=name-of-curve
     516                 :      * popcert=base64-encoded-cert
     517                 :      *
     518                 :      * When both params are specified, popcert will be used.
     519                 :      * If no popcert param is given, or if popcert can not be decoded,
     520                 :      * we will fall back to the curve param.
     521                 :      *
     522                 :      * Additional name=value pairs may be defined in the future.
     523                 :      *
     524                 :      * If param popcert is present and valid, the given certificate will be used
     525                 :      * to determine the key generation params. In addition the certificate
     526                 :      * will be used to produce a dhMac based Proof of Posession,
     527                 :      * using the cert's public key, subject and issuer names,
     528                 :      * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
     529                 :      *
     530                 :      * If neither param popcert nor param curve could be used,
     531                 :      * tse a curve based on the keysize param.
     532                 :      * NOTE: Here keysize is used only as an indication of
     533                 :      * High/Medium/Low strength; elliptic curve
     534                 :      * cryptography uses smaller keys than RSA to provide
     535                 :      * equivalent security.
     536                 :      */
     537                 : 
     538               0 :     char *curve = nsnull;
     539                 : 
     540                 :     {
     541                 :       // extract components of name=value list
     542                 : 
     543               0 :       char *next_input = params;
     544               0 :       char *name = nsnull;
     545               0 :       char *value = nsnull;
     546               0 :       int name_len = 0;
     547               0 :       int value_len = 0;
     548                 :   
     549               0 :       while (getNextNameValueFromECKeygenParamString(
     550                 :               next_input, name, name_len, value, value_len,
     551               0 :               next_input))
     552                 :       {
     553               0 :         if (PL_strncmp(name, "curve", NS_MIN(name_len, 5)) == 0)
     554                 :         {
     555               0 :           curve = PL_strndup(value, value_len);
     556                 :         }
     557               0 :         else if (PL_strncmp(name, "popcert", NS_MIN(name_len, 7)) == 0)
     558                 :         {
     559               0 :           char *certstr = PL_strndup(value, value_len);
     560               0 :           if (certstr) {
     561               0 :             keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
     562               0 :             PL_strfree(certstr);
     563                 : 
     564               0 :             if (keyPairInfo->ecPopCert)
     565                 :             {
     566               0 :               keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
     567                 :             }
     568                 :           }
     569                 :         }
     570                 :       }
     571                 :     }
     572                 : 
     573                 :     // first try to use the params of the provided CA cert
     574               0 :     if (keyPairInfo->ecPopPubKey)
     575                 :     {
     576               0 :       returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
     577                 :     }
     578                 : 
     579                 :     // if we did not yet find good params, do we have a curve name?
     580               0 :     if (!returnParams && curve)
     581                 :     {
     582               0 :       returnParams = decode_ec_params(curve);
     583                 :     }
     584                 : 
     585                 :     // if we did not yet find good params, do something based on keysize
     586               0 :     if (!returnParams)
     587                 :     {
     588               0 :       switch (keySize) {
     589                 :       case 512:
     590                 :       case 1024:
     591               0 :           returnParams = decode_ec_params("secp256r1");
     592               0 :           break;
     593                 :       case 2048:
     594                 :       default:
     595               0 :           returnParams = decode_ec_params("secp384r1");
     596               0 :           break;
     597                 :       }
     598                 :     }
     599                 : 
     600               0 :     if (curve)
     601               0 :       PL_strfree(curve);
     602                 : 
     603               0 :     break;
     604                 :   }
     605                 :   case CKM_DSA_KEY_PAIR_GEN:
     606                 :   {
     607                 :     // For DSA, we don't support passing in key generation arguments from
     608                 :     // the JS code just yet.
     609               0 :     if (params)
     610               0 :       return nsnull;
     611                 : 
     612               0 :     PQGParams *pqgParams = nsnull;
     613               0 :     PQGVerify *vfy = nsnull;
     614                 :     SECStatus  rv;
     615                 :     int        index;
     616                 :        
     617               0 :     index = PQG_PBITS_TO_INDEX(keySize);
     618               0 :     if (index == -1) {
     619               0 :       returnParams = nsnull;
     620               0 :       break;
     621                 :     }
     622               0 :     rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
     623               0 :     if (vfy) {
     624               0 :       PK11_PQG_DestroyVerify(vfy);
     625                 :     }
     626               0 :     if (rv != SECSuccess) {
     627               0 :       if (pqgParams) {
     628               0 :         PK11_PQG_DestroyParams(pqgParams);
     629                 :       }
     630               0 :       return nsnull;
     631                 :     }
     632               0 :     returnParams = pqgParams;
     633               0 :     break;
     634                 :   }
     635                 :   default:
     636               0 :     returnParams = nsnull;
     637                 :   }
     638               0 :   return returnParams;
     639                 : }
     640                 : 
     641                 : //We need to choose which PKCS11 slot we're going to generate
     642                 : //the key on.  Calls the default implementation provided by
     643                 : //nsKeygenHandler.cpp
     644                 : static PK11SlotInfo*
     645               0 : nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
     646                 : {
     647               0 :   nsNSSShutDownPreventionLock locker;
     648               0 :   PRUint32 mechanism = cryptojs_convert_to_mechanism(keyGenType);
     649               0 :   PK11SlotInfo *slot = nsnull;
     650               0 :   nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
     651               0 :   if (NS_FAILED(rv)) {
     652               0 :     if (slot)
     653               0 :       PK11_FreeSlot(slot);
     654               0 :     slot = nsnull;
     655                 :   }
     656               0 :   return slot;
     657                 : }
     658                 : 
     659                 : //Free the parameters that were passed into PK11_GenerateKeyPair
     660                 : //depending on the mechanism type used.
     661                 : static void
     662               0 : nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
     663                 : {
     664               0 :   switch (keyGenMechanism) {
     665                 :   case CKM_RSA_PKCS_KEY_PAIR_GEN:
     666               0 :     nsMemory::Free(params);
     667               0 :     break;
     668                 :   case CKM_EC_KEY_PAIR_GEN:
     669               0 :     SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
     670               0 :     break;
     671                 :   case CKM_DSA_KEY_PAIR_GEN:
     672               0 :     PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
     673               0 :     break;
     674                 :   }
     675               0 : }
     676                 : 
     677                 : //Function that is used to generate a single key pair.
     678                 : //Once all the arguments have been parsed and processed, this
     679                 : //function gets called and takes care of actually generating
     680                 : //the key pair passing the appopriate parameters to the NSS
     681                 : //functions.
     682                 : static nsresult
     683               0 : cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 
     684                 :                             PRInt32 keySize, char *params, 
     685                 :                             nsIInterfaceRequestor *uiCxt,
     686                 :                             PK11SlotInfo *slot, bool willEscrow)
     687                 :                             
     688                 : {
     689                 :   nsIGeneratingKeypairInfoDialogs * dialogs;
     690               0 :   nsKeygenThread *KeygenRunnable = 0;
     691               0 :   nsCOMPtr<nsIKeygenThread> runnable;
     692                 : 
     693               0 :   PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
     694                 :   void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 
     695                 :                                                      (params) ? strlen(params):0, 
     696               0 :                                                      keySize, keyPairInfo);
     697                 : 
     698               0 :   if (!keyGenParams) {
     699               0 :     return NS_ERROR_INVALID_ARG;
     700                 :   }
     701                 : 
     702                 :   // Make sure the token has password already set on it before trying
     703                 :   // to generate the key.
     704                 : 
     705               0 :   nsresult rv = setPassword(slot, uiCxt);
     706               0 :   if (NS_FAILED(rv))
     707               0 :     return rv;
     708                 : 
     709               0 :   if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
     710               0 :     return NS_ERROR_FAILURE;
     711                 :  
     712                 : 
     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 ultimately wind up on a smart card,
     716                 :   // then we'll generate the private key on the internal slot
     717                 :   // as a temporary key, then move it to the destination slot. 
     718                 :   // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
     719                 :   //       so that the key has zero chance of being store in the
     720                 :   //       user's key3.db file.  Which the slot returned by
     721                 :   //       PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
     722                 :   //       does not.
     723               0 :   PK11SlotInfo *intSlot = nsnull;
     724               0 :   PK11SlotInfoCleaner siCleaner(intSlot);
     725                 :   
     726               0 :   PK11SlotInfo *origSlot = nsnull;
     727                 :   bool isPerm;
     728                 : 
     729               0 :   if (willEscrow && !PK11_IsInternal(slot)) {
     730               0 :     intSlot = PK11_GetInternalSlot();
     731               0 :     NS_ASSERTION(intSlot,"Couldn't get the internal slot");
     732               0 :     isPerm = false;
     733               0 :     origSlot = slot;
     734               0 :     slot = intSlot;
     735                 :   } else {
     736               0 :     isPerm = true;
     737                 :   }
     738                 : 
     739                 :   rv = getNSSDialogs((void**)&dialogs,
     740                 :                      NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
     741               0 :                      NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
     742                 : 
     743               0 :   if (NS_SUCCEEDED(rv)) {
     744               0 :     KeygenRunnable = new nsKeygenThread();
     745               0 :     if (KeygenRunnable) {
     746               0 :       NS_ADDREF(KeygenRunnable);
     747                 :     }
     748                 :   }
     749                 : 
     750               0 :   if (NS_FAILED(rv) || !KeygenRunnable) {
     751               0 :     rv = NS_OK;
     752                 :     keyPairInfo->privKey = PK11_GenerateKeyPair(slot, mechanism, keyGenParams,
     753                 :                                                 &keyPairInfo->pubKey, isPerm, 
     754               0 :                                                 isPerm, uiCxt);
     755                 :   } else {
     756               0 :     KeygenRunnable->SetParams( slot, mechanism, keyGenParams, isPerm, isPerm, uiCxt );
     757                 : 
     758               0 :     runnable = do_QueryInterface(KeygenRunnable);
     759                 : 
     760               0 :     if (runnable) {
     761                 :       {
     762               0 :         nsPSMUITracker tracker;
     763               0 :         if (tracker.isUIForbidden()) {
     764               0 :           rv = NS_ERROR_NOT_AVAILABLE;
     765                 :         }
     766                 :         else {
     767               0 :           rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
     768                 :           // We call join on the thread, 
     769                 :           // so we can be sure that no simultaneous access to the passed parameters will happen.
     770               0 :           KeygenRunnable->Join();
     771                 :         }
     772                 :       }
     773                 : 
     774               0 :       NS_RELEASE(dialogs);
     775               0 :       if (NS_SUCCEEDED(rv)) {
     776               0 :         rv = KeygenRunnable->GetParams(&keyPairInfo->privKey, &keyPairInfo->pubKey);
     777                 :       }
     778                 :     }
     779                 :   }
     780                 : 
     781               0 :   nsFreeKeyGenParams(mechanism, keyGenParams);
     782                 : 
     783               0 :   if (KeygenRunnable) {
     784               0 :     NS_RELEASE(KeygenRunnable);
     785                 :   }
     786                 : 
     787               0 :   if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
     788               0 :     return NS_ERROR_FAILURE;
     789                 :   }
     790                 :  
     791                 : 
     792                 :   //If we generated the key pair on the internal slot because the
     793                 :   // keys were going to be escrowed, move the keys over right now.
     794               0 :   if (willEscrow && intSlot) {
     795                 :     SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(origSlot, 
     796                 :                                                     keyPairInfo->privKey,
     797                 :                                                     keyPairInfo->pubKey,
     798               0 :                                                     true, true);
     799               0 :     SECKEYPrivateKeyCleaner pkCleaner(newPrivKey);
     800                 : 
     801               0 :     if (!newPrivKey)
     802               0 :       return NS_ERROR_FAILURE;
     803                 : 
     804                 :     // The private key is stored on the selected slot now, and the copy we
     805                 :     // ultimately use for escrowing when the time comes lives 
     806                 :     // in the internal slot.  We will delete it from that slot
     807                 :     // after the requests are made.  This call only gives up
     808                 :     // our reference to the key object and does not actually 
     809                 :     // physically remove it from the card itself.
     810                 :     // The actual delete calls are being made in the destructors
     811                 :     // of the cleaner helper instances.
     812                 :   }  
     813                 : 
     814               0 :   return NS_OK;
     815                 : }
     816                 : 
     817                 : /*
     818                 :  * FUNCTION: cryptojs_ReadArgsAndGenerateKey
     819                 :  * -------------------------------------
     820                 :  * INPUTS:
     821                 :  *  cx
     822                 :  *    The JSContext associated with the execution of the corresponging
     823                 :  *    crypto.generateCRMFRequest call
     824                 :  *  argv
     825                 :  *    A pointer to an array of JavaScript parameters passed to the
     826                 :  *    method crypto.generateCRMFRequest.  The array should have the
     827                 :  *    3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
     828                 :  *    the definition of crypto.generateCRMFRequest at the following
     829                 :  *    document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
     830                 :  *  keyGenType
     831                 :  *    A structure used to store the information about the newly created
     832                 :  *    key pair.
     833                 :  *  uiCxt
     834                 :  *    An interface requestor that would be used to get an nsIPrompt
     835                 :  *    if we need to ask the user for a password.
     836                 :  *  slotToUse
     837                 :  *    The PKCS11 slot to use for generating the key pair. If nsnull, then
     838                 :  *    this function should select a slot that can do the key generation 
     839                 :  *    from the keytype associted with the keyPairInfo, and pass it back to
     840                 :  *    the caller so that subsequence key generations can use the same slot. 
     841                 :  *  willEscrow
     842                 :  *    If true, then that means we will try to escrow the generated
     843                 :  *    private key when building the CRMF request.  If false, then
     844                 :  *    we will not try to escrow the private key.
     845                 :  *
     846                 :  * NOTES:
     847                 :  * This function takes care of reading a set of 3 parameters that define
     848                 :  * one key generation.  The argv pointer should be one that originates
     849                 :  * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
     850                 :  * The function interprets the argument in the first index as an integer and
     851                 :  * passes that as the key size for the key generation-this parameter is
     852                 :  * mandatory.  The second parameter is read in as a string.  This value can
     853                 :  * be null in JavaScript world and everything will still work.  The third
     854                 :  * parameter is a mandatory string that indicates what kind of key to generate.
     855                 :  * There should always be 1-to-1 correspondence between the strings compared
     856                 :  * in the function cryptojs_interpret_key_gen_type and the strings listed in
     857                 :  * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
     858                 :  * under the definition of the method generateCRMFRequest, for the parameter
     859                 :  * "keyGenAlgN".  After reading the parameters, the function then 
     860                 :  * generates the key pairs passing the parameters parsed from the JavaScript i
     861                 :  * routine.  
     862                 :  *
     863                 :  * RETURN:
     864                 :  * NS_OK if creating the Key was successful.  Any other return value
     865                 :  * indicates an error.
     866                 :  */
     867                 : 
     868                 : static nsresult
     869               0 : cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
     870                 :                                 jsval *argv,
     871                 :                                 nsKeyPairInfo *keyGenType,
     872                 :                                 nsIInterfaceRequestor *uiCxt,
     873                 :                                 PK11SlotInfo **slot, bool willEscrow)
     874                 : {
     875                 :   JSString  *jsString;
     876               0 :   JSAutoByteString params, keyGenAlg;
     877                 :   int    keySize;
     878                 :   nsresult  rv;
     879                 : 
     880               0 :   if (!JSVAL_IS_INT(argv[0])) {
     881                 :     JS_ReportError(cx, "%s%s\n", JS_ERROR,
     882               0 :                    "passed in non-integer for key size");
     883               0 :     return NS_ERROR_FAILURE;
     884                 :   }
     885               0 :   keySize = JSVAL_TO_INT(argv[0]);
     886               0 :   if (!JSVAL_IS_NULL(argv[1])) {
     887               0 :     jsString = JS_ValueToString(cx,argv[1]);
     888               0 :     NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
     889               0 :     argv[1] = STRING_TO_JSVAL(jsString);
     890               0 :     params.encode(cx, jsString);
     891               0 :     NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
     892                 :   }
     893                 : 
     894               0 :   if (JSVAL_IS_NULL(argv[2])) {
     895                 :     JS_ReportError(cx,"%s%s\n", JS_ERROR,
     896               0 :              "key generation type not specified");
     897               0 :     return NS_ERROR_FAILURE;
     898                 :   }
     899               0 :   jsString = JS_ValueToString(cx, argv[2]);
     900               0 :   NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
     901               0 :   argv[2] = STRING_TO_JSVAL(jsString);
     902               0 :   keyGenAlg.encode(cx, jsString);
     903               0 :   NS_ENSURE_TRUE(!!keyGenAlg, NS_ERROR_OUT_OF_MEMORY);
     904               0 :   keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg.ptr());
     905               0 :   if (keyGenType->keyGenType == invalidKeyGen) {
     906                 :     JS_ReportError(cx, "%s%s%s", JS_ERROR,
     907                 :                    "invalid key generation argument:",
     908               0 :                    keyGenAlg.ptr());
     909               0 :     goto loser;
     910                 :   }
     911               0 :   if (*slot == nsnull) {
     912               0 :     *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
     913               0 :     if (*slot == nsnull)
     914               0 :       goto loser;
     915                 :   }
     916                 : 
     917                 :   rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
     918               0 :                                    *slot,willEscrow);
     919                 : 
     920               0 :   if (rv != NS_OK) {
     921                 :     JS_ReportError(cx,"%s%s%s", JS_ERROR,
     922                 :                    "could not generate the key for algorithm ",
     923               0 :                    keyGenAlg.ptr());
     924               0 :     goto loser;
     925                 :   }
     926               0 :   return NS_OK;
     927                 : loser:
     928               0 :   return NS_ERROR_FAILURE;
     929                 : }
     930                 : 
     931                 : //Utility funciton to free up the memory used by nsKeyPairInfo
     932                 : //arrays.
     933                 : static void
     934               0 : nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
     935                 : {
     936               0 :   NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
     937               0 :   if (!keyids)
     938               0 :     return;
     939                 :   int i;
     940               0 :   for (i=0; i<numIDs; i++) {
     941               0 :     if (keyids[i].pubKey)
     942               0 :       SECKEY_DestroyPublicKey(keyids[i].pubKey);
     943               0 :     if (keyids[i].privKey)
     944               0 :       SECKEY_DestroyPrivateKey(keyids[i].privKey);
     945               0 :     if (keyids[i].ecPopCert)
     946               0 :       CERT_DestroyCertificate(keyids[i].ecPopCert);
     947               0 :     if (keyids[i].ecPopPubKey)
     948               0 :       SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
     949                 :   }
     950               0 :   delete []keyids;
     951                 : }
     952                 : 
     953                 : //Utility funciton used to free the genertaed cert request messages
     954                 : static void
     955               0 : nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, PRInt32 numMessages)
     956                 : {
     957                 :   PRInt32 i;
     958               0 :   for (i=0; i<numMessages && certReqMsgs[i]; i++) {
     959               0 :     CRMF_DestroyCertReqMsg(certReqMsgs[i]);
     960                 :   }
     961               0 :   delete []certReqMsgs;
     962               0 : }
     963                 : 
     964                 : //If the form called for escrowing the private key we just generated,
     965                 : //this function adds all the correct elements to the request.
     966                 : //That consists of adding CRMFEncryptedKey to the reques as part
     967                 : //of the CRMFPKIArchiveOptions Control.
     968                 : static nsresult
     969               0 : nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
     970                 :                      nsNSSCertificate *wrappingCert)
     971                 : {
     972               0 :   if (!wrappingCert ||
     973               0 :       CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
     974               0 :     return NS_ERROR_FAILURE;
     975                 :   }
     976               0 :   CERTCertificate *cert = wrappingCert->GetCert();
     977               0 :   if (!cert)
     978               0 :     return NS_ERROR_FAILURE;
     979                 : 
     980                 :   CRMFEncryptedKey *encrKey = 
     981               0 :       CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert);
     982               0 :   CERT_DestroyCertificate(cert);
     983               0 :   if (!encrKey)
     984               0 :     return NS_ERROR_FAILURE;
     985                 : 
     986                 :   CRMFPKIArchiveOptions *archOpt = 
     987               0 :       CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
     988               0 :   if (!archOpt) {
     989               0 :     CRMF_DestroyEncryptedKey(encrKey);
     990               0 :     return NS_ERROR_FAILURE;
     991                 :   }
     992               0 :   SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
     993               0 :   CRMF_DestroyEncryptedKey(encrKey);
     994               0 :   CRMF_DestroyPKIArchiveOptions(archOpt);
     995               0 :   if (srv != SECSuccess)
     996               0 :     return NS_ERROR_FAILURE;
     997                 : 
     998               0 :   return NS_OK;
     999                 : }
    1000                 : 
    1001                 : //Set the Distinguished Name (Subject Name) for the cert
    1002                 : //being requested.
    1003                 : static nsresult
    1004               0 : nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
    1005                 : {
    1006               0 :   if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
    1007               0 :     return NS_ERROR_FAILURE;
    1008                 :   }
    1009               0 :   CERTName *subjectName = CERT_AsciiToName(reqDN);
    1010               0 :   if (!subjectName) {
    1011               0 :     return NS_ERROR_FAILURE;
    1012                 :   }
    1013                 :   SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
    1014                 :                                                    static_cast<void*>
    1015               0 :                                                               (subjectName));
    1016               0 :   CERT_DestroyName(subjectName);
    1017               0 :   return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
    1018                 : }
    1019                 : 
    1020                 : //Set Registration Token Control on the request.
    1021                 : static nsresult
    1022               0 : nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
    1023                 : {
    1024                 :   // this should never happen, but might as well add this.
    1025               0 :   NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
    1026               0 :   if (regToken){
    1027               0 :     if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
    1028               0 :       return NS_ERROR_FAILURE;
    1029                 :   
    1030                 :     SECItem src;
    1031               0 :     src.data = (unsigned char*)regToken;
    1032               0 :     src.len  = strlen(regToken);
    1033                 :     SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src, 
    1034               0 :                                         SEC_ASN1_GET(SEC_UTF8StringTemplate));
    1035                 : 
    1036               0 :     if (!derEncoded)
    1037               0 :       return NS_ERROR_FAILURE;
    1038                 : 
    1039               0 :     SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
    1040               0 :     SECITEM_FreeItem(derEncoded,true);
    1041               0 :     if (srv != SECSuccess)
    1042               0 :       return NS_ERROR_FAILURE;
    1043                 :   }
    1044               0 :   return NS_OK;
    1045                 : }
    1046                 : 
    1047                 : //Set the Authenticator control on the cert reuest.  It's just
    1048                 : //a string that gets passed along.
    1049                 : static nsresult
    1050               0 : nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
    1051                 : {
    1052                 :   //This should never happen, but might as well check.
    1053               0 :   NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
    1054               0 :   if (authenticator) {
    1055               0 :     if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
    1056               0 :       return NS_ERROR_FAILURE;
    1057                 :     
    1058                 :     SECItem src;
    1059               0 :     src.data = (unsigned char*)authenticator;
    1060               0 :     src.len  = strlen(authenticator);
    1061                 :     SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src,
    1062               0 :                                      SEC_ASN1_GET(SEC_UTF8StringTemplate));
    1063               0 :     if (!derEncoded)
    1064               0 :       return NS_ERROR_FAILURE;
    1065                 : 
    1066                 :     SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 
    1067               0 :                                                             derEncoded);
    1068               0 :     SECITEM_FreeItem(derEncoded, true);
    1069               0 :     if (srv != SECSuccess)
    1070               0 :       return NS_ERROR_FAILURE;
    1071                 :   }
    1072               0 :   return NS_OK;
    1073                 : }
    1074                 : 
    1075                 : // ASN1 DER encoding rules say that when encoding a BIT string,
    1076                 : // the length in the header for the bit string is the number 
    1077                 : // of "useful" bits in the BIT STRING.  So the function finds
    1078                 : // it and sets accordingly for the returned item.
    1079                 : static void
    1080               0 : nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
    1081                 : {
    1082                 :   unsigned char onebyte;
    1083               0 :   unsigned int i, len = 0;
    1084                 : 
    1085                 :   /* to prevent warning on some platform at compile time */
    1086               0 :   onebyte = '\0';
    1087                 :   /* Get the position of the right-most turn-on bit */
    1088               0 :   for (i = 0; i < (value->len ) * 8; ++i) {
    1089               0 :     if (i % 8 == 0)
    1090               0 :       onebyte = value->data[i/8];
    1091               0 :     if (onebyte & 0x80)
    1092               0 :       len = i;
    1093               0 :     onebyte <<= 1;
    1094                 :   }
    1095                 : 
    1096               0 :   bitsmap->data = value->data;
    1097                 :   /* Add one here since we work with base 1 */
    1098               0 :   bitsmap->len = len + 1;
    1099               0 : }
    1100                 : 
    1101                 : //This next section defines all the functions that sets the 
    1102                 : //keyUsageExtension for all the different types of key gens
    1103                 : //we handle.  The keyUsageExtension is just a bit flag extension
    1104                 : //that we set in wrapper functions that call straight into
    1105                 : //nsSetKeyUsageExtension.  There is one wrapper funciton for each
    1106                 : //keyGenType.  The correct function will eventually be called 
    1107                 : //by going through a switch statement based on the nsKeyGenType
    1108                 : //in the nsKeyPairInfo struct.
    1109                 : static nsresult
    1110               0 : nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
    1111                 :                        unsigned char   keyUsage)
    1112                 : {
    1113               0 :   SECItem                 *encodedExt= nsnull;
    1114               0 :   SECItem                  keyUsageValue = { (SECItemType) 0, nsnull, 0 };
    1115               0 :   SECItem                  bitsmap = { (SECItemType) 0, nsnull, 0 };
    1116                 :   SECStatus                srv;
    1117               0 :   CRMFCertExtension       *ext = nsnull;
    1118                 :   CRMFCertExtCreationInfo  extAddParams;
    1119                 :   SEC_ASN1Template         bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nsnull,
    1120               0 :                                              sizeof(SECItem)};
    1121                 : 
    1122               0 :   keyUsageValue.data = &keyUsage;
    1123               0 :   keyUsageValue.len  = 1;
    1124               0 :   nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
    1125                 : 
    1126               0 :   encodedExt = SEC_ASN1EncodeItem(nsnull, nsnull, &bitsmap,&bitStrTemplate);
    1127               0 :   if (encodedExt == nsnull) {
    1128               0 :     goto loser;
    1129                 :   }
    1130               0 :   ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
    1131               0 :   if (ext == nsnull) {
    1132               0 :       goto loser;
    1133                 :   }
    1134               0 :   extAddParams.numExtensions = 1;
    1135               0 :   extAddParams.extensions = &ext;
    1136                 :   srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
    1137               0 :                                          &extAddParams);
    1138               0 :   if (srv != SECSuccess) {
    1139               0 :       goto loser;
    1140                 :   }
    1141               0 :   CRMF_DestroyCertExtension(ext);
    1142               0 :   SECITEM_FreeItem(encodedExt, true);
    1143               0 :   return NS_OK;
    1144                 :  loser:
    1145               0 :   if (ext) {
    1146               0 :     CRMF_DestroyCertExtension(ext);
    1147                 :   }
    1148               0 :   if (encodedExt) {
    1149               0 :       SECITEM_FreeItem(encodedExt, true);
    1150                 :   }
    1151               0 :   return NS_ERROR_FAILURE;
    1152                 : }
    1153                 : 
    1154                 : static nsresult
    1155               0 : nsSetRSADualUse(CRMFCertRequest *crmfReq)
    1156                 : {
    1157                 :   unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
    1158                 :                            | KU_NON_REPUDIATION
    1159               0 :                            | KU_KEY_ENCIPHERMENT;
    1160                 : 
    1161               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1162                 : }
    1163                 : 
    1164                 : static nsresult
    1165               0 : nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
    1166                 : {
    1167               0 :   unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
    1168                 : 
    1169               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1170                 : }
    1171                 : 
    1172                 : static nsresult
    1173               0 : nsSetRSASign(CRMFCertRequest *crmfReq)
    1174                 : {
    1175               0 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
    1176                 : 
    1177                 : 
    1178               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1179                 : }
    1180                 : 
    1181                 : static nsresult
    1182               0 : nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
    1183                 : {
    1184               0 :   unsigned char keyUsage = KU_NON_REPUDIATION;
    1185                 : 
    1186               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1187                 : }
    1188                 : 
    1189                 : static nsresult
    1190               0 : nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
    1191                 : {
    1192                 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
    1193               0 :                            KU_NON_REPUDIATION;
    1194                 : 
    1195               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1196                 : }
    1197                 : 
    1198                 : static nsresult
    1199               0 : nsSetECDualUse(CRMFCertRequest *crmfReq)
    1200                 : {
    1201                 :   unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
    1202                 :                            | KU_NON_REPUDIATION
    1203               0 :                            | KU_KEY_AGREEMENT;
    1204                 : 
    1205               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1206                 : }
    1207                 : 
    1208                 : static nsresult
    1209               0 : nsSetECKeyEx(CRMFCertRequest *crmfReq)
    1210                 : {
    1211               0 :   unsigned char keyUsage = KU_KEY_AGREEMENT;
    1212                 : 
    1213               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1214                 : }
    1215                 : 
    1216                 : static nsresult
    1217               0 : nsSetECSign(CRMFCertRequest *crmfReq)
    1218                 : {
    1219               0 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
    1220                 : 
    1221                 : 
    1222               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1223                 : }
    1224                 : 
    1225                 : static nsresult
    1226               0 : nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
    1227                 : {
    1228               0 :   unsigned char keyUsage = KU_NON_REPUDIATION;
    1229                 : 
    1230               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1231                 : }
    1232                 : 
    1233                 : static nsresult
    1234               0 : nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
    1235                 : {
    1236                 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
    1237               0 :                            KU_NON_REPUDIATION;
    1238                 : 
    1239               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1240                 : }
    1241                 : 
    1242                 : static nsresult
    1243               0 : nsSetDH(CRMFCertRequest *crmfReq)
    1244                 : {
    1245               0 :   unsigned char keyUsage = KU_KEY_AGREEMENT;
    1246                 : 
    1247               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1248                 : }
    1249                 : 
    1250                 : static nsresult
    1251               0 : nsSetDSASign(CRMFCertRequest *crmfReq)
    1252                 : {
    1253               0 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
    1254                 : 
    1255               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1256                 : }
    1257                 : 
    1258                 : static nsresult
    1259               0 : nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
    1260                 : {
    1261               0 :   unsigned char keyUsage = KU_NON_REPUDIATION;
    1262                 : 
    1263               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1264                 : }
    1265                 : 
    1266                 : static nsresult
    1267               0 : nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
    1268                 : {
    1269                 :   unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
    1270               0 :                            KU_NON_REPUDIATION;
    1271                 : 
    1272               0 :   return nsSetKeyUsageExtension(crmfReq, keyUsage);
    1273                 : }
    1274                 : 
    1275                 : static nsresult
    1276               0 : nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
    1277                 : {
    1278                 :   nsresult rv;
    1279                 : 
    1280               0 :   switch (keyGenType) {
    1281                 :   case rsaDualUse:
    1282               0 :     rv = nsSetRSADualUse(crmfReq);
    1283               0 :     break;
    1284                 :   case rsaEnc:
    1285               0 :     rv = nsSetRSAKeyEx(crmfReq);
    1286               0 :     break;
    1287                 :   case rsaSign:
    1288               0 :     rv = nsSetRSASign(crmfReq);
    1289               0 :     break;
    1290                 :   case rsaNonrepudiation:
    1291               0 :     rv = nsSetRSANonRepudiation(crmfReq);
    1292               0 :     break;
    1293                 :   case rsaSignNonrepudiation:
    1294               0 :     rv = nsSetRSASignNonRepudiation(crmfReq);
    1295               0 :     break;
    1296                 :   case ecDualUse:
    1297               0 :     rv = nsSetECDualUse(crmfReq);
    1298               0 :     break;
    1299                 :   case ecEnc:
    1300               0 :     rv = nsSetECKeyEx(crmfReq);
    1301               0 :     break;
    1302                 :   case ecSign:
    1303               0 :     rv = nsSetECSign(crmfReq);
    1304               0 :     break;
    1305                 :   case ecNonrepudiation:
    1306               0 :     rv = nsSetECNonRepudiation(crmfReq);
    1307               0 :     break;
    1308                 :   case ecSignNonrepudiation:
    1309               0 :     rv = nsSetECSignNonRepudiation(crmfReq);
    1310               0 :     break;
    1311                 :   case dhEx:
    1312               0 :     rv = nsSetDH(crmfReq);
    1313               0 :     break;
    1314                 :   case dsaSign:
    1315               0 :     rv = nsSetDSASign(crmfReq);
    1316               0 :     break;
    1317                 :   case dsaNonrepudiation:
    1318               0 :     rv = nsSetDSANonRepudiation(crmfReq);
    1319               0 :     break;
    1320                 :   case dsaSignNonrepudiation:
    1321               0 :     rv = nsSetDSASignNonRepudiation(crmfReq);
    1322               0 :     break;
    1323                 :   default:
    1324               0 :     rv = NS_ERROR_FAILURE;
    1325               0 :     break;
    1326                 :   }
    1327               0 :   return rv;
    1328                 : }
    1329                 : 
    1330                 : //Create a single CRMFCertRequest with all of the necessary parts 
    1331                 : //already installed.  The request returned by this function will
    1332                 : //have all the parts necessary and can just be added to a 
    1333                 : //Certificate Request Message.
    1334                 : static CRMFCertRequest*
    1335               0 : nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 
    1336                 :                       char *authenticator, nsNSSCertificate *wrappingCert)
    1337                 : {
    1338                 :   PRUint32 reqID;
    1339                 :   nsresult rv;
    1340                 : 
    1341                 :   //The draft says the ID of the request should be a random
    1342                 :   //number.  We don't have a way of tracking this number
    1343                 :   //to compare when the reply actually comes back,though.
    1344               0 :   PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
    1345               0 :   CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
    1346               0 :   if (!certReq)
    1347               0 :     return nsnull;
    1348                 : 
    1349               0 :   long version = SEC_CERTIFICATE_VERSION_3;
    1350                 :   SECStatus srv;
    1351               0 :   CERTSubjectPublicKeyInfo *spki = nsnull;
    1352               0 :   srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
    1353               0 :   if (srv != SECSuccess)
    1354               0 :     goto loser;
    1355                 :   
    1356               0 :   spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
    1357               0 :   if (!spki)
    1358               0 :     goto loser;
    1359                 : 
    1360               0 :   srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
    1361               0 :   SECKEY_DestroySubjectPublicKeyInfo(spki);
    1362               0 :   if (srv != SECSuccess)
    1363               0 :     goto loser;
    1364                 : 
    1365               0 :   if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
    1366               0 :     rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
    1367               0 :     if (NS_FAILED(rv))
    1368               0 :       goto loser;
    1369                 :   }
    1370               0 :   rv = nsSetDNForRequest(certReq, reqDN);
    1371               0 :   if (NS_FAILED(rv))
    1372               0 :     goto loser;
    1373                 : 
    1374               0 :   rv = nsSetRegToken(certReq, regToken);
    1375               0 :   if (NS_FAILED(rv))
    1376               0 :     goto loser;
    1377                 : 
    1378               0 :   rv = nsSetAuthenticator(certReq, authenticator);
    1379               0 :   if (NS_FAILED(rv))
    1380               0 :     goto loser;
    1381                 : 
    1382               0 :  rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 
    1383               0 :   if (NS_FAILED(rv))
    1384               0 :     goto loser;
    1385                 : 
    1386               0 :   return certReq;
    1387                 : loser:
    1388               0 :   if (certReq) {
    1389               0 :     CRMF_DestroyCertRequest(certReq);
    1390                 :   }
    1391               0 :   return nsnull;
    1392                 : }
    1393                 : 
    1394                 : /*
    1395                 :  * This function will set the Proof Of Possession (POP) for a request
    1396                 :  * associated with a key pair intended to do Key Encipherment.  Currently
    1397                 :  * this means encryption only keys.
    1398                 :  */
    1399                 : static nsresult
    1400               0 : nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
    1401                 : {
    1402                 :   SECItem       bitString;
    1403                 :   unsigned char der[2];
    1404                 :   SECStatus     srv;
    1405                 : 
    1406               0 :   if (isEscrowed) {
    1407                 :     /* For proof of possession on escrowed keys, we use the
    1408                 :      * this Message option of POPOPrivKey and include a zero
    1409                 :      * length bit string in the POP field.  This is OK because the encrypted
    1410                 :      * private key already exists as part of the PKIArchiveOptions
    1411                 :      * Control and that for all intents and purposes proves that
    1412                 :      * we do own the private key.
    1413                 :      */
    1414               0 :     der[0] = 0x03; /*We've got a bit string          */
    1415               0 :     der[1] = 0x00; /*We've got a 0 length bit string */
    1416               0 :     bitString.data = der;
    1417               0 :     bitString.len  = 2;
    1418                 :     srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
    1419               0 :                                               crmfNoSubseqMess, &bitString);
    1420                 :   } else {
    1421                 :     /* If the encryption key is not being escrowed, then we set the 
    1422                 :      * Proof Of Possession to be a Challenge Response mechanism.
    1423                 :      */
    1424                 :     srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
    1425                 :                                               crmfSubsequentMessage,
    1426               0 :                                               crmfChallengeResp, nsnull);
    1427                 :   }
    1428               0 :   return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
    1429                 : }
    1430                 : 
    1431                 : static void PR_CALLBACK
    1432                 : nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
    1433                 : 
    1434                 : static void PR_CALLBACK
    1435                 : nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
    1436                 : 
    1437                 : static nsresult
    1438               0 : nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 
    1439                 :                                  nsKeyPairInfo  *keyInfo,
    1440                 :                                  CRMFCertRequest *certReq)
    1441                 : {
    1442                 :   // RFC 2511 Appendix A section 2 a) defines,
    1443                 :   // the "text" input for HMAC shall be the DER encoded version of
    1444                 :   // of the single cert request.
    1445                 :   // We'll produce that encoding and destroy it afterwards,
    1446                 :   // because when sending the complete package to the CA,
    1447                 :   // we'll use a different encoding, one that includes POP and
    1448                 :   // allows multiple requests to be sent in one step.
    1449                 : 
    1450               0 :   unsigned long der_request_len = 0;
    1451               0 :   SECItem *der_request = NULL;
    1452               0 :   SECItemCleanerTrueParam der_request_cleaner(der_request);
    1453                 : 
    1454               0 :   if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
    1455                 :                                            nsCRMFEncoderItemCount, 
    1456               0 :                                            &der_request_len))
    1457               0 :     return NS_ERROR_FAILURE;
    1458                 : 
    1459               0 :   der_request = SECITEM_AllocItem(nsnull, nsnull, der_request_len);
    1460               0 :   if (!der_request)
    1461               0 :     return NS_ERROR_FAILURE;
    1462                 : 
    1463                 :   // set len in returned SECItem back to zero, because it will
    1464                 :   // be used as the destination offset inside the 
    1465                 :   // nsCRMFEncoderItemStore callback.
    1466                 : 
    1467               0 :   der_request->len = 0;
    1468                 : 
    1469               0 :   if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
    1470                 :                                            nsCRMFEncoderItemStore, 
    1471               0 :                                            der_request))
    1472               0 :     return NS_ERROR_FAILURE;
    1473                 : 
    1474                 :   // RFC 2511 Appendix A section 2 c):
    1475                 :   // "A key K is derived from the shared secret Kec and the subject and
    1476                 :   //  issuer names in the CA's certificate as follows:
    1477                 :   //  K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
    1478                 : 
    1479               0 :   PK11SymKey *shared_secret = NULL;
    1480               0 :   PK11SymKeyCleaner shared_secret_cleaner(shared_secret);
    1481                 : 
    1482               0 :   PK11SymKey *subject_and_secret = NULL;
    1483               0 :   PK11SymKeyCleaner subject_and_secret_cleaner(subject_and_secret);
    1484                 : 
    1485               0 :   PK11SymKey *subject_and_secret_and_issuer = NULL;
    1486               0 :   PK11SymKeyCleaner subject_and_secret_and_issuer_cleaner(subject_and_secret_and_issuer);
    1487                 : 
    1488               0 :   PK11SymKey *sha1_of_subject_and_secret_and_issuer = NULL;
    1489               0 :   PK11SymKeyCleaner sha1_of_subject_and_secret_and_issuer_cleaner(sha1_of_subject_and_secret_and_issuer);
    1490                 : 
    1491                 :   shared_secret = 
    1492                 :     PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
    1493                 :                           keyInfo->ecPopPubKey,  // SECKEYPublicKey *pubKey
    1494                 :                           false, // bool isSender
    1495                 :                           NULL, // SECItem *randomA
    1496                 :                           NULL, // SECItem *randomB
    1497                 :                           CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
    1498                 :                           CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
    1499                 :                           CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
    1500                 :                           0, // int keySize
    1501                 :                           CKD_NULL, // CK_ULONG kdf
    1502                 :                           NULL, // SECItem *sharedData
    1503               0 :                           NULL); // void *wincx
    1504                 : 
    1505               0 :   if (!shared_secret)
    1506               0 :     return NS_ERROR_FAILURE;
    1507                 : 
    1508                 :   CK_KEY_DERIVATION_STRING_DATA concat_data_base;
    1509               0 :   concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
    1510               0 :   concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
    1511                 :   SECItem concat_data_base_item;
    1512               0 :   concat_data_base_item.data = (unsigned char*)&concat_data_base;
    1513               0 :   concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
    1514                 : 
    1515                 :   subject_and_secret =
    1516                 :     PK11_Derive(shared_secret, // PK11SymKey *baseKey
    1517                 :                 CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
    1518                 :                 &concat_data_base_item, // SECItem *param
    1519                 :                 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
    1520                 :                 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
    1521               0 :                 0); // int keySize
    1522                 : 
    1523               0 :   if (!subject_and_secret)
    1524               0 :     return NS_ERROR_FAILURE;
    1525                 : 
    1526                 :   CK_KEY_DERIVATION_STRING_DATA concat_base_data;
    1527               0 :   concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
    1528               0 :   concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
    1529                 :   SECItem concat_base_data_item;
    1530               0 :   concat_base_data_item.data = (unsigned char*)&concat_base_data;
    1531               0 :   concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
    1532                 : 
    1533                 :   subject_and_secret_and_issuer =
    1534                 :     PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
    1535                 :                 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
    1536                 :                 &concat_base_data_item, // SECItem *param
    1537                 :                 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
    1538                 :                 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
    1539               0 :                 0); // int keySize
    1540                 : 
    1541               0 :   if (!subject_and_secret_and_issuer)
    1542               0 :     return NS_ERROR_FAILURE;
    1543                 : 
    1544                 :   sha1_of_subject_and_secret_and_issuer =
    1545                 :     PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
    1546                 :                 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
    1547                 :                 NULL, // SECItem *param
    1548                 :                 CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
    1549                 :                 CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
    1550               0 :                 0); // int keySize
    1551                 : 
    1552               0 :   if (!sha1_of_subject_and_secret_and_issuer)
    1553               0 :     return NS_ERROR_FAILURE;
    1554                 : 
    1555               0 :   PK11Context *context = NULL;
    1556               0 :   PK11ContextCleanerTrueParam context_cleaner(context);
    1557                 : 
    1558                 :   SECItem ignore;
    1559               0 :   ignore.data = 0;
    1560               0 :   ignore.len = 0;
    1561                 : 
    1562                 :   context = 
    1563                 :     PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
    1564                 :                                CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
    1565                 :                                sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
    1566               0 :                                &ignore); // SECItem *param
    1567                 : 
    1568               0 :   if (!context)
    1569               0 :     return NS_ERROR_FAILURE;
    1570                 : 
    1571               0 :   if (SECSuccess != PK11_DigestBegin(context))
    1572               0 :     return NS_ERROR_FAILURE;
    1573                 : 
    1574               0 :   if (SECSuccess != 
    1575               0 :       PK11_DigestOp(context, der_request->data, der_request->len))
    1576               0 :     return NS_ERROR_FAILURE;
    1577                 : 
    1578               0 :   SECItem *result_hmac_sha1_item = NULL;
    1579               0 :   SECItemCleanerTrueParam result_hmac_sha1_item_cleaner(result_hmac_sha1_item);
    1580                 : 
    1581               0 :   result_hmac_sha1_item = SECITEM_AllocItem(nsnull, nsnull, SHA1_LENGTH);
    1582               0 :   if (!result_hmac_sha1_item)
    1583               0 :     return NS_ERROR_FAILURE;
    1584                 : 
    1585               0 :   if (SECSuccess !=
    1586                 :       PK11_DigestFinal(context, 
    1587                 :                        result_hmac_sha1_item->data, 
    1588                 :                        &result_hmac_sha1_item->len, 
    1589               0 :                        SHA1_LENGTH))
    1590               0 :     return NS_ERROR_FAILURE;
    1591                 : 
    1592               0 :   if (SECSuccess !=
    1593                 :       CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
    1594               0 :                                         crmfNoSubseqMess, result_hmac_sha1_item))
    1595               0 :     return NS_ERROR_FAILURE;
    1596                 : 
    1597               0 :   return NS_OK;
    1598                 : }
    1599                 : 
    1600                 : static nsresult
    1601               0 : nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 
    1602                 :                        nsKeyPairInfo  *keyInfo,
    1603                 :                        CRMFCertRequest *certReq)
    1604                 : {
    1605                 :   // Depending on the type of cert request we'll try
    1606                 :   // POP mechanisms in different order,
    1607                 :   // and add the result to the cert request message.
    1608                 :   //
    1609                 :   // For any signing or dual use cert,
    1610                 :   //   try signing first,
    1611                 :   //   fall back to DHMAC if we can
    1612                 :   //     (EC cert requests that provide keygen param "popcert"),
    1613                 :   //   otherwise fail.
    1614                 :   //
    1615                 :   // For encryption only certs that get escrowed, this is sufficient.
    1616                 :   //
    1617                 :   // For encryption only certs, that are not being escrowed, 
    1618                 :   //   try DHMAC if we can 
    1619                 :   //     (EC cert requests that provide keygen param "popcert"),
    1620                 :   //   otherwise we'll indicate challenge response should be used.
    1621                 :   
    1622               0 :   bool isEncryptionOnlyCertRequest = false;
    1623               0 :   bool escrowEncryptionOnlyCert = false;
    1624                 :   
    1625               0 :   switch (keyInfo->keyGenType)
    1626                 :   {
    1627                 :     case rsaEnc:
    1628                 :     case ecEnc:
    1629               0 :       isEncryptionOnlyCertRequest = true;
    1630               0 :       break;
    1631                 :     
    1632                 :     case rsaSign:
    1633                 :     case rsaDualUse:
    1634                 :     case rsaNonrepudiation:
    1635                 :     case rsaSignNonrepudiation:
    1636                 :     case ecSign:
    1637                 :     case ecDualUse:
    1638                 :     case ecNonrepudiation:
    1639                 :     case ecSignNonrepudiation:
    1640                 :     case dsaSign:
    1641                 :     case dsaNonrepudiation:
    1642                 :     case dsaSignNonrepudiation:
    1643               0 :       break;
    1644                 :     
    1645                 :     case dhEx:
    1646                 :     /* This case may be supported in the future, but for now, we just fall 
    1647                 :       * though to the default case and return an error for diffie-hellman keys.
    1648                 :     */
    1649                 :     default:
    1650               0 :       return NS_ERROR_FAILURE;
    1651                 :   };
    1652                 :     
    1653               0 :   if (isEncryptionOnlyCertRequest)
    1654                 :   {
    1655                 :     escrowEncryptionOnlyCert = 
    1656               0 :       CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
    1657                 :   }
    1658                 :     
    1659               0 :   bool gotDHMACParameters = false;
    1660                 :   
    1661               0 :   if (isECKeyGenType(keyInfo->keyGenType) && 
    1662                 :       keyInfo->ecPopCert && 
    1663                 :       keyInfo->ecPopPubKey)
    1664                 :   {
    1665               0 :     gotDHMACParameters = true;
    1666                 :   }
    1667                 :   
    1668               0 :   if (isEncryptionOnlyCertRequest)
    1669                 :   {
    1670               0 :     if (escrowEncryptionOnlyCert)
    1671               0 :       return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
    1672                 :     
    1673               0 :     if (gotDHMACParameters)
    1674               0 :       return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
    1675                 :     
    1676               0 :     return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
    1677                 :   }
    1678                 :   
    1679                 :   // !isEncryptionOnlyCertRequest
    1680                 :   
    1681                 :   SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
    1682                 :                                                  keyInfo->privKey,
    1683                 :                                                  keyInfo->pubKey, nsnull,
    1684               0 :                                                  nsnull, nsnull);
    1685                 : 
    1686               0 :   if (srv == SECSuccess)
    1687               0 :     return NS_OK;
    1688                 :   
    1689               0 :   if (!gotDHMACParameters)
    1690               0 :     return NS_ERROR_FAILURE;
    1691                 :   
    1692               0 :   return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
    1693                 : }
    1694                 : 
    1695                 : static void PR_CALLBACK
    1696               0 : nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
    1697                 : {
    1698               0 :   unsigned long *count = (unsigned long *)arg;
    1699               0 :   *count += len;
    1700               0 : }
    1701                 : 
    1702                 : static void PR_CALLBACK
    1703               0 : nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
    1704                 : {
    1705               0 :   SECItem *dest = (SECItem *)arg;
    1706               0 :   memcpy(dest->data + dest->len, buf, len);
    1707               0 :   dest->len += len;
    1708               0 : }
    1709                 : 
    1710                 : static SECItem*
    1711               0 : nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
    1712                 : {
    1713               0 :   unsigned long len = 0;
    1714               0 :   if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
    1715                 :       != SECSuccess) {
    1716               0 :     return nsnull;
    1717                 :   }
    1718               0 :   SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
    1719               0 :   if (dest == nsnull) {
    1720               0 :     return nsnull;
    1721                 :   }
    1722               0 :   dest->type = siBuffer;
    1723               0 :   dest->data = (unsigned char *)PORT_Alloc(len);
    1724               0 :   if (dest->data == nsnull) {
    1725               0 :     PORT_Free(dest);
    1726               0 :     return nsnull;
    1727                 :   }
    1728               0 :   dest->len = 0;
    1729                 : 
    1730               0 :   if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
    1731                 :       != SECSuccess) {
    1732               0 :     SECITEM_FreeItem(dest, true);
    1733               0 :     return nsnull;
    1734                 :   }
    1735               0 :   return dest;
    1736                 : }
    1737                 : 
    1738                 : //Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
    1739                 : //requesting one or more certificates to be issued.  This function
    1740                 : //creates a single cert request per key pair and then appends it to
    1741                 : //a message that is ultimately sent off to a CA.
    1742                 : static char*
    1743               0 : nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, PRInt32 numRequests,
    1744                 :                         char *reqDN, char *regToken, char *authenticator,
    1745                 :                         nsNSSCertificate *wrappingCert) 
    1746                 : {
    1747                 :   // We'use the goto notation for clean-up purposes in this function
    1748                 :   // that calls the C API of NSS.
    1749                 :   PRInt32 i;
    1750                 :   // The ASN1 encoder in NSS wants the last entry in the array to be
    1751                 :   // NULL so that it knows when the last element is.
    1752               0 :   CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
    1753                 :   CRMFCertRequest *certReq;
    1754               0 :   if (!certReqMsgs)
    1755               0 :     return nsnull;
    1756               0 :   memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
    1757                 :   SECStatus srv;
    1758                 :   nsresult rv;
    1759                 :   SECItem *encodedReq;
    1760                 :   char *retString;
    1761               0 :   for (i=0; i<numRequests; i++) {
    1762                 :     certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
    1763               0 :                                     wrappingCert);
    1764               0 :     if (!certReq)
    1765               0 :       goto loser;
    1766                 : 
    1767               0 :     certReqMsgs[i] = CRMF_CreateCertReqMsg();
    1768               0 :     if (!certReqMsgs[i])
    1769               0 :       goto loser;
    1770               0 :     srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
    1771               0 :     if (srv != SECSuccess)
    1772               0 :       goto loser;
    1773                 : 
    1774               0 :     rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
    1775               0 :     if (NS_FAILED(rv))
    1776               0 :       goto loser;
    1777               0 :     CRMF_DestroyCertRequest(certReq);
    1778                 :   }
    1779               0 :   encodedReq = nsEncodeCertReqMessages(certReqMsgs);
    1780               0 :   nsFreeCertReqMessages(certReqMsgs, numRequests);
    1781                 : 
    1782               0 :   retString = NSSBase64_EncodeItem (nsnull, nsnull, 0, encodedReq);
    1783               0 :   SECITEM_FreeItem(encodedReq, true);
    1784               0 :   return retString;
    1785                 : loser:
    1786               0 :   nsFreeCertReqMessages(certReqMsgs,numRequests);
    1787               0 :   return nsnull;;
    1788                 : }
    1789                 : 
    1790                 : static nsISupports *
    1791               0 : GetISupportsFromContext(JSContext *cx)
    1792                 : {
    1793               0 :     if (JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
    1794               0 :         return static_cast<nsISupports *>(JS_GetContextPrivate(cx));
    1795                 : 
    1796               0 :     return nsnull;
    1797                 : }
    1798                 : 
    1799                 : //The top level method which is a member of nsIDOMCrypto
    1800                 : //for generate a base64 encoded CRMF request.
    1801                 : NS_IMETHODIMP
    1802               0 : nsCrypto::GenerateCRMFRequest(nsIDOMCRMFObject** aReturn)
    1803                 : {
    1804               0 :   nsNSSShutDownPreventionLock locker;
    1805               0 :   *aReturn = nsnull;
    1806                 :   nsresult nrv;
    1807               0 :   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &nrv));
    1808               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1809                 : 
    1810               0 :   nsAXPCNativeCallContext *ncc = nsnull;
    1811                 : 
    1812               0 :   nrv = xpc->GetCurrentNativeCallContext(&ncc);
    1813               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1814                 : 
    1815               0 :   if (!ncc)
    1816               0 :     return NS_ERROR_NOT_AVAILABLE;
    1817                 : 
    1818                 :   PRUint32 argc;
    1819                 : 
    1820               0 :   ncc->GetArgc(&argc);
    1821                 : 
    1822               0 :   jsval *argv = nsnull;
    1823                 : 
    1824               0 :   nrv = ncc->GetArgvPtr(&argv);
    1825               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1826                 : 
    1827                 :   JSContext *cx;
    1828                 : 
    1829               0 :   nrv = ncc->GetJSContext(&cx);
    1830               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1831                 : 
    1832               0 :   JSObject* script_obj = nsnull;
    1833               0 :   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    1834                 : 
    1835               0 :   JSAutoRequest ar(cx);
    1836                 : 
    1837                 :   /*
    1838                 :    * Get all of the parameters.
    1839                 :    */
    1840               0 :   if (argc < 5 || ((argc-5) % 3) != 0) {
    1841                 :     JS_ReportError(cx, "%s", "%s%s\n", JS_ERROR,
    1842               0 :                   "incorrect number of parameters");
    1843               0 :     return NS_ERROR_FAILURE;
    1844                 :   }
    1845                 :   
    1846               0 :   if (JSVAL_IS_NULL(argv[0])) {
    1847               0 :     JS_ReportError(cx, "%s%s\n", JS_ERROR, "no DN specified");
    1848               0 :     return NS_ERROR_FAILURE;
    1849                 :   }
    1850                 :   
    1851               0 :   JSString *jsString = JS_ValueToString(cx,argv[0]);
    1852               0 :   NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
    1853               0 :   argv[0] = STRING_TO_JSVAL(jsString);
    1854               0 :   JSAutoByteString reqDN(cx,jsString);
    1855               0 :   NS_ENSURE_TRUE(!!reqDN, NS_ERROR_OUT_OF_MEMORY);
    1856                 : 
    1857               0 :   JSAutoByteString regToken;
    1858               0 :   if (!JSVAL_IS_NULL(argv[1])) {
    1859               0 :     jsString = JS_ValueToString(cx, argv[1]);
    1860               0 :     NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
    1861               0 :     argv[1] = STRING_TO_JSVAL(jsString);
    1862               0 :     regToken.encode(cx, jsString);
    1863               0 :     NS_ENSURE_TRUE(!!regToken, NS_ERROR_OUT_OF_MEMORY);
    1864                 :   }
    1865               0 :   JSAutoByteString authenticator;
    1866               0 :   if (!JSVAL_IS_NULL(argv[2])) {
    1867               0 :     jsString      = JS_ValueToString(cx, argv[2]);
    1868               0 :     NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
    1869               0 :     argv[2] = STRING_TO_JSVAL(jsString);
    1870               0 :     authenticator.encode(cx, jsString);
    1871               0 :     NS_ENSURE_TRUE(!!authenticator, NS_ERROR_OUT_OF_MEMORY);
    1872                 :   }
    1873               0 :   JSAutoByteString eaCert;
    1874               0 :   if (!JSVAL_IS_NULL(argv[3])) {
    1875               0 :     jsString     = JS_ValueToString(cx, argv[3]);
    1876               0 :     NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
    1877               0 :     argv[3] = STRING_TO_JSVAL(jsString);
    1878               0 :     eaCert.encode(cx, jsString);
    1879               0 :     NS_ENSURE_TRUE(!!eaCert, NS_ERROR_OUT_OF_MEMORY);
    1880                 :   }
    1881               0 :   if (JSVAL_IS_NULL(argv[4])) {
    1882                 :     JS_ReportError(cx, "%s%s\n", JS_ERROR, "no completion "
    1883               0 :                    "function specified");
    1884               0 :     return NS_ERROR_FAILURE;
    1885                 :   }
    1886               0 :   jsString = JS_ValueToString(cx, argv[4]);
    1887               0 :   NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
    1888               0 :   argv[4] = STRING_TO_JSVAL(jsString);
    1889               0 :   JSAutoByteString jsCallback(cx, jsString);
    1890               0 :   NS_ENSURE_TRUE(!!jsCallback, NS_ERROR_OUT_OF_MEMORY);
    1891                 : 
    1892               0 :   nrv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx),
    1893                 :                         static_cast<nsIDOMCrypto *>(this),
    1894               0 :                         NS_GET_IID(nsIDOMCrypto), getter_AddRefs(holder));
    1895               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1896                 : 
    1897               0 :   nrv = holder->GetJSObject(&script_obj);
    1898               0 :   NS_ENSURE_SUCCESS(nrv, nrv);
    1899                 : 
    1900                 :   //Put up some UI warning that someone is trying to 
    1901                 :   //escrow the private key.
    1902                 :   //Don't addref this copy.  That way ths reference goes away
    1903                 :   //at the same the nsIX09Cert ref goes away.
    1904               0 :   nsNSSCertificate *escrowCert = nsnull;
    1905               0 :   nsCOMPtr<nsIX509Cert> nssCert;
    1906               0 :   bool willEscrow = false;
    1907               0 :   if (!!eaCert) {
    1908               0 :     SECItem certDer = {siBuffer, nsnull, 0};
    1909               0 :     SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, eaCert.ptr());
    1910               0 :     if (srv != SECSuccess) {
    1911               0 :       return NS_ERROR_FAILURE;
    1912                 :     }
    1913                 :     CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
    1914                 :                                                     &certDer, nsnull, false,
    1915               0 :                                                     true);
    1916               0 :     if (!cert)
    1917               0 :       return NS_ERROR_FAILURE;
    1918                 : 
    1919               0 :     escrowCert = nsNSSCertificate::Create(cert);
    1920               0 :     CERT_DestroyCertificate(cert);
    1921               0 :     nssCert = escrowCert;
    1922               0 :     if (!nssCert)
    1923               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1924                 : 
    1925               0 :     nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
    1926               0 :     nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
    1927                 :                                 NS_GET_IID(nsIDOMCryptoDialogs),
    1928               0 :                                 NS_DOMCRYPTODIALOGS_CONTRACTID);
    1929               0 :     if (NS_FAILED(rv))
    1930               0 :       return rv;
    1931                 : 
    1932               0 :     bool okay=false;
    1933                 :     {
    1934               0 :       nsPSMUITracker tracker;
    1935               0 :       if (tracker.isUIForbidden()) {
    1936               0 :         okay = false;
    1937                 :       }
    1938                 :       else {
    1939               0 :         dialogs->ConfirmKeyEscrow(nssCert, &okay);
    1940                 :       }
    1941                 :     }
    1942               0 :     if (!okay)
    1943               0 :       return NS_OK;
    1944               0 :     willEscrow = true;
    1945                 :   }
    1946               0 :   nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
    1947               0 :   PRInt32 numRequests = (argc - 5)/3;
    1948               0 :   nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
    1949               0 :   if (keyids == nsnull) {
    1950               0 :     JS_ReportError(cx, "%s\n", JS_ERROR_INTERNAL);
    1951               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1952                 :   }
    1953               0 :   memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
    1954                 :   int keyInfoIndex;
    1955                 :   PRUint32 i;
    1956               0 :   PK11SlotInfo *slot = nsnull;
    1957                 :   // Go through all of the arguments and generate the appropriate key pairs.
    1958               0 :   for (i=5,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
    1959                 :     nrv = cryptojs_ReadArgsAndGenerateKey(cx, &argv[i], &keyids[keyInfoIndex],
    1960               0 :                                          uiCxt, &slot, willEscrow);
    1961                 :                                        
    1962               0 :     if (NS_FAILED(nrv)) {
    1963               0 :       if (slot)
    1964               0 :         PK11_FreeSlot(slot);
    1965               0 :       nsFreeKeyPairInfo(keyids,numRequests);
    1966               0 :       return nrv;
    1967                 :     }
    1968                 :   }
    1969                 :   // By this time we'd better have a slot for the key gen.
    1970               0 :   NS_ASSERTION(slot, "There was no slot selected for key generation");
    1971               0 :   if (slot) 
    1972               0 :     PK11_FreeSlot(slot);
    1973                 : 
    1974                 :   char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
    1975                 :                                                  reqDN.ptr(),regToken.ptr(),
    1976                 :                                                  authenticator.ptr(),
    1977               0 :                                                  escrowCert);
    1978                 : #ifdef DEBUG_javi
    1979                 :   printf ("Created the folloing CRMF request:\n%s\n", encodedRequest);
    1980                 : #endif
    1981               0 :   if (!encodedRequest) {
    1982               0 :     nsFreeKeyPairInfo(keyids, numRequests);
    1983               0 :     return NS_ERROR_FAILURE;
    1984                 :   }                                                    
    1985               0 :   nsCRMFObject *newObject = new nsCRMFObject();
    1986               0 :   if (newObject == nsnull) {
    1987               0 :     JS_ReportError(cx, "%s%s\n", JS_ERROR, "could not create crmf JS object");
    1988                 : 
    1989               0 :     nsFreeKeyPairInfo(keyids,numRequests);
    1990               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1991                 :   }
    1992               0 :   newObject->SetCRMFRequest(encodedRequest);
    1993               0 :   *aReturn = newObject;
    1994                 :   //Give a reference to the returnee.
    1995               0 :   NS_ADDREF(*aReturn);
    1996               0 :   nsFreeKeyPairInfo(keyids, numRequests);
    1997                 : 
    1998                 :   // 
    1999                 :   // Post an event on the UI queue so that the JS gets called after
    2000                 :   // we return control to the JS layer.  Why do we have to this?
    2001                 :   // Because when this API was implemented for PSM 1.x w/ Communicator,
    2002                 :   // the only way to make this method work was to have a callback
    2003                 :   // in the JS layer that got called after key generation had happened.
    2004                 :   // So for backwards compatibility, we return control and then just post
    2005                 :   // an event to call the JS the script provides as the code to execute
    2006                 :   // when the request has been generated.
    2007                 :   //
    2008                 : 
    2009                 : 
    2010                 :   nsCOMPtr<nsIScriptSecurityManager> secMan =
    2011               0 :     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
    2012               0 :   NS_ENSURE_TRUE(secMan, NS_ERROR_UNEXPECTED);
    2013                 :   
    2014               0 :   nsCOMPtr<nsIPrincipal> principals;
    2015               0 :   nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals));
    2016               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2017               0 :   NS_ENSURE_TRUE(principals, NS_ERROR_UNEXPECTED);
    2018                 :   
    2019               0 :   nsCryptoRunArgs *args = new nsCryptoRunArgs();
    2020               0 :   if (!args)
    2021               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2022                 : 
    2023               0 :   args->m_cx         = cx;
    2024               0 :   args->m_kungFuDeathGrip = GetISupportsFromContext(cx);
    2025               0 :   args->m_scope      = JS_GetParent(script_obj);
    2026                 : 
    2027               0 :   args->m_jsCallback.Adopt(!!jsCallback ? nsCRT::strdup(jsCallback.ptr()) : 0);
    2028               0 :   args->m_principals = principals;
    2029                 :   
    2030               0 :   nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args);
    2031               0 :   if (!cryptoRunnable)
    2032               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2033                 : 
    2034               0 :   rv = NS_DispatchToMainThread(cryptoRunnable);
    2035               0 :   if (NS_FAILED(rv))
    2036               0 :     delete cryptoRunnable;
    2037                 : 
    2038               0 :   return rv;
    2039                 : }
    2040                 : 
    2041                 : 
    2042                 : // Reminder that we inherit the memory passed into us here.
    2043                 : // An implementation to let us back up certs as an event.
    2044               0 : nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, PRInt32 numCerts,
    2045               0 :                              nsIPK11Token *token)
    2046                 : {
    2047               0 :   mCertArr  = certArr;
    2048               0 :   mNumCerts = numCerts;
    2049               0 :   mToken = token;
    2050               0 : }
    2051                 : 
    2052               0 : nsP12Runnable::~nsP12Runnable()
    2053                 : {
    2054                 :   PRInt32 i;
    2055               0 :   for (i=0; i<mNumCerts; i++) {
    2056               0 :       NS_IF_RELEASE(mCertArr[i]);
    2057                 :   }
    2058               0 :   delete []mCertArr;
    2059               0 : }
    2060                 : 
    2061                 : 
    2062                 : //Implementation that backs cert(s) into a PKCS12 file
    2063                 : NS_IMETHODIMP
    2064               0 : nsP12Runnable::Run()
    2065                 : {
    2066               0 :   NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
    2067                 : 
    2068               0 :   nsNSSShutDownPreventionLock locker;
    2069               0 :   NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
    2070                 : 
    2071               0 :   nsString final;
    2072               0 :   nsString temp;
    2073                 :   nsresult rv;
    2074                 : 
    2075               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
    2076               0 :   if (NS_FAILED(rv))
    2077               0 :     return rv;
    2078                 : 
    2079                 :   //Build up the message that let's the user know we're trying to 
    2080                 :   //make PKCS12 backups of the new certs.
    2081               0 :   nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
    2082               0 :   final.Append(NS_LITERAL_STRING("\n\n").get());
    2083               0 :   nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
    2084               0 :   final.Append(temp.get());
    2085               0 :   final.Append(NS_LITERAL_STRING("\n\n").get());
    2086                 : 
    2087               0 :   nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
    2088                 : 
    2089               0 :   final.Append(temp.get());
    2090               0 :   nsNSSComponent::ShowAlertWithConstructedString(final);
    2091                 : 
    2092                 :   nsCOMPtr<nsIFilePicker> filePicker = 
    2093               0 :                         do_CreateInstance("@mozilla.org/filepicker;1", &rv);
    2094               0 :   if (!filePicker) {
    2095               0 :     NS_ERROR("Could not create a file picker when backing up certs.");
    2096               0 :     return rv;
    2097                 :   }
    2098                 : 
    2099                 :   nsCOMPtr<nsIWindowWatcher> wwatch =
    2100               0 :     (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
    2101               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2102                 : 
    2103               0 :   nsCOMPtr<nsIDOMWindow> window;
    2104               0 :   wwatch->GetActiveWindow(getter_AddRefs(window));
    2105                 : 
    2106               0 :   nsString filePickMessage;
    2107               0 :   nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
    2108               0 :                                       filePickMessage);
    2109               0 :   rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
    2110               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2111                 : 
    2112               0 :   filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
    2113               0 :                            NS_LITERAL_STRING("*.p12"));
    2114               0 :   filePicker->AppendFilters(nsIFilePicker::filterAll);
    2115                 : 
    2116                 :   PRInt16 dialogReturn;
    2117               0 :   filePicker->Show(&dialogReturn);
    2118               0 :   if (dialogReturn == nsIFilePicker::returnCancel)
    2119               0 :     return NS_OK;  //User canceled.  It'd be nice if they couldn't, 
    2120                 :                    //but oh well.
    2121                 : 
    2122               0 :   nsCOMPtr<nsILocalFile> localFile;
    2123               0 :   rv = filePicker->GetFile(getter_AddRefs(localFile));
    2124               0 :   if (NS_FAILED(rv))
    2125               0 :     return NS_ERROR_FAILURE;
    2126                 : 
    2127               0 :   nsPKCS12Blob p12Cxt;
    2128                 :   
    2129               0 :   p12Cxt.SetToken(mToken);
    2130               0 :   p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
    2131               0 :   return NS_OK;
    2132                 : }
    2133                 : 
    2134               0 : nsCryptoRunArgs::nsCryptoRunArgs() 
    2135                 : {
    2136               0 : }
    2137               0 : nsCryptoRunArgs::~nsCryptoRunArgs() {}
    2138                 : 
    2139                 : 
    2140               0 : nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
    2141                 : {
    2142               0 :   nsNSSShutDownPreventionLock locker;
    2143               0 :   NS_ASSERTION(args,"Passed nsnull to nsCryptoRunnable constructor.");
    2144               0 :   m_args = args;
    2145               0 :   NS_IF_ADDREF(m_args);
    2146               0 :   JS_AddNamedObjectRoot(args->m_cx, &args->m_scope,"nsCryptoRunnable::mScope");
    2147               0 : }
    2148                 : 
    2149               0 : nsCryptoRunnable::~nsCryptoRunnable()
    2150                 : {
    2151               0 :   nsNSSShutDownPreventionLock locker;
    2152                 : 
    2153                 :   {
    2154               0 :     JSAutoRequest ar(m_args->m_cx);
    2155               0 :     JS_RemoveObjectRoot(m_args->m_cx, &m_args->m_scope);
    2156                 :   }
    2157                 : 
    2158               0 :   NS_IF_RELEASE(m_args);
    2159               0 : }
    2160                 : 
    2161                 : //Implementation that runs the callback passed to 
    2162                 : //crypto.generateCRMFRequest as an event.
    2163                 : NS_IMETHODIMP
    2164               0 : nsCryptoRunnable::Run()
    2165                 : {
    2166               0 :   nsNSSShutDownPreventionLock locker;
    2167               0 :   JSContext *cx = m_args->m_cx;
    2168                 : 
    2169               0 :   JSAutoRequest ar(cx);
    2170               0 :   JSAutoEnterCompartment ac;
    2171                 : 
    2172               0 :   if (!ac.enter(cx, m_args->m_scope)) {
    2173               0 :     return NS_ERROR_FAILURE;
    2174                 :   }
    2175                 : 
    2176                 :   // make sure the right context is on the stack. must not return w/out popping
    2177               0 :   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
    2178               0 :   if (!stack || NS_FAILED(stack->Push(cx))) {
    2179               0 :     return NS_ERROR_FAILURE;
    2180                 :   }
    2181                 : 
    2182                 :   JSBool ok =
    2183                 :     JS_EvaluateScriptForPrincipals(cx, m_args->m_scope,
    2184               0 :                                    nsJSPrincipals::get(m_args->m_principals),
    2185                 :                                    m_args->m_jsCallback, 
    2186                 :                                    strlen(m_args->m_jsCallback),
    2187               0 :                                    nsnull, 0, nsnull);
    2188               0 :   stack->Pop(nsnull);
    2189               0 :   return ok ? NS_OK : NS_ERROR_FAILURE;
    2190                 : }
    2191                 : 
    2192                 : //Quick helper function to check if a newly issued cert
    2193                 : //already exists in the user's database.
    2194                 : static bool
    2195               0 : nsCertAlreadyExists(SECItem *derCert)
    2196                 : {
    2197               0 :   CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
    2198                 :   CERTCertificate *cert;
    2199               0 :   bool retVal = false;
    2200                 : 
    2201               0 :   cert = CERT_FindCertByDERCert(handle, derCert);
    2202               0 :   if (cert) {
    2203               0 :     if (cert->isperm && !cert->nickname && !cert->emailAddr) {
    2204                 :       //If the cert doesn't have a nickname or email addr, it is
    2205                 :       //bogus cruft, so delete it.
    2206               0 :       SEC_DeletePermCertificate(cert);
    2207               0 :     } else if (cert->isperm) {
    2208               0 :       retVal = true;
    2209                 :     }
    2210               0 :     CERT_DestroyCertificate(cert);
    2211                 :   }
    2212               0 :   return retVal;
    2213                 : }
    2214                 : 
    2215                 : static PRInt32
    2216               0 : nsCertListCount(CERTCertList *certList)
    2217                 : {
    2218               0 :   PRInt32 numCerts = 0;
    2219                 :   CERTCertListNode *node;
    2220                 : 
    2221               0 :   node = CERT_LIST_HEAD(certList);
    2222               0 :   while (!CERT_LIST_END(node, certList)) {
    2223               0 :     numCerts++;
    2224               0 :     node = CERT_LIST_NEXT(node);
    2225                 :   }
    2226               0 :   return numCerts;
    2227                 : }
    2228                 : 
    2229                 : 
    2230                 : //Import user certificates that arrive as a CMMF base64 encoded
    2231                 : //string.
    2232                 : NS_IMETHODIMP
    2233               0 : nsCrypto::ImportUserCertificates(const nsAString& aNickname, 
    2234                 :                                  const nsAString& aCmmfResponse, 
    2235                 :                                  bool aDoForcedBackup, 
    2236                 :                                  nsAString& aReturn)
    2237                 : {
    2238               0 :   nsNSSShutDownPreventionLock locker;
    2239               0 :   char *nickname=nsnull, *cmmfResponse=nsnull;
    2240               0 :   CMMFCertRepContent *certRepContent = nsnull;
    2241               0 :   int numResponses = 0;
    2242               0 :   nsIX509Cert **certArr = nsnull;
    2243                 :   int i;
    2244                 :   CMMFCertResponse *currResponse;
    2245                 :   CMMFPKIStatus reqStatus;
    2246                 :   CERTCertificate *currCert;
    2247                 :   PK11SlotInfo *slot;
    2248               0 :   nsCAutoString localNick;
    2249               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
    2250               0 :   nsresult rv = NS_OK;
    2251               0 :   CERTCertList *caPubs = nsnull;
    2252               0 :   nsCOMPtr<nsIPK11Token> token;
    2253                 : 
    2254               0 :   nickname = ToNewCString(aNickname);
    2255               0 :   cmmfResponse = ToNewCString(aCmmfResponse);
    2256               0 :   if (nsCRT::strcmp("null", nickname) == 0) {
    2257               0 :     nsMemory::Free(nickname);
    2258               0 :     nickname = nsnull;
    2259                 :   }
    2260                 : 
    2261               0 :   SECItem cmmfDer = {siBuffer, nsnull, 0};
    2262               0 :   SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
    2263                 : 
    2264               0 :   if (srv != SECSuccess) {
    2265               0 :     rv = NS_ERROR_FAILURE;
    2266               0 :     goto loser;
    2267                 :   }
    2268                 : 
    2269                 :   certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
    2270                 :                                                     (const char*)cmmfDer.data,
    2271               0 :                                                     cmmfDer.len);
    2272               0 :   if (!certRepContent) {
    2273               0 :     rv = NS_ERROR_FAILURE;
    2274               0 :     goto loser;
    2275                 :   }
    2276                 : 
    2277               0 :   numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
    2278                 : 
    2279               0 :   if (aDoForcedBackup) {
    2280                 :     //We've been asked to force the user to back up these
    2281                 :     //certificates.  Let's keep an array of them around which
    2282                 :     //we pass along to the nsP12Runnable to use.
    2283               0 :     certArr = new nsIX509Cert*[numResponses];
    2284                 :     // If this is NULL, chances are we're gonna fail really soon,
    2285                 :     // but let's try to keep going just in case.
    2286               0 :     if (!certArr)
    2287               0 :       aDoForcedBackup = false;
    2288                 : 
    2289               0 :     memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
    2290                 :   }
    2291               0 :   for (i=0; i<numResponses; i++) {
    2292               0 :     currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
    2293               0 :     if (!currResponse) {
    2294               0 :       rv = NS_ERROR_FAILURE;
    2295               0 :       goto loser;
    2296                 :     }
    2297               0 :     reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
    2298               0 :     if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
    2299                 :       // The CA didn't give us the cert we requested.
    2300               0 :       rv = NS_ERROR_FAILURE;
    2301               0 :       goto loser;
    2302                 :     }
    2303                 :     currCert = CMMF_CertResponseGetCertificate(currResponse, 
    2304               0 :                                                CERT_GetDefaultCertDB());
    2305               0 :     if (!currCert) {
    2306               0 :       rv = NS_ERROR_FAILURE;
    2307               0 :       goto loser;
    2308                 :     }
    2309                 : 
    2310               0 :     if (nsCertAlreadyExists(&currCert->derCert)) {
    2311               0 :       if (aDoForcedBackup) {
    2312               0 :         certArr[i] = nsNSSCertificate::Create(currCert);
    2313               0 :         if (!certArr[i])
    2314               0 :           goto loser;
    2315               0 :         NS_ADDREF(certArr[i]);
    2316                 :       }
    2317               0 :       CERT_DestroyCertificate(currCert);
    2318               0 :       CMMF_DestroyCertResponse(currResponse);
    2319               0 :       continue;
    2320                 :     }
    2321                 :     // Let's figure out which nickname to give the cert.  If 
    2322                 :     // a certificate with the same subject name already exists,
    2323                 :     // then just use that one, otherwise, get the default nickname.
    2324               0 :     if (currCert->nickname) {
    2325               0 :       localNick = currCert->nickname;
    2326                 :     }
    2327               0 :     else if (nickname == nsnull || nickname[0] == '\0') {
    2328               0 :       nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick);
    2329                 :     } else {
    2330                 :       //This is the case where we're getting a brand new
    2331                 :       //cert that doesn't have the same subjectName as a cert
    2332                 :       //that already exists in our db and the CA page has 
    2333                 :       //designated a nickname to use for the newly issued cert.
    2334               0 :       localNick = nickname;
    2335                 :     }
    2336                 :     {
    2337               0 :       char *cast_const_away = const_cast<char*>(localNick.get());
    2338               0 :       slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
    2339                 :     }
    2340               0 :     if (slot == nsnull) {
    2341               0 :       rv = NS_ERROR_FAILURE;
    2342               0 :       goto loser;
    2343                 :     }
    2344               0 :     if (aDoForcedBackup) {
    2345               0 :       certArr[i] = nsNSSCertificate::Create(currCert);
    2346               0 :       if (!certArr[i])
    2347               0 :         goto loser;
    2348               0 :       NS_ADDREF(certArr[i]);
    2349                 :     }
    2350               0 :     CERT_DestroyCertificate(currCert);
    2351                 : 
    2352               0 :     if (!token)
    2353               0 :       token = new nsPK11Token(slot);
    2354                 : 
    2355               0 :     PK11_FreeSlot(slot);
    2356               0 :     CMMF_DestroyCertResponse(currResponse);
    2357                 :   }
    2358                 :   //Let the loser: label take care of freeing up our reference to
    2359                 :   //nickname (This way we don't free it twice and avoid crashing.
    2360                 :   //That would be a good thing.
    2361                 : 
    2362                 :   //Import the root chain into the cert db.
    2363               0 :   caPubs = CMMF_CertRepContentGetCAPubs(certRepContent);
    2364               0 :   if (caPubs) {
    2365               0 :     PRInt32 numCAs = nsCertListCount(caPubs);
    2366                 :     
    2367               0 :     NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
    2368               0 :     if (numCAs > 0) {
    2369                 :       CERTCertListNode *node;
    2370                 :       SECItem *derCerts;
    2371                 : 
    2372                 :       derCerts = static_cast<SECItem*>
    2373               0 :                             (nsMemory::Alloc(sizeof(SECItem)*numCAs));
    2374               0 :       if (!derCerts) {
    2375               0 :         rv = NS_ERROR_OUT_OF_MEMORY;
    2376               0 :         goto loser;
    2377                 :       }
    2378               0 :       for (node = CERT_LIST_HEAD(caPubs), i=0; 
    2379               0 :            !CERT_LIST_END(node, caPubs);
    2380                 :            node = CERT_LIST_NEXT(node), i++) {
    2381               0 :         derCerts[i] = node->cert->derCert;
    2382                 :       }
    2383               0 :       nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx);
    2384               0 :       nsMemory::Free(derCerts);
    2385                 :     }
    2386                 :     
    2387               0 :     CERT_DestroyCertList(caPubs);
    2388                 :   }
    2389                 : 
    2390               0 :   if (aDoForcedBackup) {
    2391                 :     // I can't pop up a file picker from the depths of JavaScript,
    2392                 :     // so I'll just post an event on the UI queue to do the backups
    2393                 :     // later.
    2394                 :     nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
    2395               0 :                                                           token);
    2396               0 :     if (!p12Runnable) {
    2397               0 :       rv = NS_ERROR_FAILURE;
    2398                 :       goto loser;
    2399                 :     }
    2400                 : 
    2401                 :     // null out the certArr pointer which has now been inherited by
    2402                 :     // the nsP12Runnable instance so that we don't free up the
    2403                 :     // memory on the way out.
    2404               0 :     certArr = nsnull;
    2405                 : 
    2406               0 :     rv = NS_DispatchToMainThread(p12Runnable);
    2407               0 :     if (NS_FAILED(rv))
    2408                 :       goto loser;
    2409                 :   }
    2410                 : 
    2411                 :  loser:
    2412               0 :   if (certArr) {
    2413               0 :     for (i=0; i<numResponses; i++) {
    2414               0 :       NS_IF_RELEASE(certArr[i]);
    2415                 :     }
    2416               0 :     delete []certArr;
    2417                 :   }
    2418               0 :   aReturn.Assign(EmptyString());
    2419               0 :   if (nickname) {
    2420               0 :     NS_Free(nickname);
    2421                 :   }
    2422               0 :   if (cmmfResponse) {
    2423               0 :     NS_Free(cmmfResponse);
    2424                 :   }
    2425               0 :   if (certRepContent) {
    2426               0 :     CMMF_DestroyCertRepContent(certRepContent);
    2427                 :   }
    2428               0 :   return rv;
    2429                 : }
    2430                 : 
    2431                 : NS_IMETHODIMP
    2432               0 : nsCrypto::PopChallengeResponse(const nsAString& aChallenge, 
    2433                 :                                nsAString& aReturn)
    2434                 : {
    2435               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    2436                 : }
    2437                 : 
    2438                 : NS_IMETHODIMP
    2439               0 : nsCrypto::Random(PRInt32 aNumBytes, nsAString& aReturn)
    2440                 : {
    2441               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    2442                 : }
    2443                 : 
    2444                 : static void
    2445               0 : GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
    2446                 : {
    2447                 :   // Get the script context.
    2448               0 :   nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
    2449               0 :   if (!scriptContext) {
    2450               0 :     return;
    2451                 :   }
    2452                 : 
    2453                 :   nsCOMPtr<nsIDOMWindow> domWindow = 
    2454               0 :     do_QueryInterface(scriptContext->GetGlobalObject());
    2455               0 :   if (!domWindow) {
    2456                 :     return;
    2457                 :   }
    2458                 : 
    2459               0 :   nsCOMPtr<nsIDOMDocument> domDocument;
    2460               0 :   domWindow->GetDocument(getter_AddRefs(domDocument));
    2461               0 :   if (!domDocument) {
    2462                 :     return;
    2463                 :   }
    2464                 : 
    2465               0 :   CallQueryInterface(domDocument, aDocument);
    2466                 : 
    2467                 :   return;
    2468                 : }
    2469                 : 
    2470               0 : void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
    2471                 : {
    2472               0 :   ((nsCString*)arg)->Append(buf, len);
    2473               0 : }
    2474                 : 
    2475                 : NS_IMETHODIMP
    2476               0 : nsCrypto::SignText(const nsAString& aStringToSign, const nsAString& aCaOption,
    2477                 :                    nsAString& aResult)
    2478                 : {
    2479                 :   // XXX This code should return error codes, but we're keeping this
    2480                 :   //     backwards compatible with NS4.x and so we can't throw exceptions.
    2481               0 :   NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
    2482                 : 
    2483               0 :   aResult.Truncate();
    2484                 : 
    2485               0 :   nsAXPCNativeCallContext* ncc = nsnull;
    2486               0 :   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
    2487               0 :   if (xpc) {
    2488               0 :     xpc->GetCurrentNativeCallContext(&ncc);
    2489                 :   }
    2490                 : 
    2491               0 :   if (!ncc) {
    2492               0 :     aResult.Append(internalError);
    2493                 : 
    2494               0 :     return NS_OK;
    2495                 :   }
    2496                 : 
    2497                 :   PRUint32 argc;
    2498               0 :   ncc->GetArgc(&argc);
    2499                 : 
    2500                 :   JSContext *cx;
    2501               0 :   ncc->GetJSContext(&cx);
    2502               0 :   if (!cx) {
    2503               0 :     aResult.Append(internalError);
    2504                 : 
    2505               0 :     return NS_OK;
    2506                 :   }
    2507                 : 
    2508               0 :   if (!aCaOption.EqualsLiteral("auto") &&
    2509               0 :       !aCaOption.EqualsLiteral("ask")) {
    2510               0 :     JS_ReportError(cx, "%s%s\n", JS_ERROR, "caOption argument must be ask or auto");
    2511                 : 
    2512               0 :     aResult.Append(internalError);
    2513                 : 
    2514               0 :     return NS_OK;
    2515                 :   }
    2516                 : 
    2517                 :   // It was decided to always behave as if "ask" were specified.
    2518                 :   // XXX Should we warn in the JS Console for auto?
    2519                 : 
    2520               0 :   nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
    2521               0 :   if (!uiContext) {
    2522               0 :     aResult.Append(internalError);
    2523                 : 
    2524               0 :     return NS_OK;
    2525                 :   }
    2526                 : 
    2527               0 :   bool bestOnly = true;
    2528               0 :   bool validOnly = true;
    2529                 :   CERTCertList* certList =
    2530                 :     CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
    2531               0 :                               bestOnly, validOnly, uiContext);
    2532                 : 
    2533               0 :   PRUint32 numCAs = argc - 2;
    2534               0 :   if (numCAs > 0) {
    2535               0 :     jsval *argv = nsnull;
    2536               0 :     ncc->GetArgvPtr(&argv);
    2537                 : 
    2538               0 :     nsAutoArrayPtr<JSAutoByteString> caNameBytes(new JSAutoByteString[numCAs]);
    2539               0 :     if (!caNameBytes) {
    2540               0 :       aResult.Append(internalError);
    2541               0 :       return NS_OK;
    2542                 :     }
    2543                 : 
    2544               0 :     JSAutoRequest ar(cx);
    2545                 : 
    2546                 :     PRUint32 i;
    2547               0 :     for (i = 2; i < argc; ++i) {
    2548               0 :       JSString *caName = JS_ValueToString(cx, argv[i]);
    2549               0 :       NS_ENSURE_TRUE(caName, NS_ERROR_OUT_OF_MEMORY);
    2550               0 :       argv[i] = STRING_TO_JSVAL(caName);
    2551               0 :       caNameBytes[i - 2].encode(cx, caName);
    2552               0 :       NS_ENSURE_TRUE(!!caNameBytes[i - 2], NS_ERROR_OUT_OF_MEMORY);
    2553                 :     }
    2554                 : 
    2555               0 :     nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
    2556               0 :     if (!caNames) {
    2557               0 :       aResult.Append(internalError);
    2558               0 :       return NS_OK;
    2559                 :     }
    2560                 : 
    2561               0 :     for (i = 0; i < numCAs; ++i)
    2562               0 :       caNames[i] = caNameBytes[i].ptr();
    2563                 : 
    2564               0 :     if (certList &&
    2565                 :         CERT_FilterCertListByCANames(certList, numCAs, caNames,
    2566               0 :                                      certUsageEmailSigner) != SECSuccess) {
    2567               0 :       aResult.Append(internalError);
    2568                 : 
    2569               0 :       return NS_OK;
    2570                 :     }
    2571                 :   }
    2572                 : 
    2573               0 :   if (!certList || CERT_LIST_EMPTY(certList)) {
    2574               0 :     aResult.AppendLiteral("error:noMatchingCert");
    2575                 : 
    2576               0 :     return NS_OK;
    2577                 :   }
    2578                 : 
    2579                 :   nsCOMPtr<nsIFormSigningDialog> fsd =
    2580               0 :     do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
    2581               0 :   if (!fsd) {
    2582               0 :     aResult.Append(internalError);
    2583                 : 
    2584               0 :     return NS_OK;
    2585                 :   }
    2586                 : 
    2587               0 :   nsCOMPtr<nsIDocument> document;
    2588               0 :   GetDocumentFromContext(cx, getter_AddRefs(document));
    2589               0 :   if (!document) {
    2590               0 :     aResult.Append(internalError);
    2591                 : 
    2592               0 :     return NS_OK;
    2593                 :   }
    2594                 : 
    2595                 :   // Get the hostname from the URL of the document.
    2596               0 :   nsIURI* uri = document->GetDocumentURI();
    2597               0 :   if (!uri) {
    2598               0 :     aResult.Append(internalError);
    2599                 : 
    2600               0 :     return NS_OK;
    2601                 :   }
    2602                 : 
    2603                 :   nsresult rv;
    2604                 : 
    2605               0 :   nsCString host;
    2606               0 :   rv = uri->GetHost(host);
    2607               0 :   if (NS_FAILED(rv)) {
    2608               0 :     aResult.Append(internalError);
    2609                 : 
    2610               0 :     return NS_OK;
    2611                 :   }
    2612                 : 
    2613               0 :   PRInt32 numberOfCerts = 0;
    2614                 :   CERTCertListNode* node;
    2615               0 :   for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
    2616                 :        node = CERT_LIST_NEXT(node)) {
    2617               0 :     ++numberOfCerts;
    2618                 :   }
    2619                 : 
    2620               0 :   CERTCertNicknames* nicknames = getNSSCertNicknamesFromCertList(certList);
    2621                 : 
    2622               0 :   if (!nicknames) {
    2623               0 :     aResult.Append(internalError);
    2624                 : 
    2625               0 :     return NS_OK;
    2626                 :   }
    2627                 : 
    2628               0 :   CERTCertNicknamesCleaner cnc(nicknames);
    2629                 : 
    2630               0 :   NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
    2631                 :                "nicknames->numnicknames != numberOfCerts");
    2632                 : 
    2633               0 :   nsAutoArrayPtr<PRUnichar*> certNicknameList(new PRUnichar*[nicknames->numnicknames * 2]);
    2634               0 :   if (!certNicknameList) {
    2635               0 :     aResult.Append(internalError);
    2636                 : 
    2637               0 :     return NS_OK;
    2638                 :   }
    2639                 : 
    2640               0 :   PRUnichar** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
    2641                 : 
    2642                 :   PRInt32 certsToUse;
    2643               0 :   for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
    2644               0 :        !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
    2645                 :        node = CERT_LIST_NEXT(node)) {
    2646               0 :     nsRefPtr<nsNSSCertificate> tempCert = nsNSSCertificate::Create(node->cert);
    2647               0 :     if (tempCert) {
    2648               0 :       nsAutoString nickWithSerial, details;
    2649               0 :       rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
    2650               0 :                                      nickWithSerial, details);
    2651               0 :       if (NS_SUCCEEDED(rv)) {
    2652               0 :         certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
    2653               0 :         if (certNicknameList[certsToUse]) {
    2654               0 :           certDetailsList[certsToUse] = ToNewUnicode(details);
    2655               0 :           if (!certDetailsList[certsToUse]) {
    2656               0 :             nsMemory::Free(certNicknameList[certsToUse]);
    2657               0 :             continue;
    2658                 :           }
    2659               0 :           ++certsToUse;
    2660                 :         }
    2661                 :       }
    2662                 :     }
    2663                 :   }
    2664                 : 
    2665               0 :   if (certsToUse == 0) {
    2666               0 :     aResult.Append(internalError);
    2667                 : 
    2668               0 :     return NS_OK;
    2669                 :   }
    2670                 : 
    2671               0 :   NS_ConvertUTF8toUTF16 utf16Host(host);
    2672                 : 
    2673               0 :   CERTCertificate *signingCert = nsnull;
    2674                 :   bool tryAgain, canceled;
    2675               0 :   nsAutoString password;
    2676               0 :   do {
    2677                 :     // Throw up the form signing confirmation dialog and get back the index
    2678                 :     // of the selected cert.
    2679               0 :     PRInt32 selectedIndex = -1;
    2680               0 :     rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
    2681               0 :                               const_cast<const PRUnichar**>(certNicknameList.get()),
    2682                 :                               const_cast<const PRUnichar**>(certDetailsList),
    2683                 :                               certsToUse, &selectedIndex, password,
    2684               0 :                               &canceled);
    2685               0 :     if (NS_FAILED(rv) || canceled) {
    2686               0 :       break; // out of tryAgain loop
    2687                 :     }
    2688                 : 
    2689               0 :     PRInt32 j = 0;
    2690               0 :     for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
    2691                 :          node = CERT_LIST_NEXT(node)) {
    2692               0 :       if (j == selectedIndex) {
    2693               0 :         signingCert = CERT_DupCertificate(node->cert);
    2694               0 :         break; // out of cert list iteration loop
    2695                 :       }
    2696               0 :       ++j;
    2697                 :     }
    2698                 : 
    2699               0 :     if (!signingCert) {
    2700               0 :       rv = NS_ERROR_FAILURE;
    2701               0 :       break; // out of tryAgain loop
    2702                 :     }
    2703                 : 
    2704               0 :     NS_ConvertUTF16toUTF8 pwUtf8(password);
    2705                 : 
    2706                 :     tryAgain =
    2707                 :       PK11_CheckUserPassword(signingCert->slot,
    2708               0 :                              const_cast<char *>(pwUtf8.get())) != SECSuccess;
    2709                 :     // XXX we should show an error dialog before retrying
    2710                 :   } while (tryAgain);
    2711                 : 
    2712                 :   PRInt32 k;
    2713               0 :   for (k = 0; k < certsToUse; ++k) {
    2714               0 :     nsMemory::Free(certNicknameList[k]);
    2715               0 :     nsMemory::Free(certDetailsList[k]);
    2716                 :   }
    2717                 : 
    2718               0 :   if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
    2719               0 :     aResult.Append(internalError);
    2720                 : 
    2721               0 :     return NS_OK;
    2722                 :   }
    2723                 : 
    2724               0 :   if (canceled) {
    2725               0 :     aResult.AppendLiteral("error:userCancel");
    2726                 : 
    2727               0 :     return NS_OK;
    2728                 :   }
    2729                 : 
    2730               0 :   SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
    2731               0 :   if (!privKey) {
    2732               0 :     aResult.Append(internalError);
    2733                 : 
    2734               0 :     return NS_OK;
    2735                 :   }
    2736                 : 
    2737               0 :   nsCAutoString charset(document->GetDocumentCharacterSet());
    2738                 : 
    2739                 :   // XXX Doing what nsFormSubmission::GetEncoder does (see
    2740                 :   //     http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
    2741               0 :   if (charset.EqualsLiteral("ISO-8859-1")) {
    2742               0 :     charset.AssignLiteral("windows-1252");
    2743                 :   }
    2744                 : 
    2745                 :   nsCOMPtr<nsISaveAsCharset> encoder =
    2746               0 :     do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
    2747               0 :   if (encoder) {
    2748               0 :     rv = encoder->Init(charset.get(),
    2749                 :                        (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
    2750                 :                        nsISaveAsCharset::attr_FallbackDecimalNCR),
    2751               0 :                        0);
    2752                 :   }
    2753                 : 
    2754               0 :   nsXPIDLCString buffer;
    2755               0 :   if (aStringToSign.Length() > 0) {
    2756               0 :     if (encoder && NS_SUCCEEDED(rv)) {
    2757               0 :       rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
    2758               0 :                             getter_Copies(buffer));
    2759               0 :       if (NS_FAILED(rv)) {
    2760               0 :         aResult.Append(internalError);
    2761                 : 
    2762               0 :         return NS_OK;
    2763                 :       }
    2764                 :     }
    2765                 :     else {
    2766               0 :       AppendUTF16toUTF8(aStringToSign, buffer);
    2767                 :     }
    2768                 :   }
    2769                 : 
    2770               0 :   HASHContext *hc = HASH_Create(HASH_AlgSHA1);
    2771               0 :   if (!hc) {
    2772               0 :     aResult.Append(internalError);
    2773                 : 
    2774               0 :     return NS_OK;
    2775                 :   }
    2776                 : 
    2777                 :   unsigned char hash[SHA1_LENGTH];
    2778                 : 
    2779                 :   SECItem digest;
    2780               0 :   digest.data = hash;
    2781                 : 
    2782               0 :   HASH_Begin(hc);
    2783               0 :   HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
    2784               0 :               buffer.Length());
    2785               0 :   HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
    2786               0 :   HASH_Destroy(hc);
    2787                 : 
    2788               0 :   nsCString p7;
    2789               0 :   SECStatus srv = SECFailure;
    2790                 : 
    2791                 :   SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
    2792                 :                                                        certUsageEmailSigner,
    2793                 :                                                        nsnull, SEC_OID_SHA1,
    2794               0 :                                                        &digest, nsnull, uiContext);
    2795               0 :   if (ci) {
    2796               0 :     srv = SEC_PKCS7IncludeCertChain(ci, nsnull);
    2797               0 :     if (srv == SECSuccess) {
    2798               0 :       srv = SEC_PKCS7AddSigningTime(ci);
    2799               0 :       if (srv == SECSuccess) {
    2800                 :         srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nsnull, nsnull,
    2801               0 :                               uiContext);
    2802                 :       }
    2803                 :     }
    2804                 : 
    2805               0 :     SEC_PKCS7DestroyContentInfo(ci);
    2806                 :   }
    2807                 : 
    2808               0 :   if (srv != SECSuccess) {
    2809               0 :     aResult.Append(internalError);
    2810                 : 
    2811               0 :     return NS_OK;
    2812                 :   }
    2813                 : 
    2814                 :   SECItem binary_item;
    2815                 :   binary_item.data = reinterpret_cast<unsigned char*>
    2816               0 :                                      (const_cast<char*>(p7.get()));
    2817               0 :   binary_item.len = p7.Length();
    2818                 : 
    2819               0 :   char *result = NSSBase64_EncodeItem(nsnull, nsnull, 0, &binary_item);
    2820               0 :   if (result) {
    2821               0 :     AppendASCIItoUTF16(result, aResult);
    2822                 :   }
    2823                 :   else {
    2824               0 :     aResult.Append(internalError);
    2825                 :   }
    2826                 : 
    2827               0 :   PORT_Free(result);
    2828                 : 
    2829               0 :   return NS_OK;
    2830                 : }
    2831                 : 
    2832                 : //Logout out of all installed PKCS11 tokens.
    2833                 : NS_IMETHODIMP
    2834               0 : nsCrypto::Logout()
    2835                 : {
    2836                 :   nsresult rv;
    2837               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
    2838               0 :   if (NS_FAILED(rv))
    2839               0 :     return rv;
    2840                 : 
    2841                 :   {
    2842               0 :     nsNSSShutDownPreventionLock locker;
    2843               0 :     PK11_LogoutAll();
    2844               0 :     SSL_ClearSessionCache();
    2845                 :   }
    2846                 : 
    2847               0 :   return nssComponent->LogoutAuthenticatedPK11();
    2848                 : }
    2849                 : 
    2850                 : NS_IMETHODIMP
    2851               0 : nsCrypto::DisableRightClick()
    2852                 : {
    2853               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    2854                 : }
    2855                 : 
    2856               0 : nsCRMFObject::nsCRMFObject()
    2857                 : {
    2858               0 : }
    2859                 : 
    2860               0 : nsCRMFObject::~nsCRMFObject()
    2861                 : {
    2862               0 : }
    2863                 : 
    2864                 : nsresult
    2865               0 : nsCRMFObject::init()
    2866                 : {
    2867               0 :   return NS_OK;
    2868                 : }
    2869                 : 
    2870                 : NS_IMETHODIMP
    2871               0 : nsCRMFObject::GetRequest(nsAString& aRequest)
    2872                 : {
    2873               0 :   aRequest.Assign(mBase64Request);
    2874               0 :   return NS_OK;
    2875                 : }
    2876                 : 
    2877                 : nsresult
    2878               0 : nsCRMFObject::SetCRMFRequest(char *inRequest)
    2879                 : {
    2880               0 :   mBase64Request.AssignWithConversion(inRequest);  
    2881               0 :   return NS_OK;
    2882                 : }
    2883                 : 
    2884               0 : nsPkcs11::nsPkcs11()
    2885                 : {
    2886               0 : }
    2887                 : 
    2888               0 : nsPkcs11::~nsPkcs11()
    2889                 : {
    2890               0 : }
    2891                 : 
    2892                 : //Quick function to confirm with the user.
    2893                 : bool
    2894               0 : confirm_user(const PRUnichar *message)
    2895                 : {
    2896               0 :   PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
    2897                 : 
    2898               0 :   nsCOMPtr<nsIPrompt> prompter;
    2899               0 :   (void) nsNSSComponent::GetNewPrompter(getter_AddRefs(prompter));
    2900                 : 
    2901               0 :   if (prompter) {
    2902               0 :     nsPSMUITracker tracker;
    2903               0 :     if (!tracker.isUIForbidden()) {
    2904                 :       // The actual value is irrelevant but we shouldn't be handing out
    2905                 :       // malformed JSBools to XPConnect.
    2906               0 :       bool checkState = false;
    2907               0 :       prompter->ConfirmEx(0, message,
    2908                 :                           (nsIPrompt::BUTTON_DELAY_ENABLE) +
    2909                 :                           (nsIPrompt::BUTTON_POS_1_DEFAULT) +
    2910                 :                           (nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0) +
    2911                 :                           (nsIPrompt::BUTTON_TITLE_CANCEL * nsIPrompt::BUTTON_POS_1),
    2912               0 :                           nsnull, nsnull, nsnull, nsnull, &checkState, &buttonPressed);
    2913                 :     }
    2914                 :   }
    2915                 : 
    2916               0 :   return (buttonPressed == 0);
    2917                 : }
    2918                 : 
    2919                 : //Delete a PKCS11 module from the user's profile.
    2920                 : NS_IMETHODIMP
    2921               0 : nsPkcs11::DeleteModule(const nsAString& aModuleName)
    2922                 : {
    2923               0 :   nsNSSShutDownPreventionLock locker;
    2924                 :   nsresult rv;
    2925               0 :   nsString errorMessage;
    2926                 : 
    2927               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
    2928               0 :   if (NS_FAILED(rv))
    2929               0 :     return rv;
    2930                 : 
    2931               0 :   if (aModuleName.IsEmpty()) {
    2932               0 :     return NS_ERROR_ILLEGAL_VALUE;
    2933                 :   }
    2934                 :   
    2935               0 :   char *modName = ToNewCString(aModuleName);
    2936                 :   PRInt32 modType;
    2937               0 :   SECStatus srv = SECMOD_DeleteModule(modName, &modType);
    2938               0 :   if (srv == SECSuccess) {
    2939               0 :     SECMODModule *module = SECMOD_FindModule(modName);
    2940               0 :     if (module) {
    2941               0 :       nssComponent->ShutdownSmartCardThread(module);
    2942               0 :       SECMOD_DestroyModule(module);
    2943                 :     }
    2944               0 :     rv = NS_OK;
    2945                 :   } else {
    2946               0 :     rv = NS_ERROR_FAILURE;
    2947                 :   }
    2948               0 :   NS_Free(modName);
    2949               0 :   return rv;
    2950                 : }
    2951                 : 
    2952                 : //Add a new PKCS11 module to the user's profile.
    2953                 : NS_IMETHODIMP
    2954               0 : nsPkcs11::AddModule(const nsAString& aModuleName, 
    2955                 :                     const nsAString& aLibraryFullPath, 
    2956                 :                     PRInt32 aCryptoMechanismFlags, 
    2957                 :                     PRInt32 aCipherFlags)
    2958                 : {
    2959               0 :   nsNSSShutDownPreventionLock locker;
    2960                 :   nsresult rv;
    2961               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
    2962                 : 
    2963               0 :   char *moduleName = ToNewCString(aModuleName);
    2964               0 :   char *fullPath   = ToNewCString(aLibraryFullPath);
    2965               0 :   PRUint32 mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
    2966               0 :   PRUint32 cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
    2967                 :   SECStatus srv = SECMOD_AddNewModule(moduleName, fullPath, 
    2968               0 :                                       mechFlags, cipherFlags);
    2969               0 :   if (srv == SECSuccess) {
    2970               0 :     SECMODModule *module = SECMOD_FindModule(moduleName);
    2971               0 :     if (module) {
    2972               0 :       nssComponent->LaunchSmartCardThread(module);
    2973               0 :       SECMOD_DestroyModule(module);
    2974                 :     }
    2975                 :   }
    2976                 : 
    2977               0 :   nsMemory::Free(moduleName);
    2978               0 :   nsMemory::Free(fullPath);
    2979                 : 
    2980                 :   // The error message we report to the user depends directly on 
    2981                 :   // what the return value for SEDMOD_AddNewModule is
    2982               0 :   switch (srv) {
    2983                 :   case SECSuccess:
    2984               0 :     return NS_OK;
    2985                 :   case SECFailure:
    2986               0 :     return NS_ERROR_FAILURE;
    2987                 :   case -2:
    2988               0 :     return NS_ERROR_ILLEGAL_VALUE;
    2989                 :   }
    2990               0 :   NS_ERROR("Bogus return value, this should never happen");
    2991               0 :   return NS_ERROR_FAILURE;
    2992                 : }
    2993                 : 

Generated by: LCOV version 1.7