security/manager/ssl/src/nsCrypto.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/src/nsCrypto.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2939 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +#include "nsCrypto.h"
    1.10 +#include "nsNSSComponent.h"
    1.11 +#include "secmod.h"
    1.12 +
    1.13 +#include "nsReadableUtils.h"
    1.14 +#include "nsCRT.h"
    1.15 +#include "nsXPIDLString.h"
    1.16 +#include "nsISaveAsCharset.h"
    1.17 +#include "nsNativeCharsetUtils.h"
    1.18 +#include "nsServiceManagerUtils.h"
    1.19 +
    1.20 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
    1.21 +#include "nsKeygenHandler.h"
    1.22 +#include "nsKeygenThread.h"
    1.23 +#include "nsNSSCertificate.h"
    1.24 +#include "nsNSSCertificateDB.h"
    1.25 +#include "nsPKCS12Blob.h"
    1.26 +#include "nsPK11TokenDB.h"
    1.27 +#include "nsThreadUtils.h"
    1.28 +#include "nsIServiceManager.h"
    1.29 +#include "nsIMemory.h"
    1.30 +#include "nsAlgorithm.h"
    1.31 +#include "prprf.h"
    1.32 +#include "nsDOMCID.h"
    1.33 +#include "nsIDOMWindow.h"
    1.34 +#include "nsIDOMClassInfo.h"
    1.35 +#include "nsIDOMDocument.h"
    1.36 +#include "nsIDocument.h"
    1.37 +#include "nsIScriptObjectPrincipal.h"
    1.38 +#include "nsIScriptContext.h"
    1.39 +#include "nsIScriptGlobalObject.h"
    1.40 +#include "nsContentUtils.h"
    1.41 +#include "nsCxPusher.h"
    1.42 +#include "nsDOMJSUtils.h"
    1.43 +#include "nsJSUtils.h"
    1.44 +#include "nsIXPConnect.h"
    1.45 +#include "nsIRunnable.h"
    1.46 +#include "nsIWindowWatcher.h"
    1.47 +#include "nsIPrompt.h"
    1.48 +#include "nsIFilePicker.h"
    1.49 +#include "nsJSPrincipals.h"
    1.50 +#include "nsJSUtils.h"
    1.51 +#include "nsIPrincipal.h"
    1.52 +#include "nsIScriptSecurityManager.h"
    1.53 +#include "nsIGenKeypairInfoDlg.h"
    1.54 +#include "nsIDOMCryptoDialogs.h"
    1.55 +#include "nsIFormSigningDialog.h"
    1.56 +#include "nsIContentSecurityPolicy.h"
    1.57 +#include "nsIURI.h"
    1.58 +#include "jsapi.h"
    1.59 +#include "js/OldDebugAPI.h"
    1.60 +#include <ctype.h>
    1.61 +#include "pk11func.h"
    1.62 +#include "keyhi.h"
    1.63 +#include "cryptohi.h"
    1.64 +#include "seccomon.h"
    1.65 +#include "secerr.h"
    1.66 +#include "sechash.h"
    1.67 +#include "crmf.h"
    1.68 +#include "pk11pqg.h"
    1.69 +#include "cmmf.h"
    1.70 +#include "nssb64.h"
    1.71 +#include "base64.h"
    1.72 +#include "cert.h"
    1.73 +#include "certdb.h"
    1.74 +#include "secmod.h"
    1.75 +#include "ScopedNSSTypes.h"
    1.76 +#include "pkix/pkixtypes.h"
    1.77 +
    1.78 +#include "ssl.h" // For SSL_ClearSessionCache
    1.79 +
    1.80 +#include "nsNSSCleaner.h"
    1.81 +
    1.82 +#include "nsNSSCertHelper.h"
    1.83 +#include <algorithm>
    1.84 +#include "nsWrapperCacheInlines.h"
    1.85 +#endif
    1.86 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
    1.87 +#include "mozilla/dom/CRMFObjectBinding.h"
    1.88 +#endif
    1.89 +
    1.90 +using namespace mozilla;
    1.91 +using namespace mozilla::dom;
    1.92 +
    1.93 +/*
    1.94 + * These are the most common error strings that are returned
    1.95 + * by the JavaScript methods in case of error.
    1.96 + */
    1.97 +
    1.98 +#define JS_ERROR       "error:"
    1.99 +#define JS_ERROR_INTERNAL  JS_ERROR"internalError"
   1.100 +
   1.101 +#undef REPORT_INCORRECT_NUM_ARGS
   1.102 +
   1.103 +#define JS_OK_ADD_MOD                      3
   1.104 +#define JS_OK_DEL_EXTERNAL_MOD             2
   1.105 +#define JS_OK_DEL_INTERNAL_MOD             1
   1.106 +
   1.107 +#define JS_ERR_INTERNAL                   -1
   1.108 +#define JS_ERR_USER_CANCEL_ACTION         -2
   1.109 +#define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
   1.110 +#define JS_ERR_DEL_MOD                    -4
   1.111 +#define JS_ERR_ADD_MOD                    -5
   1.112 +#define JS_ERR_BAD_MODULE_NAME            -6
   1.113 +#define JS_ERR_BAD_DLL_NAME               -7
   1.114 +#define JS_ERR_BAD_MECHANISM_FLAGS        -8
   1.115 +#define JS_ERR_BAD_CIPHER_ENABLE_FLAGS    -9
   1.116 +#define JS_ERR_ADD_DUPLICATE_MOD          -10
   1.117 +
   1.118 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
   1.119 +
   1.120 +NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
   1.121 +
   1.122 +/*
   1.123 + * This structure is used to store information for one key generation.
   1.124 + * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
   1.125 + * stores one of these structures for every key generation that happens.
   1.126 + * The information stored in this structure is then used to set some
   1.127 + * values in the CRMF request.
   1.128 + */
   1.129 +typedef enum {
   1.130 +  rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
   1.131 +  ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
   1.132 +  dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
   1.133 +} nsKeyGenType;
   1.134 +
   1.135 +bool isECKeyGenType(nsKeyGenType kgt)
   1.136 +{
   1.137 +  switch (kgt)
   1.138 +  {
   1.139 +    case ecEnc:
   1.140 +    case ecDualUse:
   1.141 +    case ecSign:
   1.142 +    case ecNonrepudiation:
   1.143 +    case ecSignNonrepudiation:
   1.144 +      return true;
   1.145 +    
   1.146 +    default:
   1.147 +      break;
   1.148 +  }
   1.149 +
   1.150 +  return false;
   1.151 +}
   1.152 +
   1.153 +typedef struct nsKeyPairInfoStr {
   1.154 +  SECKEYPublicKey  *pubKey;     /* The putlic key associated with gen'd 
   1.155 +                                   priv key. */
   1.156 +  SECKEYPrivateKey *privKey;    /* The private key we generated */ 
   1.157 +  nsKeyGenType      keyGenType; /* What type of key gen are we doing.*/
   1.158 +
   1.159 +  CERTCertificate *ecPopCert;
   1.160 +                   /* null: use signing for pop
   1.161 +                      other than null: a cert that defines EC keygen params
   1.162 +                                       and will be used for dhMac PoP. */
   1.163 +
   1.164 +  SECKEYPublicKey  *ecPopPubKey;
   1.165 +                   /* extracted public key from ecPopCert */
   1.166 +} nsKeyPairInfo;
   1.167 +
   1.168 +
   1.169 +//This class is just used to pass arguments
   1.170 +//to the nsCryptoRunnable event.
   1.171 +class nsCryptoRunArgs : public nsISupports {
   1.172 +public:
   1.173 +  nsCryptoRunArgs(JSContext *aCx);
   1.174 +  virtual ~nsCryptoRunArgs();
   1.175 +  nsCOMPtr<nsISupports> m_kungFuDeathGrip;
   1.176 +  JSContext *m_cx;
   1.177 +  JS::PersistentRooted<JSObject*> m_scope;
   1.178 +  nsCOMPtr<nsIPrincipal> m_principals;
   1.179 +  nsXPIDLCString m_jsCallback;
   1.180 +  NS_DECL_ISUPPORTS
   1.181 +};
   1.182 +
   1.183 +//This class is used to run the callback code
   1.184 +//passed to crypto.generateCRMFRequest
   1.185 +//We have to do that for backwards compatibility
   1.186 +//reasons w/ PSM 1.x and Communciator 4.x
   1.187 +class nsCryptoRunnable : public nsIRunnable {
   1.188 +public:
   1.189 +  nsCryptoRunnable(nsCryptoRunArgs *args);
   1.190 +  virtual ~nsCryptoRunnable();
   1.191 +
   1.192 +  NS_IMETHOD Run ();
   1.193 +  NS_DECL_ISUPPORTS
   1.194 +private:
   1.195 +  nsCryptoRunArgs *m_args;
   1.196 +};
   1.197 +
   1.198 +
   1.199 +//We're going to inherit the memory passed
   1.200 +//into us.
   1.201 +//This class backs up an array of certificates
   1.202 +//as an event.
   1.203 +class nsP12Runnable : public nsIRunnable {
   1.204 +public:
   1.205 +  nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, nsIPK11Token *token);
   1.206 +  virtual ~nsP12Runnable();
   1.207 +
   1.208 +  NS_IMETHOD Run();
   1.209 +  NS_DECL_ISUPPORTS
   1.210 +private:
   1.211 +  nsCOMPtr<nsIPK11Token> mToken;
   1.212 +  nsIX509Cert **mCertArr;
   1.213 +  int32_t       mNumCerts;
   1.214 +};
   1.215 +
   1.216 +// QueryInterface implementation for nsCrypto
   1.217 +NS_INTERFACE_MAP_BEGIN(nsCrypto)
   1.218 +  NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
   1.219 +NS_INTERFACE_MAP_END_INHERITING(mozilla::dom::Crypto)
   1.220 +
   1.221 +NS_IMPL_ADDREF_INHERITED(nsCrypto, mozilla::dom::Crypto)
   1.222 +NS_IMPL_RELEASE_INHERITED(nsCrypto, mozilla::dom::Crypto)
   1.223 +
   1.224 +// QueryInterface implementation for nsPkcs11
   1.225 +#endif // MOZ_DISABLE_CRYPTOLEGACY
   1.226 +
   1.227 +NS_INTERFACE_MAP_BEGIN(nsPkcs11)
   1.228 +  NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
   1.229 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.230 +NS_INTERFACE_MAP_END
   1.231 +
   1.232 +NS_IMPL_ADDREF(nsPkcs11)
   1.233 +NS_IMPL_RELEASE(nsPkcs11)
   1.234 +
   1.235 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
   1.236 +
   1.237 +// ISupports implementation for nsCryptoRunnable
   1.238 +NS_IMPL_ISUPPORTS(nsCryptoRunnable, nsIRunnable)
   1.239 +
   1.240 +// ISupports implementation for nsP12Runnable
   1.241 +NS_IMPL_ISUPPORTS(nsP12Runnable, nsIRunnable)
   1.242 +
   1.243 +// ISupports implementation for nsCryptoRunArgs
   1.244 +NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
   1.245 +
   1.246 +nsCrypto::nsCrypto() :
   1.247 +  mEnableSmartCardEvents(false)
   1.248 +{
   1.249 +}
   1.250 +
   1.251 +nsCrypto::~nsCrypto()
   1.252 +{
   1.253 +}
   1.254 +
   1.255 +void
   1.256 +nsCrypto::Init(nsIDOMWindow* aWindow)
   1.257 +{
   1.258 +  mozilla::dom::Crypto::Init(aWindow);
   1.259 +}
   1.260 +
   1.261 +void
   1.262 +nsCrypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv)
   1.263 +{
   1.264 +  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.265 +
   1.266 +  nsresult rv = NS_OK;
   1.267 +
   1.268 +  // this has the side effect of starting the nssComponent (and initializing
   1.269 +  // NSS) even if it isn't already going. Starting the nssComponent is a
   1.270 +  // prerequisite for getting smartCard events.
   1.271 +  if (aEnable) {
   1.272 +    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   1.273 +  }
   1.274 +
   1.275 +  if (NS_FAILED(rv)) {
   1.276 +    aRv.Throw(rv);
   1.277 +    return;
   1.278 +  }
   1.279 +
   1.280 +  mEnableSmartCardEvents = aEnable;
   1.281 +}
   1.282 +
   1.283 +NS_IMETHODIMP
   1.284 +nsCrypto::SetEnableSmartCardEvents(bool aEnable)
   1.285 +{
   1.286 +  ErrorResult rv;
   1.287 +  SetEnableSmartCardEvents(aEnable, rv);
   1.288 +  return rv.ErrorCode();
   1.289 +}
   1.290 +
   1.291 +bool
   1.292 +nsCrypto::EnableSmartCardEvents()
   1.293 +{
   1.294 +  return mEnableSmartCardEvents;
   1.295 +}
   1.296 +
   1.297 +NS_IMETHODIMP
   1.298 +nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
   1.299 +{
   1.300 +  *aEnable = EnableSmartCardEvents();
   1.301 +  return NS_OK;
   1.302 +}
   1.303 +
   1.304 +//A quick function to let us know if the key we're trying to generate
   1.305 +//can be escrowed.
   1.306 +static bool
   1.307 +ns_can_escrow(nsKeyGenType keyGenType)
   1.308 +{
   1.309 +  /* For now, we only escrow rsa-encryption and ec-encryption keys. */
   1.310 +  return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
   1.311 +}
   1.312 +
   1.313 +//Retrieve crypto.version so that callers know what
   1.314 +//version of PSM this is.
   1.315 +void
   1.316 +nsCrypto::GetVersion(nsString& aVersion)
   1.317 +{
   1.318 +  aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING));
   1.319 +}
   1.320 +
   1.321 +/*
   1.322 + * Given an nsKeyGenType, return the PKCS11 mechanism that will
   1.323 + * perform the correct key generation.
   1.324 + */
   1.325 +static uint32_t
   1.326 +cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
   1.327 +{
   1.328 +  uint32_t retMech;
   1.329 +
   1.330 +  switch (keyGenType) {
   1.331 +  case rsaEnc:
   1.332 +  case rsaDualUse:
   1.333 +  case rsaSign:
   1.334 +  case rsaNonrepudiation:
   1.335 +  case rsaSignNonrepudiation:
   1.336 +    retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
   1.337 +    break;
   1.338 +  case ecEnc:
   1.339 +  case ecDualUse:
   1.340 +  case ecSign:
   1.341 +  case ecNonrepudiation:
   1.342 +  case ecSignNonrepudiation:
   1.343 +    retMech = CKM_EC_KEY_PAIR_GEN;
   1.344 +    break;
   1.345 +  case dhEx:
   1.346 +    retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
   1.347 +    break;
   1.348 +  case dsaSign:
   1.349 +  case dsaSignNonrepudiation:
   1.350 +  case dsaNonrepudiation:
   1.351 +    retMech = CKM_DSA_KEY_PAIR_GEN;
   1.352 +    break;
   1.353 +  default:
   1.354 +    retMech = CKM_INVALID_MECHANISM;
   1.355 +  }
   1.356 +  return retMech;
   1.357 +}
   1.358 +
   1.359 +/*
   1.360 + * This function takes a string read through JavaScript parameters
   1.361 + * and translates it to the internal enumeration representing the
   1.362 + * key gen type. Leading and trailing whitespace must be already removed.
   1.363 + */
   1.364 +static nsKeyGenType
   1.365 +cryptojs_interpret_key_gen_type(const nsAString& keyAlg)
   1.366 +{
   1.367 +  if (keyAlg.EqualsLiteral("rsa-ex")) {
   1.368 +    return rsaEnc;
   1.369 +  }
   1.370 +  if (keyAlg.EqualsLiteral("rsa-dual-use")) {
   1.371 +    return rsaDualUse;
   1.372 +  }
   1.373 +  if (keyAlg.EqualsLiteral("rsa-sign")) {
   1.374 +    return rsaSign;
   1.375 +  }
   1.376 +  if (keyAlg.EqualsLiteral("rsa-sign-nonrepudiation")) {
   1.377 +    return rsaSignNonrepudiation;
   1.378 +  }
   1.379 +  if (keyAlg.EqualsLiteral("rsa-nonrepudiation")) {
   1.380 +    return rsaNonrepudiation;
   1.381 +  }
   1.382 +  if (keyAlg.EqualsLiteral("ec-ex")) {
   1.383 +    return ecEnc;
   1.384 +  }
   1.385 +  if (keyAlg.EqualsLiteral("ec-dual-use")) {
   1.386 +    return ecDualUse;
   1.387 +  }
   1.388 +  if (keyAlg.EqualsLiteral("ec-sign")) {
   1.389 +    return ecSign;
   1.390 +  }
   1.391 +  if (keyAlg.EqualsLiteral("ec-sign-nonrepudiation")) {
   1.392 +    return ecSignNonrepudiation;
   1.393 +  }
   1.394 +  if (keyAlg.EqualsLiteral("ec-nonrepudiation")) {
   1.395 +    return ecNonrepudiation;
   1.396 +  }
   1.397 +  if (keyAlg.EqualsLiteral("dsa-sign-nonrepudiation")) {
   1.398 +    return dsaSignNonrepudiation;
   1.399 +  }
   1.400 +  if (keyAlg.EqualsLiteral("dsa-sign")) {
   1.401 +    return dsaSign;
   1.402 +  }
   1.403 +  if (keyAlg.EqualsLiteral("dsa-nonrepudiation")) {
   1.404 +    return dsaNonrepudiation;
   1.405 +  }
   1.406 +  if (keyAlg.EqualsLiteral("dh-ex")) {
   1.407 +    return dhEx;
   1.408 +  }
   1.409 +  return invalidKeyGen;
   1.410 +}
   1.411 +
   1.412 +/* 
   1.413 + * input: null terminated char* pointing to (the remainder of) an
   1.414 + * EC key param string.
   1.415 + *
   1.416 + * bool return value, false means "no more name=value pair found",
   1.417 + *                    true means "found, see out params"
   1.418 + * 
   1.419 + * out param name: char * pointing to name (not zero terminated)
   1.420 + * out param name_len: length of found name
   1.421 + * out param value: char * pointing to value (not zero terminated)
   1.422 + * out param value_len: length of found value
   1.423 + * out param next_pair: to be used for a follow up call to this function
   1.424 + */
   1.425 +
   1.426 +bool getNextNameValueFromECKeygenParamString(char *input,
   1.427 +                                               char *&name,
   1.428 +                                               int &name_len,
   1.429 +                                               char *&value,
   1.430 +                                               int &value_len,
   1.431 +                                               char *&next_call)
   1.432 +{
   1.433 +  if (!input || !*input)
   1.434 +    return false;
   1.435 +
   1.436 +  // we allow leading ; and leading space in front of each name value pair
   1.437 +
   1.438 +  while (*input && *input == ';')
   1.439 +    ++input;
   1.440 +
   1.441 +  while (*input && *input == ' ')
   1.442 +    ++input;
   1.443 +
   1.444 +  name = input;
   1.445 +
   1.446 +  while (*input && *input != '=')
   1.447 +    ++input;
   1.448 +
   1.449 +  if (*input != '=')
   1.450 +    return false;
   1.451 +
   1.452 +  name_len = input - name;
   1.453 +  ++input;
   1.454 +
   1.455 +  value = input;
   1.456 +
   1.457 +  while (*input && *input != ';')
   1.458 +    ++input;
   1.459 +
   1.460 +  value_len = input - value;
   1.461 +  next_call = input;
   1.462 +
   1.463 +  return true;
   1.464 +}
   1.465 +
   1.466 +//Take the string passed into us via crypto.generateCRMFRequest
   1.467 +//as the keygen type parameter and convert it to parameters 
   1.468 +//we can actually pass to the PKCS#11 layer.
   1.469 +static void*
   1.470 +nsConvertToActualKeyGenParams(uint32_t keyGenMech, char *params,
   1.471 +                              uint32_t paramLen, int32_t keySize,
   1.472 +                              nsKeyPairInfo *keyPairInfo)
   1.473 +{
   1.474 +  void *returnParams = nullptr;
   1.475 +
   1.476 +
   1.477 +  switch (keyGenMech) {
   1.478 +  case CKM_RSA_PKCS_KEY_PAIR_GEN:
   1.479 +  {
   1.480 +    // For RSA, we don't support passing in key generation arguments from
   1.481 +    // the JS code just yet.
   1.482 +    if (params)
   1.483 +      return nullptr;
   1.484 +
   1.485 +    PK11RSAGenParams *rsaParams;
   1.486 +    rsaParams = static_cast<PK11RSAGenParams*>
   1.487 +                           (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
   1.488 +                              
   1.489 +    if (!rsaParams) {
   1.490 +      return nullptr;
   1.491 +    }
   1.492 +    /* I'm just taking the same parameters used in 
   1.493 +     * certdlgs.c:GenKey
   1.494 +     */
   1.495 +    if (keySize > 0) {
   1.496 +      rsaParams->keySizeInBits = keySize;
   1.497 +    } else {
   1.498 +      rsaParams->keySizeInBits = 1024;
   1.499 +    }
   1.500 +    rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
   1.501 +    returnParams = rsaParams;
   1.502 +    break;
   1.503 +  }
   1.504 +  case CKM_EC_KEY_PAIR_GEN:
   1.505 +  {
   1.506 +    /*
   1.507 +     * keygen params for generating EC keys must be composed of name=value pairs,
   1.508 +     * multiple pairs allowed, separated using semicolon ;
   1.509 +     *
   1.510 +     * Either param "curve" or param "popcert" must be specified.
   1.511 +     * curve=name-of-curve
   1.512 +     * popcert=base64-encoded-cert
   1.513 +     *
   1.514 +     * When both params are specified, popcert will be used.
   1.515 +     * If no popcert param is given, or if popcert can not be decoded,
   1.516 +     * we will fall back to the curve param.
   1.517 +     *
   1.518 +     * Additional name=value pairs may be defined in the future.
   1.519 +     *
   1.520 +     * If param popcert is present and valid, the given certificate will be used
   1.521 +     * to determine the key generation params. In addition the certificate
   1.522 +     * will be used to produce a dhMac based Proof of Posession,
   1.523 +     * using the cert's public key, subject and issuer names,
   1.524 +     * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
   1.525 +     *
   1.526 +     * If neither param popcert nor param curve could be used,
   1.527 +     * tse a curve based on the keysize param.
   1.528 +     * NOTE: Here keysize is used only as an indication of
   1.529 +     * High/Medium/Low strength; elliptic curve
   1.530 +     * cryptography uses smaller keys than RSA to provide
   1.531 +     * equivalent security.
   1.532 +     */
   1.533 +
   1.534 +    char *curve = nullptr;
   1.535 +
   1.536 +    {
   1.537 +      // extract components of name=value list
   1.538 +
   1.539 +      char *next_input = params;
   1.540 +      char *name = nullptr;
   1.541 +      char *value = nullptr;
   1.542 +      int name_len = 0;
   1.543 +      int value_len = 0;
   1.544 +  
   1.545 +      while (getNextNameValueFromECKeygenParamString(
   1.546 +              next_input, name, name_len, value, value_len,
   1.547 +              next_input))
   1.548 +      {
   1.549 +        // use only the first specified curve
   1.550 +        if (!curve && PL_strncmp(name, "curve", std::min(name_len, 5)) == 0)
   1.551 +        {
   1.552 +          curve = PL_strndup(value, value_len);
   1.553 +        }
   1.554 +        // use only the first specified popcert
   1.555 +        else if (!keyPairInfo->ecPopCert &&
   1.556 +                 PL_strncmp(name, "popcert", std::min(name_len, 7)) == 0)
   1.557 +        {
   1.558 +          char *certstr = PL_strndup(value, value_len);
   1.559 +          if (certstr) {
   1.560 +            keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
   1.561 +            PL_strfree(certstr);
   1.562 +
   1.563 +            if (keyPairInfo->ecPopCert)
   1.564 +            {
   1.565 +              keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
   1.566 +            }
   1.567 +          }
   1.568 +        }
   1.569 +      }
   1.570 +    }
   1.571 +
   1.572 +    // first try to use the params of the provided CA cert
   1.573 +    if (keyPairInfo->ecPopPubKey && keyPairInfo->ecPopPubKey->keyType == ecKey)
   1.574 +    {
   1.575 +      returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
   1.576 +    }
   1.577 +
   1.578 +    // if we did not yet find good params, do we have a curve name?
   1.579 +    if (!returnParams && curve)
   1.580 +    {
   1.581 +      returnParams = decode_ec_params(curve);
   1.582 +    }
   1.583 +
   1.584 +    // if we did not yet find good params, do something based on keysize
   1.585 +    if (!returnParams)
   1.586 +    {
   1.587 +      switch (keySize) {
   1.588 +      case 512:
   1.589 +      case 1024:
   1.590 +          returnParams = decode_ec_params("secp256r1");
   1.591 +          break;
   1.592 +      case 2048:
   1.593 +      default:
   1.594 +          returnParams = decode_ec_params("secp384r1");
   1.595 +          break;
   1.596 +      }
   1.597 +    }
   1.598 +
   1.599 +    if (curve)
   1.600 +      PL_strfree(curve);
   1.601 +
   1.602 +    break;
   1.603 +  }
   1.604 +  case CKM_DSA_KEY_PAIR_GEN:
   1.605 +  {
   1.606 +    // For DSA, we don't support passing in key generation arguments from
   1.607 +    // the JS code just yet.
   1.608 +    if (params)
   1.609 +      return nullptr;
   1.610 +
   1.611 +    PQGParams *pqgParams = nullptr;
   1.612 +    PQGVerify *vfy = nullptr;
   1.613 +    SECStatus  rv;
   1.614 +    int        index;
   1.615 +       
   1.616 +    index = PQG_PBITS_TO_INDEX(keySize);
   1.617 +    if (index == -1) {
   1.618 +      returnParams = nullptr;
   1.619 +      break;
   1.620 +    }
   1.621 +    rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
   1.622 +    if (vfy) {
   1.623 +      PK11_PQG_DestroyVerify(vfy);
   1.624 +    }
   1.625 +    if (rv != SECSuccess) {
   1.626 +      if (pqgParams) {
   1.627 +        PK11_PQG_DestroyParams(pqgParams);
   1.628 +      }
   1.629 +      return nullptr;
   1.630 +    }
   1.631 +    returnParams = pqgParams;
   1.632 +    break;
   1.633 +  }
   1.634 +  default:
   1.635 +    returnParams = nullptr;
   1.636 +  }
   1.637 +  return returnParams;
   1.638 +}
   1.639 +
   1.640 +//We need to choose which PKCS11 slot we're going to generate
   1.641 +//the key on.  Calls the default implementation provided by
   1.642 +//nsKeygenHandler.cpp
   1.643 +static PK11SlotInfo*
   1.644 +nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
   1.645 +{
   1.646 +  nsNSSShutDownPreventionLock locker;
   1.647 +  uint32_t mechanism = cryptojs_convert_to_mechanism(keyGenType);
   1.648 +  PK11SlotInfo *slot = nullptr;
   1.649 +  nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
   1.650 +  if (NS_FAILED(rv)) {
   1.651 +    if (slot)
   1.652 +      PK11_FreeSlot(slot);
   1.653 +    slot = nullptr;
   1.654 +  }
   1.655 +  return slot;
   1.656 +}
   1.657 +
   1.658 +//Free the parameters that were passed into PK11_GenerateKeyPair
   1.659 +//depending on the mechanism type used.
   1.660 +static void
   1.661 +nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
   1.662 +{
   1.663 +  switch (keyGenMechanism) {
   1.664 +  case CKM_RSA_PKCS_KEY_PAIR_GEN:
   1.665 +    nsMemory::Free(params);
   1.666 +    break;
   1.667 +  case CKM_EC_KEY_PAIR_GEN:
   1.668 +    SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
   1.669 +    break;
   1.670 +  case CKM_DSA_KEY_PAIR_GEN:
   1.671 +    PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
   1.672 +    break;
   1.673 +  }
   1.674 +}
   1.675 +
   1.676 +//Function that is used to generate a single key pair.
   1.677 +//Once all the arguments have been parsed and processed, this
   1.678 +//function gets called and takes care of actually generating
   1.679 +//the key pair passing the appopriate parameters to the NSS
   1.680 +//functions.
   1.681 +static nsresult
   1.682 +cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 
   1.683 +                            int32_t keySize, char *params, 
   1.684 +                            nsIInterfaceRequestor *uiCxt,
   1.685 +                            PK11SlotInfo *slot, bool willEscrow)
   1.686 +                            
   1.687 +{
   1.688 +  const PK11AttrFlags sensitiveFlags = (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
   1.689 +  const PK11AttrFlags temporarySessionFlags = PK11_ATTR_SESSION;
   1.690 +  const PK11AttrFlags permanentTokenFlags = PK11_ATTR_TOKEN;
   1.691 +  const PK11AttrFlags extractableFlags = PK11_ATTR_EXTRACTABLE;
   1.692 +  
   1.693 +  nsIGeneratingKeypairInfoDialogs * dialogs;
   1.694 +  nsKeygenThread *KeygenRunnable = 0;
   1.695 +  nsCOMPtr<nsIKeygenThread> runnable;
   1.696 +
   1.697 +  uint32_t mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
   1.698 +  void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 
   1.699 +                                                     (params) ? strlen(params):0, 
   1.700 +                                                     keySize, keyPairInfo);
   1.701 +
   1.702 +  if (!keyGenParams || !slot) {
   1.703 +    return NS_ERROR_INVALID_ARG;
   1.704 +  }
   1.705 +
   1.706 +  // Make sure the token has password already set on it before trying
   1.707 +  // to generate the key.
   1.708 +
   1.709 +  nsresult rv = setPassword(slot, uiCxt);
   1.710 +  if (NS_FAILED(rv))
   1.711 +    return rv;
   1.712 +
   1.713 +  if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
   1.714 +    return NS_ERROR_FAILURE;
   1.715 + 
   1.716 +  // Smart cards will not let you extract a private key once 
   1.717 +  // it is on the smart card.  If we've been told to escrow
   1.718 +  // a private key that will be stored on a smart card,
   1.719 +  // then we'll use the following strategy to ensure we can escrow it.
   1.720 +  // We'll attempt to generate the key on our internal token,
   1.721 +  // because this is expected to avoid some problems.
   1.722 +  // If it works, we'll escrow, move the key to the smartcard, done.
   1.723 +  // If it didn't work (or the internal key doesn't support the desired
   1.724 +  // mechanism), then we'll attempt to generate the key on
   1.725 +  // the destination token, with the EXTRACTABLE flag set.
   1.726 +  // If it works, we'll extract, escrow, done.
   1.727 +  // If it failed, then we're unable to escrow and return failure.
   1.728 +  // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
   1.729 +  //       so that the key has zero chance of being store in the
   1.730 +  //       user's key3.db file.  Which the slot returned by
   1.731 +  //       PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
   1.732 +  //       does not.
   1.733 +  ScopedPK11SlotInfo intSlot;
   1.734 +  
   1.735 +  if (willEscrow && !PK11_IsInternal(slot)) {
   1.736 +    intSlot = PK11_GetInternalSlot();
   1.737 +    NS_ASSERTION(intSlot,"Couldn't get the internal slot");
   1.738 +    
   1.739 +    if (!PK11_DoesMechanism(intSlot, mechanism)) {
   1.740 +      // Set to null, and the subsequent code will not attempt to use it.
   1.741 +      intSlot = nullptr;
   1.742 +    }
   1.743 +  }
   1.744 +
   1.745 +  rv = getNSSDialogs((void**)&dialogs,
   1.746 +                     NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
   1.747 +                     NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
   1.748 +
   1.749 +  if (NS_SUCCEEDED(rv)) {
   1.750 +    KeygenRunnable = new nsKeygenThread();
   1.751 +    if (KeygenRunnable) {
   1.752 +      NS_ADDREF(KeygenRunnable);
   1.753 +    }
   1.754 +  }
   1.755 +  
   1.756 +  // "firstAttemptSlot" and "secondAttemptSlot" are alternative names
   1.757 +  // for better code readability, we don't increase the reference counts.
   1.758 +  
   1.759 +  PK11SlotInfo *firstAttemptSlot = nullptr;
   1.760 +  PK11AttrFlags firstAttemptFlags = 0;
   1.761 +
   1.762 +  PK11SlotInfo *secondAttemptSlot = slot;
   1.763 +  PK11AttrFlags secondAttemptFlags = sensitiveFlags | permanentTokenFlags;
   1.764 +  
   1.765 +  if (willEscrow) {
   1.766 +    secondAttemptFlags |= extractableFlags;
   1.767 +  }
   1.768 +  
   1.769 +  if (!intSlot || PK11_IsInternal(slot)) {
   1.770 +    // if we cannot use the internal slot, then there is only one attempt
   1.771 +    // if the destination slot is the internal slot, then there is only one attempt
   1.772 +    firstAttemptSlot = secondAttemptSlot;
   1.773 +    firstAttemptFlags = secondAttemptFlags;
   1.774 +    secondAttemptSlot = nullptr;
   1.775 +    secondAttemptFlags = 0;
   1.776 +  }
   1.777 +  else {
   1.778 +    firstAttemptSlot = intSlot;
   1.779 +    firstAttemptFlags = sensitiveFlags | temporarySessionFlags;
   1.780 +    
   1.781 +    // We always need the extractable flag on the first attempt,
   1.782 +    // because we want to move the key to another slot - ### is this correct?
   1.783 +    firstAttemptFlags |= extractableFlags;
   1.784 +  }
   1.785 +
   1.786 +  bool mustMoveKey = false;
   1.787 +  
   1.788 +  if (NS_FAILED(rv) || !KeygenRunnable) {
   1.789 +    /* execute key generation on this thread */
   1.790 +    rv = NS_OK;
   1.791 +    
   1.792 +    keyPairInfo->privKey = 
   1.793 +      PK11_GenerateKeyPairWithFlags(firstAttemptSlot, mechanism,
   1.794 +                                    keyGenParams, &keyPairInfo->pubKey,
   1.795 +                                    firstAttemptFlags, uiCxt);
   1.796 +    
   1.797 +    if (keyPairInfo->privKey) {
   1.798 +      // success on first attempt
   1.799 +      if (secondAttemptSlot) {
   1.800 +        mustMoveKey = true;
   1.801 +      }
   1.802 +    }
   1.803 +    else {
   1.804 +      keyPairInfo->privKey = 
   1.805 +        PK11_GenerateKeyPairWithFlags(secondAttemptSlot, mechanism,
   1.806 +                                      keyGenParams, &keyPairInfo->pubKey,
   1.807 +                                      secondAttemptFlags, uiCxt);
   1.808 +    }
   1.809 +    
   1.810 +  } else {
   1.811 +    /* execute key generation on separate thread */
   1.812 +    KeygenRunnable->SetParams( firstAttemptSlot, firstAttemptFlags,
   1.813 +                               secondAttemptSlot, secondAttemptFlags,
   1.814 +                               mechanism, keyGenParams, uiCxt );
   1.815 +
   1.816 +    runnable = do_QueryInterface(KeygenRunnable);
   1.817 +
   1.818 +    if (runnable) {
   1.819 +      {
   1.820 +        nsPSMUITracker tracker;
   1.821 +        if (tracker.isUIForbidden()) {
   1.822 +          rv = NS_ERROR_NOT_AVAILABLE;
   1.823 +        }
   1.824 +        else {
   1.825 +          rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
   1.826 +          // We call join on the thread, 
   1.827 +          // so we can be sure that no simultaneous access to the passed parameters will happen.
   1.828 +          KeygenRunnable->Join();
   1.829 +        }
   1.830 +      }
   1.831 +
   1.832 +      NS_RELEASE(dialogs);
   1.833 +      if (NS_SUCCEEDED(rv)) {
   1.834 +        PK11SlotInfo *used_slot = nullptr;
   1.835 +        rv = KeygenRunnable->ConsumeResult(&used_slot, 
   1.836 +                                           &keyPairInfo->privKey, &keyPairInfo->pubKey);
   1.837 +
   1.838 +        if (NS_SUCCEEDED(rv)) {
   1.839 +          if ((used_slot == firstAttemptSlot) && secondAttemptSlot) {
   1.840 +            mustMoveKey = true;
   1.841 +          }
   1.842 +        
   1.843 +          if (used_slot) {
   1.844 +            PK11_FreeSlot(used_slot);
   1.845 +          }
   1.846 +        }
   1.847 +      }
   1.848 +    }
   1.849 +  }
   1.850 +
   1.851 +  firstAttemptSlot = nullptr;
   1.852 +  secondAttemptSlot = nullptr;
   1.853 +  
   1.854 +  nsFreeKeyGenParams(mechanism, keyGenParams);
   1.855 +
   1.856 +  if (KeygenRunnable) {
   1.857 +    NS_RELEASE(KeygenRunnable);
   1.858 +  }
   1.859 +
   1.860 +  if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
   1.861 +    return NS_ERROR_FAILURE;
   1.862 +  }
   1.863 + 
   1.864 +  //If we generated the key pair on the internal slot because the
   1.865 +  // keys were going to be escrowed, move the keys over right now.
   1.866 +  if (mustMoveKey) {
   1.867 +    ScopedSECKEYPrivateKey newPrivKey(PK11_LoadPrivKey(slot,
   1.868 +                                                    keyPairInfo->privKey,
   1.869 +                                                    keyPairInfo->pubKey,
   1.870 +                                                    true, true));
   1.871 +    if (!newPrivKey)
   1.872 +      return NS_ERROR_FAILURE;
   1.873 +
   1.874 +    // The private key is stored on the selected slot now, and the copy we
   1.875 +    // ultimately use for escrowing when the time comes lives 
   1.876 +    // in the internal slot.  We will delete it from that slot
   1.877 +    // after the requests are made.
   1.878 +  }  
   1.879 +
   1.880 +  return NS_OK;
   1.881 +}
   1.882 +
   1.883 +/*
   1.884 + * FUNCTION: cryptojs_ReadArgsAndGenerateKey
   1.885 + * -------------------------------------
   1.886 + * INPUTS:
   1.887 + *  cx
   1.888 + *    The JSContext associated with the execution of the corresponging
   1.889 + *    crypto.generateCRMFRequest call
   1.890 + *  argv
   1.891 + *    A pointer to an array of JavaScript parameters passed to the
   1.892 + *    method crypto.generateCRMFRequest.  The array should have the
   1.893 + *    3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
   1.894 + *    the definition of crypto.generateCRMFRequest at the following
   1.895 + *    document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
   1.896 + *  keyGenType
   1.897 + *    A structure used to store the information about the newly created
   1.898 + *    key pair.
   1.899 + *  uiCxt
   1.900 + *    An interface requestor that would be used to get an nsIPrompt
   1.901 + *    if we need to ask the user for a password.
   1.902 + *  slotToUse
   1.903 + *    The PKCS11 slot to use for generating the key pair. If nullptr, then
   1.904 + *    this function should select a slot that can do the key generation 
   1.905 + *    from the keytype associted with the keyPairInfo, and pass it back to
   1.906 + *    the caller so that subsequence key generations can use the same slot. 
   1.907 + *  willEscrow
   1.908 + *    If true, then that means we will try to escrow the generated
   1.909 + *    private key when building the CRMF request.  If false, then
   1.910 + *    we will not try to escrow the private key.
   1.911 + *
   1.912 + * NOTES:
   1.913 + * This function takes care of reading a set of 3 parameters that define
   1.914 + * one key generation.  The argv pointer should be one that originates
   1.915 + * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
   1.916 + * The function interprets the argument in the first index as an integer and
   1.917 + * passes that as the key size for the key generation-this parameter is
   1.918 + * mandatory.  The second parameter is read in as a string.  This value can
   1.919 + * be null in JavaScript world and everything will still work.  The third
   1.920 + * parameter is a mandatory string that indicates what kind of key to generate.
   1.921 + * There should always be 1-to-1 correspondence between the strings compared
   1.922 + * in the function cryptojs_interpret_key_gen_type and the strings listed in
   1.923 + * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
   1.924 + * under the definition of the method generateCRMFRequest, for the parameter
   1.925 + * "keyGenAlgN".  After reading the parameters, the function then 
   1.926 + * generates the key pairs passing the parameters parsed from the JavaScript i
   1.927 + * routine.  
   1.928 + *
   1.929 + * RETURN:
   1.930 + * NS_OK if creating the Key was successful.  Any other return value
   1.931 + * indicates an error.
   1.932 + */
   1.933 +
   1.934 +static nsresult
   1.935 +cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
   1.936 +                                JS::Value *argv,
   1.937 +                                nsKeyPairInfo *keyGenType,
   1.938 +                                nsIInterfaceRequestor *uiCxt,
   1.939 +                                PK11SlotInfo **slot, bool willEscrow)
   1.940 +{
   1.941 +  JSString  *jsString;
   1.942 +  JSAutoByteString params;
   1.943 +  int    keySize;
   1.944 +  nsresult  rv;
   1.945 +
   1.946 +  if (!JSVAL_IS_INT(argv[0])) {
   1.947 +    JS_ReportError(cx, "%s%s", JS_ERROR,
   1.948 +                   "passed in non-integer for key size");
   1.949 +    return NS_ERROR_FAILURE;
   1.950 +  }
   1.951 +  keySize = JSVAL_TO_INT(argv[0]);
   1.952 +  if (!JSVAL_IS_NULL(argv[1])) {
   1.953 +    JS::Rooted<JS::Value> v(cx, argv[1]);
   1.954 +    jsString = JS::ToString(cx, v);
   1.955 +    NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
   1.956 +    argv[1] = STRING_TO_JSVAL(jsString);
   1.957 +    params.encodeLatin1(cx, jsString);
   1.958 +    NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
   1.959 +  }
   1.960 +
   1.961 +  if (JSVAL_IS_NULL(argv[2])) {
   1.962 +    JS_ReportError(cx,"%s%s", JS_ERROR,
   1.963 +             "key generation type not specified");
   1.964 +    return NS_ERROR_FAILURE;
   1.965 +  }
   1.966 +  JS::Rooted<JS::Value> v(cx, argv[2]);
   1.967 +  jsString = JS::ToString(cx, v);
   1.968 +  NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
   1.969 +  argv[2] = STRING_TO_JSVAL(jsString);
   1.970 +  nsDependentJSString dependentKeyGenAlg;
   1.971 +  NS_ENSURE_TRUE(dependentKeyGenAlg.init(cx, jsString), NS_ERROR_UNEXPECTED);
   1.972 +  nsAutoString keyGenAlg(dependentKeyGenAlg);
   1.973 +  keyGenAlg.Trim("\r\n\t ");
   1.974 +  keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg);
   1.975 +  if (keyGenType->keyGenType == invalidKeyGen) {
   1.976 +    NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
   1.977 +    JS_ReportError(cx, "%s%s%s", JS_ERROR,
   1.978 +                   "invalid key generation argument:",
   1.979 +                   keyGenAlgNarrow.get());
   1.980 +    goto loser;
   1.981 +  }
   1.982 +  if (!*slot) {
   1.983 +    *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
   1.984 +    if (!*slot)
   1.985 +      goto loser;
   1.986 +  }
   1.987 +
   1.988 +  rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
   1.989 +                                   *slot,willEscrow);
   1.990 +
   1.991 +  if (rv != NS_OK) {
   1.992 +    NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
   1.993 +    JS_ReportError(cx,"%s%s%s", JS_ERROR,
   1.994 +                   "could not generate the key for algorithm ",
   1.995 +                   keyGenAlgNarrow.get());
   1.996 +    goto loser;
   1.997 +  }
   1.998 +  return NS_OK;
   1.999 +loser:
  1.1000 +  return NS_ERROR_FAILURE;
  1.1001 +}
  1.1002 +
  1.1003 +//Utility funciton to free up the memory used by nsKeyPairInfo
  1.1004 +//arrays.
  1.1005 +static void
  1.1006 +nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
  1.1007 +{
  1.1008 +  NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
  1.1009 +  if (!keyids)
  1.1010 +    return;
  1.1011 +  int i;
  1.1012 +  for (i=0; i<numIDs; i++) {
  1.1013 +    if (keyids[i].pubKey)
  1.1014 +      SECKEY_DestroyPublicKey(keyids[i].pubKey);
  1.1015 +    if (keyids[i].privKey)
  1.1016 +      SECKEY_DestroyPrivateKey(keyids[i].privKey);
  1.1017 +    if (keyids[i].ecPopCert)
  1.1018 +      CERT_DestroyCertificate(keyids[i].ecPopCert);
  1.1019 +    if (keyids[i].ecPopPubKey)
  1.1020 +      SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
  1.1021 +  }
  1.1022 +  delete []keyids;
  1.1023 +}
  1.1024 +
  1.1025 +//Utility funciton used to free the genertaed cert request messages
  1.1026 +static void
  1.1027 +nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, int32_t numMessages)
  1.1028 +{
  1.1029 +  int32_t i;
  1.1030 +  for (i=0; i<numMessages && certReqMsgs[i]; i++) {
  1.1031 +    CRMF_DestroyCertReqMsg(certReqMsgs[i]);
  1.1032 +  }
  1.1033 +  delete []certReqMsgs;
  1.1034 +}
  1.1035 +
  1.1036 +//If the form called for escrowing the private key we just generated,
  1.1037 +//this function adds all the correct elements to the request.
  1.1038 +//That consists of adding CRMFEncryptedKey to the reques as part
  1.1039 +//of the CRMFPKIArchiveOptions Control.
  1.1040 +static nsresult
  1.1041 +nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
  1.1042 +                     nsNSSCertificate *wrappingCert)
  1.1043 +{
  1.1044 +  if (!wrappingCert ||
  1.1045 +      CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
  1.1046 +    return NS_ERROR_FAILURE;
  1.1047 +  }
  1.1048 +  mozilla::pkix::ScopedCERTCertificate cert(wrappingCert->GetCert());
  1.1049 +  if (!cert)
  1.1050 +    return NS_ERROR_FAILURE;
  1.1051 +
  1.1052 +  CRMFEncryptedKey *encrKey = 
  1.1053 +      CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert.get());
  1.1054 +  if (!encrKey)
  1.1055 +    return NS_ERROR_FAILURE;
  1.1056 +
  1.1057 +  CRMFPKIArchiveOptions *archOpt = 
  1.1058 +      CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
  1.1059 +  if (!archOpt) {
  1.1060 +    CRMF_DestroyEncryptedKey(encrKey);
  1.1061 +    return NS_ERROR_FAILURE;
  1.1062 +  }
  1.1063 +  SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
  1.1064 +  CRMF_DestroyEncryptedKey(encrKey);
  1.1065 +  CRMF_DestroyPKIArchiveOptions(archOpt);
  1.1066 +  if (srv != SECSuccess)
  1.1067 +    return NS_ERROR_FAILURE;
  1.1068 +
  1.1069 +  return NS_OK;
  1.1070 +}
  1.1071 +
  1.1072 +//Set the Distinguished Name (Subject Name) for the cert
  1.1073 +//being requested.
  1.1074 +static nsresult
  1.1075 +nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
  1.1076 +{
  1.1077 +  if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
  1.1078 +    return NS_ERROR_FAILURE;
  1.1079 +  }
  1.1080 +  ScopedCERTName subjectName(CERT_AsciiToName(reqDN));
  1.1081 +  if (!subjectName) {
  1.1082 +    return NS_ERROR_FAILURE;
  1.1083 +  }
  1.1084 +  SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
  1.1085 +                                                   static_cast<void*>
  1.1086 +                                                              (subjectName));
  1.1087 +  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
  1.1088 +}
  1.1089 +
  1.1090 +//Set Registration Token Control on the request.
  1.1091 +static nsresult
  1.1092 +nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
  1.1093 +{
  1.1094 +  // this should never happen, but might as well add this.
  1.1095 +  NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
  1.1096 +  if (regToken){
  1.1097 +    if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
  1.1098 +      return NS_ERROR_FAILURE;
  1.1099 +  
  1.1100 +    SECItem src;
  1.1101 +    src.data = (unsigned char*)regToken;
  1.1102 +    src.len  = strlen(regToken);
  1.1103 +    SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src, 
  1.1104 +                                        SEC_ASN1_GET(SEC_UTF8StringTemplate));
  1.1105 +
  1.1106 +    if (!derEncoded)
  1.1107 +      return NS_ERROR_FAILURE;
  1.1108 +
  1.1109 +    SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
  1.1110 +    SECITEM_FreeItem(derEncoded,true);
  1.1111 +    if (srv != SECSuccess)
  1.1112 +      return NS_ERROR_FAILURE;
  1.1113 +  }
  1.1114 +  return NS_OK;
  1.1115 +}
  1.1116 +
  1.1117 +//Set the Authenticator control on the cert reuest.  It's just
  1.1118 +//a string that gets passed along.
  1.1119 +static nsresult
  1.1120 +nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
  1.1121 +{
  1.1122 +  //This should never happen, but might as well check.
  1.1123 +  NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
  1.1124 +  if (authenticator) {
  1.1125 +    if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
  1.1126 +      return NS_ERROR_FAILURE;
  1.1127 +    
  1.1128 +    SECItem src;
  1.1129 +    src.data = (unsigned char*)authenticator;
  1.1130 +    src.len  = strlen(authenticator);
  1.1131 +    SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src,
  1.1132 +                                     SEC_ASN1_GET(SEC_UTF8StringTemplate));
  1.1133 +    if (!derEncoded)
  1.1134 +      return NS_ERROR_FAILURE;
  1.1135 +
  1.1136 +    SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 
  1.1137 +                                                            derEncoded);
  1.1138 +    SECITEM_FreeItem(derEncoded, true);
  1.1139 +    if (srv != SECSuccess)
  1.1140 +      return NS_ERROR_FAILURE;
  1.1141 +  }
  1.1142 +  return NS_OK;
  1.1143 +}
  1.1144 +
  1.1145 +// ASN1 DER encoding rules say that when encoding a BIT string,
  1.1146 +// the length in the header for the bit string is the number 
  1.1147 +// of "useful" bits in the BIT STRING.  So the function finds
  1.1148 +// it and sets accordingly for the returned item.
  1.1149 +static void
  1.1150 +nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
  1.1151 +{
  1.1152 +  unsigned char onebyte;
  1.1153 +  unsigned int i, len = 0;
  1.1154 +
  1.1155 +  /* to prevent warning on some platform at compile time */
  1.1156 +  onebyte = '\0';
  1.1157 +  /* Get the position of the right-most turn-on bit */
  1.1158 +  for (i = 0; i < (value->len ) * 8; ++i) {
  1.1159 +    if (i % 8 == 0)
  1.1160 +      onebyte = value->data[i/8];
  1.1161 +    if (onebyte & 0x80)
  1.1162 +      len = i;
  1.1163 +    onebyte <<= 1;
  1.1164 +  }
  1.1165 +
  1.1166 +  bitsmap->data = value->data;
  1.1167 +  /* Add one here since we work with base 1 */
  1.1168 +  bitsmap->len = len + 1;
  1.1169 +}
  1.1170 +
  1.1171 +//This next section defines all the functions that sets the 
  1.1172 +//keyUsageExtension for all the different types of key gens
  1.1173 +//we handle.  The keyUsageExtension is just a bit flag extension
  1.1174 +//that we set in wrapper functions that call straight into
  1.1175 +//nsSetKeyUsageExtension.  There is one wrapper funciton for each
  1.1176 +//keyGenType.  The correct function will eventually be called 
  1.1177 +//by going through a switch statement based on the nsKeyGenType
  1.1178 +//in the nsKeyPairInfo struct.
  1.1179 +static nsresult
  1.1180 +nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
  1.1181 +                       unsigned char   keyUsage)
  1.1182 +{
  1.1183 +  SECItem                 *encodedExt= nullptr;
  1.1184 +  SECItem                  keyUsageValue = { (SECItemType) 0, nullptr, 0 };
  1.1185 +  SECItem                  bitsmap = { (SECItemType) 0, nullptr, 0 };
  1.1186 +  SECStatus                srv;
  1.1187 +  CRMFCertExtension       *ext = nullptr;
  1.1188 +  CRMFCertExtCreationInfo  extAddParams;
  1.1189 +  SEC_ASN1Template         bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nullptr,
  1.1190 +                                             sizeof(SECItem)};
  1.1191 +
  1.1192 +  keyUsageValue.data = &keyUsage;
  1.1193 +  keyUsageValue.len  = 1;
  1.1194 +  nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
  1.1195 +
  1.1196 +  encodedExt = SEC_ASN1EncodeItem(nullptr, nullptr, &bitsmap,&bitStrTemplate);
  1.1197 +  if (!encodedExt) {
  1.1198 +    goto loser;
  1.1199 +  }
  1.1200 +  ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
  1.1201 +  if (!ext) {
  1.1202 +      goto loser;
  1.1203 +  }
  1.1204 +  extAddParams.numExtensions = 1;
  1.1205 +  extAddParams.extensions = &ext;
  1.1206 +  srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
  1.1207 +                                         &extAddParams);
  1.1208 +  if (srv != SECSuccess) {
  1.1209 +      goto loser;
  1.1210 +  }
  1.1211 +  CRMF_DestroyCertExtension(ext);
  1.1212 +  SECITEM_FreeItem(encodedExt, true);
  1.1213 +  return NS_OK;
  1.1214 + loser:
  1.1215 +  if (ext) {
  1.1216 +    CRMF_DestroyCertExtension(ext);
  1.1217 +  }
  1.1218 +  if (encodedExt) {
  1.1219 +      SECITEM_FreeItem(encodedExt, true);
  1.1220 +  }
  1.1221 +  return NS_ERROR_FAILURE;
  1.1222 +}
  1.1223 +
  1.1224 +static nsresult
  1.1225 +nsSetRSADualUse(CRMFCertRequest *crmfReq)
  1.1226 +{
  1.1227 +  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
  1.1228 +                           | KU_NON_REPUDIATION
  1.1229 +                           | KU_KEY_ENCIPHERMENT;
  1.1230 +
  1.1231 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1232 +}
  1.1233 +
  1.1234 +static nsresult
  1.1235 +nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
  1.1236 +{
  1.1237 +  unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
  1.1238 +
  1.1239 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1240 +}
  1.1241 +
  1.1242 +static nsresult
  1.1243 +nsSetRSASign(CRMFCertRequest *crmfReq)
  1.1244 +{
  1.1245 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1.1246 +
  1.1247 +
  1.1248 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1249 +}
  1.1250 +
  1.1251 +static nsresult
  1.1252 +nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
  1.1253 +{
  1.1254 +  unsigned char keyUsage = KU_NON_REPUDIATION;
  1.1255 +
  1.1256 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1257 +}
  1.1258 +
  1.1259 +static nsresult
  1.1260 +nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
  1.1261 +{
  1.1262 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1.1263 +                           KU_NON_REPUDIATION;
  1.1264 +
  1.1265 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1266 +}
  1.1267 +
  1.1268 +static nsresult
  1.1269 +nsSetECDualUse(CRMFCertRequest *crmfReq)
  1.1270 +{
  1.1271 +  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
  1.1272 +                           | KU_NON_REPUDIATION
  1.1273 +                           | KU_KEY_AGREEMENT;
  1.1274 +
  1.1275 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1276 +}
  1.1277 +
  1.1278 +static nsresult
  1.1279 +nsSetECKeyEx(CRMFCertRequest *crmfReq)
  1.1280 +{
  1.1281 +  unsigned char keyUsage = KU_KEY_AGREEMENT;
  1.1282 +
  1.1283 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1284 +}
  1.1285 +
  1.1286 +static nsresult
  1.1287 +nsSetECSign(CRMFCertRequest *crmfReq)
  1.1288 +{
  1.1289 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1.1290 +
  1.1291 +
  1.1292 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1293 +}
  1.1294 +
  1.1295 +static nsresult
  1.1296 +nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
  1.1297 +{
  1.1298 +  unsigned char keyUsage = KU_NON_REPUDIATION;
  1.1299 +
  1.1300 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1301 +}
  1.1302 +
  1.1303 +static nsresult
  1.1304 +nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
  1.1305 +{
  1.1306 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1.1307 +                           KU_NON_REPUDIATION;
  1.1308 +
  1.1309 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1310 +}
  1.1311 +
  1.1312 +static nsresult
  1.1313 +nsSetDH(CRMFCertRequest *crmfReq)
  1.1314 +{
  1.1315 +  unsigned char keyUsage = KU_KEY_AGREEMENT;
  1.1316 +
  1.1317 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1318 +}
  1.1319 +
  1.1320 +static nsresult
  1.1321 +nsSetDSASign(CRMFCertRequest *crmfReq)
  1.1322 +{
  1.1323 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
  1.1324 +
  1.1325 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1326 +}
  1.1327 +
  1.1328 +static nsresult
  1.1329 +nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
  1.1330 +{
  1.1331 +  unsigned char keyUsage = KU_NON_REPUDIATION;
  1.1332 +
  1.1333 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1334 +}
  1.1335 +
  1.1336 +static nsresult
  1.1337 +nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
  1.1338 +{
  1.1339 +  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
  1.1340 +                           KU_NON_REPUDIATION;
  1.1341 +
  1.1342 +  return nsSetKeyUsageExtension(crmfReq, keyUsage);
  1.1343 +}
  1.1344 +
  1.1345 +static nsresult
  1.1346 +nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
  1.1347 +{
  1.1348 +  nsresult rv;
  1.1349 +
  1.1350 +  switch (keyGenType) {
  1.1351 +  case rsaDualUse:
  1.1352 +    rv = nsSetRSADualUse(crmfReq);
  1.1353 +    break;
  1.1354 +  case rsaEnc:
  1.1355 +    rv = nsSetRSAKeyEx(crmfReq);
  1.1356 +    break;
  1.1357 +  case rsaSign:
  1.1358 +    rv = nsSetRSASign(crmfReq);
  1.1359 +    break;
  1.1360 +  case rsaNonrepudiation:
  1.1361 +    rv = nsSetRSANonRepudiation(crmfReq);
  1.1362 +    break;
  1.1363 +  case rsaSignNonrepudiation:
  1.1364 +    rv = nsSetRSASignNonRepudiation(crmfReq);
  1.1365 +    break;
  1.1366 +  case ecDualUse:
  1.1367 +    rv = nsSetECDualUse(crmfReq);
  1.1368 +    break;
  1.1369 +  case ecEnc:
  1.1370 +    rv = nsSetECKeyEx(crmfReq);
  1.1371 +    break;
  1.1372 +  case ecSign:
  1.1373 +    rv = nsSetECSign(crmfReq);
  1.1374 +    break;
  1.1375 +  case ecNonrepudiation:
  1.1376 +    rv = nsSetECNonRepudiation(crmfReq);
  1.1377 +    break;
  1.1378 +  case ecSignNonrepudiation:
  1.1379 +    rv = nsSetECSignNonRepudiation(crmfReq);
  1.1380 +    break;
  1.1381 +  case dhEx:
  1.1382 +    rv = nsSetDH(crmfReq);
  1.1383 +    break;
  1.1384 +  case dsaSign:
  1.1385 +    rv = nsSetDSASign(crmfReq);
  1.1386 +    break;
  1.1387 +  case dsaNonrepudiation:
  1.1388 +    rv = nsSetDSANonRepudiation(crmfReq);
  1.1389 +    break;
  1.1390 +  case dsaSignNonrepudiation:
  1.1391 +    rv = nsSetDSASignNonRepudiation(crmfReq);
  1.1392 +    break;
  1.1393 +  default:
  1.1394 +    rv = NS_ERROR_FAILURE;
  1.1395 +    break;
  1.1396 +  }
  1.1397 +  return rv;
  1.1398 +}
  1.1399 +
  1.1400 +//Create a single CRMFCertRequest with all of the necessary parts 
  1.1401 +//already installed.  The request returned by this function will
  1.1402 +//have all the parts necessary and can just be added to a 
  1.1403 +//Certificate Request Message.
  1.1404 +static CRMFCertRequest*
  1.1405 +nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 
  1.1406 +                      char *authenticator, nsNSSCertificate *wrappingCert)
  1.1407 +{
  1.1408 +  uint32_t reqID;
  1.1409 +  nsresult rv;
  1.1410 +
  1.1411 +  //The draft says the ID of the request should be a random
  1.1412 +  //number.  We don't have a way of tracking this number
  1.1413 +  //to compare when the reply actually comes back,though.
  1.1414 +  PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
  1.1415 +  CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
  1.1416 +  if (!certReq)
  1.1417 +    return nullptr;
  1.1418 +
  1.1419 +  long version = SEC_CERTIFICATE_VERSION_3;
  1.1420 +  SECStatus srv;
  1.1421 +  CERTSubjectPublicKeyInfo *spki = nullptr;
  1.1422 +  srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
  1.1423 +  if (srv != SECSuccess)
  1.1424 +    goto loser;
  1.1425 +  
  1.1426 +  spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
  1.1427 +  if (!spki)
  1.1428 +    goto loser;
  1.1429 +
  1.1430 +  srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
  1.1431 +  SECKEY_DestroySubjectPublicKeyInfo(spki);
  1.1432 +  if (srv != SECSuccess)
  1.1433 +    goto loser;
  1.1434 +
  1.1435 +  if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
  1.1436 +    rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
  1.1437 +    if (NS_FAILED(rv))
  1.1438 +      goto loser;
  1.1439 +  }
  1.1440 +  rv = nsSetDNForRequest(certReq, reqDN);
  1.1441 +  if (NS_FAILED(rv))
  1.1442 +    goto loser;
  1.1443 +
  1.1444 +  rv = nsSetRegToken(certReq, regToken);
  1.1445 +  if (NS_FAILED(rv))
  1.1446 +    goto loser;
  1.1447 +
  1.1448 +  rv = nsSetAuthenticator(certReq, authenticator);
  1.1449 +  if (NS_FAILED(rv))
  1.1450 +    goto loser;
  1.1451 +
  1.1452 + rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 
  1.1453 +  if (NS_FAILED(rv))
  1.1454 +    goto loser;
  1.1455 +
  1.1456 +  return certReq;
  1.1457 +loser:
  1.1458 +  if (certReq) {
  1.1459 +    CRMF_DestroyCertRequest(certReq);
  1.1460 +  }
  1.1461 +  return nullptr;
  1.1462 +}
  1.1463 +
  1.1464 +/*
  1.1465 + * This function will set the Proof Of Possession (POP) for a request
  1.1466 + * associated with a key pair intended to do Key Encipherment.  Currently
  1.1467 + * this means encryption only keys.
  1.1468 + */
  1.1469 +static nsresult
  1.1470 +nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
  1.1471 +{
  1.1472 +  SECItem       bitString;
  1.1473 +  unsigned char der[2];
  1.1474 +  SECStatus     srv;
  1.1475 +
  1.1476 +  if (isEscrowed) {
  1.1477 +    /* For proof of possession on escrowed keys, we use the
  1.1478 +     * this Message option of POPOPrivKey and include a zero
  1.1479 +     * length bit string in the POP field.  This is OK because the encrypted
  1.1480 +     * private key already exists as part of the PKIArchiveOptions
  1.1481 +     * Control and that for all intents and purposes proves that
  1.1482 +     * we do own the private key.
  1.1483 +     */
  1.1484 +    der[0] = 0x03; /*We've got a bit string          */
  1.1485 +    der[1] = 0x00; /*We've got a 0 length bit string */
  1.1486 +    bitString.data = der;
  1.1487 +    bitString.len  = 2;
  1.1488 +    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
  1.1489 +                                              crmfNoSubseqMess, &bitString);
  1.1490 +  } else {
  1.1491 +    /* If the encryption key is not being escrowed, then we set the 
  1.1492 +     * Proof Of Possession to be a Challenge Response mechanism.
  1.1493 +     */
  1.1494 +    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
  1.1495 +                                              crmfSubsequentMessage,
  1.1496 +                                              crmfChallengeResp, nullptr);
  1.1497 +  }
  1.1498 +  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
  1.1499 +}
  1.1500 +
  1.1501 +static void
  1.1502 +nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
  1.1503 +
  1.1504 +static void
  1.1505 +nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
  1.1506 +
  1.1507 +static nsresult
  1.1508 +nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 
  1.1509 +                                 nsKeyPairInfo  *keyInfo,
  1.1510 +                                 CRMFCertRequest *certReq)
  1.1511 +{
  1.1512 +  // RFC 2511 Appendix A section 2 a) defines,
  1.1513 +  // the "text" input for HMAC shall be the DER encoded version of
  1.1514 +  // of the single cert request.
  1.1515 +  // We'll produce that encoding and destroy it afterwards,
  1.1516 +  // because when sending the complete package to the CA,
  1.1517 +  // we'll use a different encoding, one that includes POP and
  1.1518 +  // allows multiple requests to be sent in one step.
  1.1519 +
  1.1520 +  unsigned long der_request_len = 0;
  1.1521 +  ScopedSECItem der_request;
  1.1522 +
  1.1523 +  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
  1.1524 +                                           nsCRMFEncoderItemCount, 
  1.1525 +                                           &der_request_len))
  1.1526 +    return NS_ERROR_FAILURE;
  1.1527 +
  1.1528 +  der_request = SECITEM_AllocItem(nullptr, nullptr, der_request_len);
  1.1529 +  if (!der_request)
  1.1530 +    return NS_ERROR_FAILURE;
  1.1531 +
  1.1532 +  // set len in returned SECItem back to zero, because it will
  1.1533 +  // be used as the destination offset inside the 
  1.1534 +  // nsCRMFEncoderItemStore callback.
  1.1535 +
  1.1536 +  der_request->len = 0;
  1.1537 +
  1.1538 +  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
  1.1539 +                                           nsCRMFEncoderItemStore, 
  1.1540 +                                           der_request))
  1.1541 +    return NS_ERROR_FAILURE;
  1.1542 +
  1.1543 +  // RFC 2511 Appendix A section 2 c):
  1.1544 +  // "A key K is derived from the shared secret Kec and the subject and
  1.1545 +  //  issuer names in the CA's certificate as follows:
  1.1546 +  //  K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
  1.1547 +
  1.1548 +  ScopedPK11SymKey shared_secret;
  1.1549 +  ScopedPK11SymKey subject_and_secret;
  1.1550 +  ScopedPK11SymKey subject_and_secret_and_issuer;
  1.1551 +  ScopedPK11SymKey sha1_of_subject_and_secret_and_issuer;
  1.1552 +
  1.1553 +  shared_secret = 
  1.1554 +    PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
  1.1555 +                          keyInfo->ecPopPubKey,  // SECKEYPublicKey *pubKey
  1.1556 +                          false, // bool isSender
  1.1557 +                          nullptr, // SECItem *randomA
  1.1558 +                          nullptr, // SECItem *randomB
  1.1559 +                          CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
  1.1560 +                          CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
  1.1561 +                          CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1.1562 +                          0, // int keySize
  1.1563 +                          CKD_NULL, // CK_ULONG kdf
  1.1564 +                          nullptr, // SECItem *sharedData
  1.1565 +                          nullptr); // void *wincx
  1.1566 +
  1.1567 +  if (!shared_secret)
  1.1568 +    return NS_ERROR_FAILURE;
  1.1569 +
  1.1570 +  CK_KEY_DERIVATION_STRING_DATA concat_data_base;
  1.1571 +  concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
  1.1572 +  concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
  1.1573 +  SECItem concat_data_base_item;
  1.1574 +  concat_data_base_item.data = (unsigned char*)&concat_data_base;
  1.1575 +  concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
  1.1576 +
  1.1577 +  subject_and_secret =
  1.1578 +    PK11_Derive(shared_secret, // PK11SymKey *baseKey
  1.1579 +                CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
  1.1580 +                &concat_data_base_item, // SECItem *param
  1.1581 +                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
  1.1582 +                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1.1583 +                0); // int keySize
  1.1584 +
  1.1585 +  if (!subject_and_secret)
  1.1586 +    return NS_ERROR_FAILURE;
  1.1587 +
  1.1588 +  CK_KEY_DERIVATION_STRING_DATA concat_base_data;
  1.1589 +  concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
  1.1590 +  concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
  1.1591 +  SECItem concat_base_data_item;
  1.1592 +  concat_base_data_item.data = (unsigned char*)&concat_base_data;
  1.1593 +  concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
  1.1594 +
  1.1595 +  subject_and_secret_and_issuer =
  1.1596 +    PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
  1.1597 +                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
  1.1598 +                &concat_base_data_item, // SECItem *param
  1.1599 +                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
  1.1600 +                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
  1.1601 +                0); // int keySize
  1.1602 +
  1.1603 +  if (!subject_and_secret_and_issuer)
  1.1604 +    return NS_ERROR_FAILURE;
  1.1605 +
  1.1606 +  sha1_of_subject_and_secret_and_issuer =
  1.1607 +    PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
  1.1608 +                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
  1.1609 +                nullptr, // SECItem *param
  1.1610 +                CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
  1.1611 +                CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
  1.1612 +                0); // int keySize
  1.1613 +
  1.1614 +  if (!sha1_of_subject_and_secret_and_issuer)
  1.1615 +    return NS_ERROR_FAILURE;
  1.1616 +
  1.1617 +  PK11Context *context = nullptr;
  1.1618 +  PK11ContextCleanerTrueParam context_cleaner(context);
  1.1619 +
  1.1620 +  SECItem ignore;
  1.1621 +  ignore.data = 0;
  1.1622 +  ignore.len = 0;
  1.1623 +
  1.1624 +  context = 
  1.1625 +    PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
  1.1626 +                               CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
  1.1627 +                               sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
  1.1628 +                               &ignore); // SECItem *param
  1.1629 +
  1.1630 +  if (!context)
  1.1631 +    return NS_ERROR_FAILURE;
  1.1632 +
  1.1633 +  if (SECSuccess != PK11_DigestBegin(context))
  1.1634 +    return NS_ERROR_FAILURE;
  1.1635 +
  1.1636 +  if (SECSuccess != 
  1.1637 +      PK11_DigestOp(context, der_request->data, der_request->len))
  1.1638 +    return NS_ERROR_FAILURE;
  1.1639 +
  1.1640 +  ScopedAutoSECItem result_hmac_sha1_item(SHA1_LENGTH);
  1.1641 +
  1.1642 +  if (SECSuccess !=
  1.1643 +      PK11_DigestFinal(context, 
  1.1644 +                       result_hmac_sha1_item.data, 
  1.1645 +                       &result_hmac_sha1_item.len, 
  1.1646 +                       SHA1_LENGTH))
  1.1647 +    return NS_ERROR_FAILURE;
  1.1648 +
  1.1649 +  if (SECSuccess !=
  1.1650 +      CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
  1.1651 +                                        crmfNoSubseqMess, &result_hmac_sha1_item))
  1.1652 +    return NS_ERROR_FAILURE;
  1.1653 +
  1.1654 +  return NS_OK;
  1.1655 +}
  1.1656 +
  1.1657 +static nsresult
  1.1658 +nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 
  1.1659 +                       nsKeyPairInfo  *keyInfo,
  1.1660 +                       CRMFCertRequest *certReq)
  1.1661 +{
  1.1662 +  // Depending on the type of cert request we'll try
  1.1663 +  // POP mechanisms in different order,
  1.1664 +  // and add the result to the cert request message.
  1.1665 +  //
  1.1666 +  // For any signing or dual use cert,
  1.1667 +  //   try signing first,
  1.1668 +  //   fall back to DHMAC if we can
  1.1669 +  //     (EC cert requests that provide keygen param "popcert"),
  1.1670 +  //   otherwise fail.
  1.1671 +  //
  1.1672 +  // For encryption only certs that get escrowed, this is sufficient.
  1.1673 +  //
  1.1674 +  // For encryption only certs, that are not being escrowed, 
  1.1675 +  //   try DHMAC if we can 
  1.1676 +  //     (EC cert requests that provide keygen param "popcert"),
  1.1677 +  //   otherwise we'll indicate challenge response should be used.
  1.1678 +  
  1.1679 +  bool isEncryptionOnlyCertRequest = false;
  1.1680 +  bool escrowEncryptionOnlyCert = false;
  1.1681 +  
  1.1682 +  switch (keyInfo->keyGenType)
  1.1683 +  {
  1.1684 +    case rsaEnc:
  1.1685 +    case ecEnc:
  1.1686 +      isEncryptionOnlyCertRequest = true;
  1.1687 +      break;
  1.1688 +    
  1.1689 +    case rsaSign:
  1.1690 +    case rsaDualUse:
  1.1691 +    case rsaNonrepudiation:
  1.1692 +    case rsaSignNonrepudiation:
  1.1693 +    case ecSign:
  1.1694 +    case ecDualUse:
  1.1695 +    case ecNonrepudiation:
  1.1696 +    case ecSignNonrepudiation:
  1.1697 +    case dsaSign:
  1.1698 +    case dsaNonrepudiation:
  1.1699 +    case dsaSignNonrepudiation:
  1.1700 +      break;
  1.1701 +    
  1.1702 +    case dhEx:
  1.1703 +    /* This case may be supported in the future, but for now, we just fall 
  1.1704 +      * though to the default case and return an error for diffie-hellman keys.
  1.1705 +    */
  1.1706 +    default:
  1.1707 +      return NS_ERROR_FAILURE;
  1.1708 +  };
  1.1709 +    
  1.1710 +  if (isEncryptionOnlyCertRequest)
  1.1711 +  {
  1.1712 +    escrowEncryptionOnlyCert = 
  1.1713 +      CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
  1.1714 +  }
  1.1715 +    
  1.1716 +  bool gotDHMACParameters = false;
  1.1717 +  
  1.1718 +  if (isECKeyGenType(keyInfo->keyGenType) && 
  1.1719 +      keyInfo->ecPopCert && 
  1.1720 +      keyInfo->ecPopPubKey)
  1.1721 +  {
  1.1722 +    gotDHMACParameters = true;
  1.1723 +  }
  1.1724 +  
  1.1725 +  if (isEncryptionOnlyCertRequest)
  1.1726 +  {
  1.1727 +    if (escrowEncryptionOnlyCert)
  1.1728 +      return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
  1.1729 +    
  1.1730 +    if (gotDHMACParameters)
  1.1731 +      return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1.1732 +    
  1.1733 +    return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
  1.1734 +  }
  1.1735 +  
  1.1736 +  // !isEncryptionOnlyCertRequest
  1.1737 +  
  1.1738 +  SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
  1.1739 +                                                 keyInfo->privKey,
  1.1740 +                                                 keyInfo->pubKey, nullptr,
  1.1741 +                                                 nullptr, nullptr);
  1.1742 +
  1.1743 +  if (srv == SECSuccess)
  1.1744 +    return NS_OK;
  1.1745 +  
  1.1746 +  if (!gotDHMACParameters)
  1.1747 +    return NS_ERROR_FAILURE;
  1.1748 +  
  1.1749 +  return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1.1750 +}
  1.1751 +
  1.1752 +static void
  1.1753 +nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
  1.1754 +{
  1.1755 +  unsigned long *count = (unsigned long *)arg;
  1.1756 +  *count += len;
  1.1757 +}
  1.1758 +
  1.1759 +static void
  1.1760 +nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
  1.1761 +{
  1.1762 +  SECItem *dest = (SECItem *)arg;
  1.1763 +  memcpy(dest->data + dest->len, buf, len);
  1.1764 +  dest->len += len;
  1.1765 +}
  1.1766 +
  1.1767 +static SECItem*
  1.1768 +nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
  1.1769 +{
  1.1770 +  unsigned long len = 0;
  1.1771 +  if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
  1.1772 +      != SECSuccess) {
  1.1773 +    return nullptr;
  1.1774 +  }
  1.1775 +  SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
  1.1776 +  if (!dest) {
  1.1777 +    return nullptr;
  1.1778 +  }
  1.1779 +  dest->type = siBuffer;
  1.1780 +  dest->data = (unsigned char *)PORT_Alloc(len);
  1.1781 +  if (!dest->data) {
  1.1782 +    PORT_Free(dest);
  1.1783 +    return nullptr;
  1.1784 +  }
  1.1785 +  dest->len = 0;
  1.1786 +
  1.1787 +  if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
  1.1788 +      != SECSuccess) {
  1.1789 +    SECITEM_FreeItem(dest, true);
  1.1790 +    return nullptr;
  1.1791 +  }
  1.1792 +  return dest;
  1.1793 +}
  1.1794 +
  1.1795 +//Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
  1.1796 +//requesting one or more certificates to be issued.  This function
  1.1797 +//creates a single cert request per key pair and then appends it to
  1.1798 +//a message that is ultimately sent off to a CA.
  1.1799 +static char*
  1.1800 +nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, int32_t numRequests,
  1.1801 +                        char *reqDN, char *regToken, char *authenticator,
  1.1802 +                        nsNSSCertificate *wrappingCert) 
  1.1803 +{
  1.1804 +  // We'use the goto notation for clean-up purposes in this function
  1.1805 +  // that calls the C API of NSS.
  1.1806 +  int32_t i;
  1.1807 +  // The ASN1 encoder in NSS wants the last entry in the array to be
  1.1808 +  // nullptr so that it knows when the last element is.
  1.1809 +  CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
  1.1810 +  CRMFCertRequest *certReq;
  1.1811 +  if (!certReqMsgs)
  1.1812 +    return nullptr;
  1.1813 +  memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
  1.1814 +  SECStatus srv;
  1.1815 +  nsresult rv;
  1.1816 +  SECItem *encodedReq;
  1.1817 +  char *retString;
  1.1818 +  for (i=0; i<numRequests; i++) {
  1.1819 +    certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
  1.1820 +                                    wrappingCert);
  1.1821 +    if (!certReq)
  1.1822 +      goto loser;
  1.1823 +
  1.1824 +    certReqMsgs[i] = CRMF_CreateCertReqMsg();
  1.1825 +    if (!certReqMsgs[i])
  1.1826 +      goto loser;
  1.1827 +    srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
  1.1828 +    if (srv != SECSuccess)
  1.1829 +      goto loser;
  1.1830 +
  1.1831 +    rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
  1.1832 +    if (NS_FAILED(rv))
  1.1833 +      goto loser;
  1.1834 +    CRMF_DestroyCertRequest(certReq);
  1.1835 +  }
  1.1836 +  encodedReq = nsEncodeCertReqMessages(certReqMsgs);
  1.1837 +  nsFreeCertReqMessages(certReqMsgs, numRequests);
  1.1838 +
  1.1839 +  retString = NSSBase64_EncodeItem (nullptr, nullptr, 0, encodedReq);
  1.1840 +  SECITEM_FreeItem(encodedReq, true);
  1.1841 +  return retString;
  1.1842 +loser:
  1.1843 +  nsFreeCertReqMessages(certReqMsgs,numRequests);
  1.1844 +  return nullptr;
  1.1845 +}
  1.1846 +
  1.1847 +static nsISupports *
  1.1848 +GetISupportsFromContext(JSContext *cx)
  1.1849 +{
  1.1850 +    if (JS::ContextOptionsRef(cx).privateIsNSISupports())
  1.1851 +        return static_cast<nsISupports *>(JS_GetContextPrivate(cx));
  1.1852 +
  1.1853 +    return nullptr;
  1.1854 +}
  1.1855 +
  1.1856 +//The top level method which is a member of nsIDOMCrypto
  1.1857 +//for generate a base64 encoded CRMF request.
  1.1858 +CRMFObject*
  1.1859 +nsCrypto::GenerateCRMFRequest(JSContext* aContext,
  1.1860 +                              const nsCString& aReqDN,
  1.1861 +                              const nsCString& aRegToken,
  1.1862 +                              const nsCString& aAuthenticator,
  1.1863 +                              const nsCString& aEaCert,
  1.1864 +                              const nsCString& aJsCallback,
  1.1865 +                              const Sequence<JS::Value>& aArgs,
  1.1866 +                              ErrorResult& aRv)
  1.1867 +{
  1.1868 +  nsNSSShutDownPreventionLock locker;
  1.1869 +  nsresult nrv;
  1.1870 +
  1.1871 +  uint32_t argc = aArgs.Length();
  1.1872 +
  1.1873 +  /*
  1.1874 +   * Get all of the parameters.
  1.1875 +   */
  1.1876 +  if (argc % 3 != 0) {
  1.1877 +    aRv.ThrowNotEnoughArgsError();
  1.1878 +    return nullptr;
  1.1879 +  }
  1.1880 +
  1.1881 +  if (aReqDN.IsVoid()) {
  1.1882 +    NS_WARNING("no DN specified");
  1.1883 +    aRv.Throw(NS_ERROR_FAILURE);
  1.1884 +    return nullptr;
  1.1885 +  }
  1.1886 +
  1.1887 +  if (aJsCallback.IsVoid()) {
  1.1888 +    NS_WARNING("no completion function specified");
  1.1889 +    aRv.Throw(NS_ERROR_FAILURE);
  1.1890 +    return nullptr;
  1.1891 +  }
  1.1892 +
  1.1893 +  JS::RootedObject script_obj(aContext, GetWrapper());
  1.1894 +  if (MOZ_UNLIKELY(!script_obj)) {
  1.1895 +    aRv.Throw(NS_ERROR_UNEXPECTED);
  1.1896 +    return nullptr;
  1.1897 +  }
  1.1898 +
  1.1899 +  nsCOMPtr<nsIContentSecurityPolicy> csp;
  1.1900 +  if (!nsContentUtils::GetContentSecurityPolicy(aContext, getter_AddRefs(csp))) {
  1.1901 +    NS_ERROR("Error: failed to get CSP");
  1.1902 +    aRv.Throw(NS_ERROR_FAILURE);
  1.1903 +    return nullptr;
  1.1904 +  }
  1.1905 +
  1.1906 +  bool evalAllowed = true;
  1.1907 +  bool reportEvalViolations = false;
  1.1908 +  if (csp && NS_FAILED(csp->GetAllowsEval(&reportEvalViolations, &evalAllowed))) {
  1.1909 +    NS_WARNING("CSP: failed to get allowsEval");
  1.1910 +    aRv.Throw(NS_ERROR_FAILURE);
  1.1911 +    return nullptr;
  1.1912 +  }
  1.1913 +
  1.1914 +  if (reportEvalViolations) {
  1.1915 +    NS_NAMED_LITERAL_STRING(scriptSample, "window.crypto.generateCRMFRequest: call to eval() or related function blocked by CSP");
  1.1916 +
  1.1917 +    const char *fileName;
  1.1918 +    uint32_t lineNum;
  1.1919 +    nsJSUtils::GetCallingLocation(aContext, &fileName, &lineNum);
  1.1920 +    csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
  1.1921 +                             NS_ConvertASCIItoUTF16(fileName),
  1.1922 +                             scriptSample,
  1.1923 +                             lineNum,
  1.1924 +                             EmptyString(),
  1.1925 +                             EmptyString());
  1.1926 +  }
  1.1927 +
  1.1928 +  if (!evalAllowed) {
  1.1929 +    NS_WARNING("eval() not allowed by Content Security Policy");
  1.1930 +    aRv.Throw(NS_ERROR_FAILURE);
  1.1931 +    return nullptr;
  1.1932 +  }
  1.1933 +
  1.1934 +  //Put up some UI warning that someone is trying to
  1.1935 +  //escrow the private key.
  1.1936 +  //Don't addref this copy.  That way ths reference goes away
  1.1937 +  //at the same the nsIX09Cert ref goes away.
  1.1938 +  nsNSSCertificate *escrowCert = nullptr;
  1.1939 +  nsCOMPtr<nsIX509Cert> nssCert;
  1.1940 +  bool willEscrow = false;
  1.1941 +  if (!aEaCert.IsVoid()) {
  1.1942 +    SECItem certDer = {siBuffer, nullptr, 0};
  1.1943 +    SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, aEaCert.get());
  1.1944 +    if (srv != SECSuccess) {
  1.1945 +      aRv.Throw(NS_ERROR_FAILURE);
  1.1946 +      return nullptr;
  1.1947 +    }
  1.1948 +    mozilla::pkix::ScopedCERTCertificate cert(
  1.1949 +      CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1.1950 +                              &certDer, nullptr, false, true));
  1.1951 +    if (!cert) {
  1.1952 +      aRv.Throw(NS_ERROR_FAILURE);
  1.1953 +      return nullptr;
  1.1954 +    }
  1.1955 +
  1.1956 +    escrowCert = nsNSSCertificate::Create(cert.get());
  1.1957 +    nssCert = escrowCert;
  1.1958 +    if (!nssCert) {
  1.1959 +      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  1.1960 +      return nullptr;
  1.1961 +    }
  1.1962 +
  1.1963 +    nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
  1.1964 +    nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
  1.1965 +                                NS_GET_IID(nsIDOMCryptoDialogs),
  1.1966 +                                NS_DOMCRYPTODIALOGS_CONTRACTID);
  1.1967 +    if (NS_FAILED(rv)) {
  1.1968 +      aRv.Throw(rv);
  1.1969 +      return nullptr;
  1.1970 +    }
  1.1971 +
  1.1972 +    bool okay=false;
  1.1973 +    {
  1.1974 +      nsPSMUITracker tracker;
  1.1975 +      if (tracker.isUIForbidden()) {
  1.1976 +        okay = false;
  1.1977 +      }
  1.1978 +      else {
  1.1979 +        dialogs->ConfirmKeyEscrow(nssCert, &okay);
  1.1980 +      }
  1.1981 +    }
  1.1982 +    if (!okay) {
  1.1983 +      aRv.Throw(NS_ERROR_FAILURE);
  1.1984 +      return nullptr;
  1.1985 +    }
  1.1986 +    willEscrow = true;
  1.1987 +  }
  1.1988 +  nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
  1.1989 +  int32_t numRequests = argc / 3;
  1.1990 +  nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
  1.1991 +  memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
  1.1992 +  int keyInfoIndex;
  1.1993 +  uint32_t i;
  1.1994 +  PK11SlotInfo *slot = nullptr;
  1.1995 +  // Go through all of the arguments and generate the appropriate key pairs.
  1.1996 +  for (i=0,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
  1.1997 +    nrv = cryptojs_ReadArgsAndGenerateKey(aContext,
  1.1998 +                                          const_cast<JS::Value*>(&aArgs[i]),
  1.1999 +                                          &keyids[keyInfoIndex],
  1.2000 +                                          uiCxt, &slot, willEscrow);
  1.2001 +
  1.2002 +    if (NS_FAILED(nrv)) {
  1.2003 +      if (slot)
  1.2004 +        PK11_FreeSlot(slot);
  1.2005 +      nsFreeKeyPairInfo(keyids,numRequests);
  1.2006 +      aRv.Throw(nrv);
  1.2007 +      return nullptr;
  1.2008 +    }
  1.2009 +  }
  1.2010 +  // By this time we'd better have a slot for the key gen.
  1.2011 +  NS_ASSERTION(slot, "There was no slot selected for key generation");
  1.2012 +  if (slot)
  1.2013 +    PK11_FreeSlot(slot);
  1.2014 +
  1.2015 +  char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
  1.2016 +                                                 const_cast<char*>(aReqDN.get()),
  1.2017 +                                                 const_cast<char*>(aRegToken.get()),
  1.2018 +                                                 const_cast<char*>(aAuthenticator.get()),
  1.2019 +                                                 escrowCert);
  1.2020 +#ifdef DEBUG_javi
  1.2021 +  printf ("Created the folloing CRMF request:\n%s\n", encodedRequest);
  1.2022 +#endif
  1.2023 +  if (!encodedRequest) {
  1.2024 +    nsFreeKeyPairInfo(keyids, numRequests);
  1.2025 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2026 +    return nullptr;
  1.2027 +  }
  1.2028 +  CRMFObject* newObject = new CRMFObject();
  1.2029 +  newObject->SetCRMFRequest(encodedRequest);
  1.2030 +  PORT_Free(encodedRequest);
  1.2031 +  nsFreeKeyPairInfo(keyids, numRequests);
  1.2032 +
  1.2033 +  // Post an event on the UI queue so that the JS gets called after
  1.2034 +  // we return control to the JS layer.  Why do we have to this?
  1.2035 +  // Because when this API was implemented for PSM 1.x w/ Communicator,
  1.2036 +  // the only way to make this method work was to have a callback
  1.2037 +  // in the JS layer that got called after key generation had happened.
  1.2038 +  // So for backwards compatibility, we return control and then just post
  1.2039 +  // an event to call the JS the script provides as the code to execute
  1.2040 +  // when the request has been generated.
  1.2041 +  //
  1.2042 +
  1.2043 +  nsCOMPtr<nsIScriptSecurityManager> secMan =
  1.2044 +    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
  1.2045 +  if (MOZ_UNLIKELY(!secMan)) {
  1.2046 +    aRv.Throw(NS_ERROR_UNEXPECTED);
  1.2047 +    return nullptr;
  1.2048 +  }
  1.2049 +
  1.2050 +  nsCOMPtr<nsIPrincipal> principals;
  1.2051 +  nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals));
  1.2052 +  if (NS_FAILED(nrv)) {
  1.2053 +    aRv.Throw(nrv);
  1.2054 +    return nullptr;
  1.2055 +  }
  1.2056 +  if (MOZ_UNLIKELY(!principals)) {
  1.2057 +    aRv.Throw(NS_ERROR_UNEXPECTED);
  1.2058 +    return nullptr;
  1.2059 +  }
  1.2060 +
  1.2061 +  nsCryptoRunArgs *args = new nsCryptoRunArgs(aContext);
  1.2062 +
  1.2063 +  args->m_kungFuDeathGrip = GetISupportsFromContext(aContext);
  1.2064 +  args->m_scope      = JS_GetParent(script_obj);
  1.2065 +  if (!aJsCallback.IsVoid()) {
  1.2066 +    args->m_jsCallback = aJsCallback;
  1.2067 +  }
  1.2068 +  args->m_principals = principals;
  1.2069 +
  1.2070 +  nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args);
  1.2071 +
  1.2072 +  rv = NS_DispatchToMainThread(cryptoRunnable);
  1.2073 +  if (NS_FAILED(rv)) {
  1.2074 +    aRv.Throw(rv);
  1.2075 +    delete cryptoRunnable;
  1.2076 +  }
  1.2077 +
  1.2078 +  return newObject;
  1.2079 +}
  1.2080 +
  1.2081 +// Reminder that we inherit the memory passed into us here.
  1.2082 +// An implementation to let us back up certs as an event.
  1.2083 +nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts,
  1.2084 +                             nsIPK11Token *token)
  1.2085 +{
  1.2086 +  mCertArr  = certArr;
  1.2087 +  mNumCerts = numCerts;
  1.2088 +  mToken = token;
  1.2089 +}
  1.2090 +
  1.2091 +nsP12Runnable::~nsP12Runnable()
  1.2092 +{
  1.2093 +  int32_t i;
  1.2094 +  for (i=0; i<mNumCerts; i++) {
  1.2095 +      NS_IF_RELEASE(mCertArr[i]);
  1.2096 +  }
  1.2097 +  delete []mCertArr;
  1.2098 +}
  1.2099 +
  1.2100 +
  1.2101 +//Implementation that backs cert(s) into a PKCS12 file
  1.2102 +NS_IMETHODIMP
  1.2103 +nsP12Runnable::Run()
  1.2104 +{
  1.2105 +  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1.2106 +
  1.2107 +  NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
  1.2108 +
  1.2109 +  nsNSSShutDownPreventionLock locker;
  1.2110 +  NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
  1.2111 +
  1.2112 +  nsString final;
  1.2113 +  nsString temp;
  1.2114 +  nsresult rv;
  1.2115 +
  1.2116 +  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1.2117 +  if (NS_FAILED(rv))
  1.2118 +    return rv;
  1.2119 +
  1.2120 +  //Build up the message that let's the user know we're trying to 
  1.2121 +  //make PKCS12 backups of the new certs.
  1.2122 +  nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
  1.2123 +  final.Append(MOZ_UTF16("\n\n"));
  1.2124 +  nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
  1.2125 +  final.Append(temp.get());
  1.2126 +  final.Append(MOZ_UTF16("\n\n"));
  1.2127 +
  1.2128 +  nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
  1.2129 +
  1.2130 +  final.Append(temp.get());
  1.2131 +  nsNSSComponent::ShowAlertWithConstructedString(final);
  1.2132 +
  1.2133 +  nsCOMPtr<nsIFilePicker> filePicker = 
  1.2134 +                        do_CreateInstance("@mozilla.org/filepicker;1", &rv);
  1.2135 +  if (!filePicker) {
  1.2136 +    NS_ERROR("Could not create a file picker when backing up certs.");
  1.2137 +    return rv;
  1.2138 +  }
  1.2139 +
  1.2140 +  nsCOMPtr<nsIWindowWatcher> wwatch =
  1.2141 +    (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
  1.2142 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2143 +
  1.2144 +  nsCOMPtr<nsIDOMWindow> window;
  1.2145 +  wwatch->GetActiveWindow(getter_AddRefs(window));
  1.2146 +
  1.2147 +  nsString filePickMessage;
  1.2148 +  nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
  1.2149 +                                      filePickMessage);
  1.2150 +  rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
  1.2151 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2152 +
  1.2153 +  filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
  1.2154 +                           NS_LITERAL_STRING("*.p12"));
  1.2155 +  filePicker->AppendFilters(nsIFilePicker::filterAll);
  1.2156 +
  1.2157 +  int16_t dialogReturn;
  1.2158 +  filePicker->Show(&dialogReturn);
  1.2159 +  if (dialogReturn == nsIFilePicker::returnCancel)
  1.2160 +    return NS_OK;  //User canceled.  It'd be nice if they couldn't, 
  1.2161 +                   //but oh well.
  1.2162 +
  1.2163 +  nsCOMPtr<nsIFile> localFile;
  1.2164 +  rv = filePicker->GetFile(getter_AddRefs(localFile));
  1.2165 +  if (NS_FAILED(rv))
  1.2166 +    return NS_ERROR_FAILURE;
  1.2167 +
  1.2168 +  nsPKCS12Blob p12Cxt;
  1.2169 +  
  1.2170 +  p12Cxt.SetToken(mToken);
  1.2171 +  p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
  1.2172 +  return NS_OK;
  1.2173 +}
  1.2174 +
  1.2175 +nsCryptoRunArgs::nsCryptoRunArgs(JSContext *cx) : m_cx(cx), m_scope(cx) {}
  1.2176 +
  1.2177 +nsCryptoRunArgs::~nsCryptoRunArgs() {}
  1.2178 +
  1.2179 +nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
  1.2180 +{
  1.2181 +  nsNSSShutDownPreventionLock locker;
  1.2182 +  NS_ASSERTION(args,"Passed nullptr to nsCryptoRunnable constructor.");
  1.2183 +  m_args = args;
  1.2184 +  NS_IF_ADDREF(m_args);
  1.2185 +}
  1.2186 +
  1.2187 +nsCryptoRunnable::~nsCryptoRunnable()
  1.2188 +{
  1.2189 +  nsNSSShutDownPreventionLock locker;
  1.2190 +  NS_IF_RELEASE(m_args);
  1.2191 +}
  1.2192 +
  1.2193 +//Implementation that runs the callback passed to 
  1.2194 +//crypto.generateCRMFRequest as an event.
  1.2195 +NS_IMETHODIMP
  1.2196 +nsCryptoRunnable::Run()
  1.2197 +{
  1.2198 +  nsNSSShutDownPreventionLock locker;
  1.2199 +  AutoPushJSContext cx(m_args->m_cx);
  1.2200 +  JSAutoRequest ar(cx);
  1.2201 +  JS::Rooted<JSObject*> scope(cx, m_args->m_scope);
  1.2202 +  JSAutoCompartment ac(cx, scope);
  1.2203 +
  1.2204 +  bool ok =
  1.2205 +    JS_EvaluateScript(cx, scope, m_args->m_jsCallback,
  1.2206 +                      strlen(m_args->m_jsCallback), nullptr, 0);
  1.2207 +  return ok ? NS_OK : NS_ERROR_FAILURE;
  1.2208 +}
  1.2209 +
  1.2210 +//Quick helper function to check if a newly issued cert
  1.2211 +//already exists in the user's database.
  1.2212 +static bool
  1.2213 +nsCertAlreadyExists(SECItem *derCert)
  1.2214 +{
  1.2215 +  CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
  1.2216 +  bool retVal = false;
  1.2217 +
  1.2218 +  mozilla::pkix::ScopedCERTCertificate cert(
  1.2219 +    CERT_FindCertByDERCert(handle, derCert));
  1.2220 +  if (cert) {
  1.2221 +    if (cert->isperm && !cert->nickname && !cert->emailAddr) {
  1.2222 +      //If the cert doesn't have a nickname or email addr, it is
  1.2223 +      //bogus cruft, so delete it.
  1.2224 +      SEC_DeletePermCertificate(cert.get());
  1.2225 +    } else if (cert->isperm) {
  1.2226 +      retVal = true;
  1.2227 +    }
  1.2228 +  }
  1.2229 +  return retVal;
  1.2230 +}
  1.2231 +
  1.2232 +static int32_t
  1.2233 +nsCertListCount(CERTCertList *certList)
  1.2234 +{
  1.2235 +  int32_t numCerts = 0;
  1.2236 +  CERTCertListNode *node;
  1.2237 +
  1.2238 +  node = CERT_LIST_HEAD(certList);
  1.2239 +  while (!CERT_LIST_END(node, certList)) {
  1.2240 +    numCerts++;
  1.2241 +    node = CERT_LIST_NEXT(node);
  1.2242 +  }
  1.2243 +  return numCerts;
  1.2244 +}
  1.2245 +
  1.2246 +//Import user certificates that arrive as a CMMF base64 encoded
  1.2247 +//string.
  1.2248 +void
  1.2249 +nsCrypto::ImportUserCertificates(const nsAString& aNickname,
  1.2250 +                                 const nsAString& aCmmfResponse,
  1.2251 +                                 bool aDoForcedBackup,
  1.2252 +                                 nsAString& aReturn,
  1.2253 +                                 ErrorResult& aRv)
  1.2254 +{
  1.2255 +  nsNSSShutDownPreventionLock locker;
  1.2256 +  char *nickname=nullptr, *cmmfResponse=nullptr;
  1.2257 +  CMMFCertRepContent *certRepContent = nullptr;
  1.2258 +  int numResponses = 0;
  1.2259 +  nsIX509Cert **certArr = nullptr;
  1.2260 +  int i;
  1.2261 +  CMMFCertResponse *currResponse;
  1.2262 +  CMMFPKIStatus reqStatus;
  1.2263 +  CERTCertificate *currCert;
  1.2264 +  PK11SlotInfo *slot;
  1.2265 +  nsAutoCString localNick;
  1.2266 +  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  1.2267 +  nsresult rv = NS_OK;
  1.2268 +  nsCOMPtr<nsIPK11Token> token;
  1.2269 +
  1.2270 +  nickname = ToNewCString(aNickname);
  1.2271 +  cmmfResponse = ToNewCString(aCmmfResponse);
  1.2272 +  if (nsCRT::strcmp("null", nickname) == 0) {
  1.2273 +    nsMemory::Free(nickname);
  1.2274 +    nickname = nullptr;
  1.2275 +  }
  1.2276 +
  1.2277 +  SECItem cmmfDer = {siBuffer, nullptr, 0};
  1.2278 +  SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
  1.2279 +
  1.2280 +  if (srv != SECSuccess) {
  1.2281 +    rv = NS_ERROR_FAILURE;
  1.2282 +    goto loser;
  1.2283 +  }
  1.2284 +
  1.2285 +  certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
  1.2286 +                                                    (const char*)cmmfDer.data,
  1.2287 +                                                    cmmfDer.len);
  1.2288 +  if (!certRepContent) {
  1.2289 +    rv = NS_ERROR_FAILURE;
  1.2290 +    goto loser;
  1.2291 +  }
  1.2292 +
  1.2293 +  numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
  1.2294 +
  1.2295 +  if (aDoForcedBackup) {
  1.2296 +    //We've been asked to force the user to back up these
  1.2297 +    //certificates.  Let's keep an array of them around which
  1.2298 +    //we pass along to the nsP12Runnable to use.
  1.2299 +    certArr = new nsIX509Cert*[numResponses];
  1.2300 +    // If this is nullptr, chances are we're gonna fail really
  1.2301 +    // soon, but let's try to keep going just in case.
  1.2302 +    if (!certArr)
  1.2303 +      aDoForcedBackup = false;
  1.2304 +
  1.2305 +    memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
  1.2306 +  }
  1.2307 +  for (i=0; i<numResponses; i++) {
  1.2308 +    currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
  1.2309 +    if (!currResponse) {
  1.2310 +      rv = NS_ERROR_FAILURE;
  1.2311 +      goto loser;
  1.2312 +    }
  1.2313 +    reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
  1.2314 +    if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
  1.2315 +      // The CA didn't give us the cert we requested.
  1.2316 +      rv = NS_ERROR_FAILURE;
  1.2317 +      goto loser;
  1.2318 +    }
  1.2319 +    currCert = CMMF_CertResponseGetCertificate(currResponse, 
  1.2320 +                                               CERT_GetDefaultCertDB());
  1.2321 +    if (!currCert) {
  1.2322 +      rv = NS_ERROR_FAILURE;
  1.2323 +      goto loser;
  1.2324 +    }
  1.2325 +
  1.2326 +    if (nsCertAlreadyExists(&currCert->derCert)) {
  1.2327 +      if (aDoForcedBackup) {
  1.2328 +        certArr[i] = nsNSSCertificate::Create(currCert);
  1.2329 +        if (!certArr[i])
  1.2330 +          goto loser;
  1.2331 +        NS_ADDREF(certArr[i]);
  1.2332 +      }
  1.2333 +      CERT_DestroyCertificate(currCert);
  1.2334 +      CMMF_DestroyCertResponse(currResponse);
  1.2335 +      continue;
  1.2336 +    }
  1.2337 +    // Let's figure out which nickname to give the cert.  If 
  1.2338 +    // a certificate with the same subject name already exists,
  1.2339 +    // then just use that one, otherwise, get the default nickname.
  1.2340 +    if (currCert->nickname) {
  1.2341 +      localNick = currCert->nickname;
  1.2342 +    }
  1.2343 +    else if (!nickname || nickname[0] == '\0') {
  1.2344 +      nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick, locker);
  1.2345 +    } else {
  1.2346 +      //This is the case where we're getting a brand new
  1.2347 +      //cert that doesn't have the same subjectName as a cert
  1.2348 +      //that already exists in our db and the CA page has 
  1.2349 +      //designated a nickname to use for the newly issued cert.
  1.2350 +      localNick = nickname;
  1.2351 +    }
  1.2352 +    {
  1.2353 +      char *cast_const_away = const_cast<char*>(localNick.get());
  1.2354 +      slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
  1.2355 +    }
  1.2356 +    if (!slot) {
  1.2357 +      rv = NS_ERROR_FAILURE;
  1.2358 +      goto loser;
  1.2359 +    }
  1.2360 +    if (aDoForcedBackup) {
  1.2361 +      certArr[i] = nsNSSCertificate::Create(currCert);
  1.2362 +      if (!certArr[i])
  1.2363 +        goto loser;
  1.2364 +      NS_ADDREF(certArr[i]);
  1.2365 +    }
  1.2366 +    CERT_DestroyCertificate(currCert);
  1.2367 +
  1.2368 +    if (!token)
  1.2369 +      token = new nsPK11Token(slot);
  1.2370 +
  1.2371 +    PK11_FreeSlot(slot);
  1.2372 +    CMMF_DestroyCertResponse(currResponse);
  1.2373 +  }
  1.2374 +  //Let the loser: label take care of freeing up our reference to
  1.2375 +  //nickname (This way we don't free it twice and avoid crashing.
  1.2376 +  //That would be a good thing.
  1.2377 +
  1.2378 +  //Import the root chain into the cert db.
  1.2379 + {
  1.2380 +  mozilla::pkix::ScopedCERTCertList
  1.2381 +    caPubs(CMMF_CertRepContentGetCAPubs(certRepContent));
  1.2382 +  if (caPubs) {
  1.2383 +    int32_t numCAs = nsCertListCount(caPubs.get());
  1.2384 +    
  1.2385 +    NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
  1.2386 +    if (numCAs > 0) {
  1.2387 +      CERTCertListNode *node;
  1.2388 +      SECItem *derCerts;
  1.2389 +
  1.2390 +      derCerts = static_cast<SECItem*>
  1.2391 +                            (nsMemory::Alloc(sizeof(SECItem)*numCAs));
  1.2392 +      if (!derCerts) {
  1.2393 +        rv = NS_ERROR_OUT_OF_MEMORY;
  1.2394 +        goto loser;
  1.2395 +      }
  1.2396 +      for (node = CERT_LIST_HEAD(caPubs), i=0; 
  1.2397 +           !CERT_LIST_END(node, caPubs);
  1.2398 +           node = CERT_LIST_NEXT(node), i++) {
  1.2399 +        derCerts[i] = node->cert->derCert;
  1.2400 +      }
  1.2401 +      nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx, locker);
  1.2402 +      nsMemory::Free(derCerts);
  1.2403 +    }
  1.2404 +  }
  1.2405 + }
  1.2406 +
  1.2407 +  if (aDoForcedBackup) {
  1.2408 +    // I can't pop up a file picker from the depths of JavaScript,
  1.2409 +    // so I'll just post an event on the UI queue to do the backups
  1.2410 +    // later.
  1.2411 +    nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
  1.2412 +                                                          token);
  1.2413 +    if (!p12Runnable) {
  1.2414 +      rv = NS_ERROR_FAILURE;
  1.2415 +      goto loser;
  1.2416 +    }
  1.2417 +
  1.2418 +    // null out the certArr pointer which has now been inherited by
  1.2419 +    // the nsP12Runnable instance so that we don't free up the
  1.2420 +    // memory on the way out.
  1.2421 +    certArr = nullptr;
  1.2422 +
  1.2423 +    rv = NS_DispatchToMainThread(p12Runnable);
  1.2424 +    if (NS_FAILED(rv))
  1.2425 +      goto loser;
  1.2426 +  }
  1.2427 +
  1.2428 + loser:
  1.2429 +  if (certArr) {
  1.2430 +    for (i=0; i<numResponses; i++) {
  1.2431 +      NS_IF_RELEASE(certArr[i]);
  1.2432 +    }
  1.2433 +    delete []certArr;
  1.2434 +  }
  1.2435 +  aReturn.Assign(EmptyString());
  1.2436 +  if (nickname) {
  1.2437 +    NS_Free(nickname);
  1.2438 +  }
  1.2439 +  if (cmmfResponse) {
  1.2440 +    NS_Free(cmmfResponse);
  1.2441 +  }
  1.2442 +  if (certRepContent) {
  1.2443 +    CMMF_DestroyCertRepContent(certRepContent);
  1.2444 +  }
  1.2445 +
  1.2446 +  if (NS_FAILED(rv)) {
  1.2447 +    aRv.Throw(rv);
  1.2448 +  }
  1.2449 +}
  1.2450 +
  1.2451 +static void
  1.2452 +GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
  1.2453 +{
  1.2454 +  // Get the script context.
  1.2455 +  nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
  1.2456 +  if (!scriptContext) {
  1.2457 +    return;
  1.2458 +  }
  1.2459 +
  1.2460 +  nsCOMPtr<nsIDOMWindow> domWindow = 
  1.2461 +    do_QueryInterface(scriptContext->GetGlobalObject());
  1.2462 +  if (!domWindow) {
  1.2463 +    return;
  1.2464 +  }
  1.2465 +
  1.2466 +  nsCOMPtr<nsIDOMDocument> domDocument;
  1.2467 +  domWindow->GetDocument(getter_AddRefs(domDocument));
  1.2468 +  if (!domDocument) {
  1.2469 +    return;
  1.2470 +  }
  1.2471 +
  1.2472 +  CallQueryInterface(domDocument, aDocument);
  1.2473 +
  1.2474 +  return;
  1.2475 +}
  1.2476 +
  1.2477 +void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
  1.2478 +{
  1.2479 +  ((nsCString*)arg)->Append(buf, len);
  1.2480 +}
  1.2481 +
  1.2482 +void
  1.2483 +nsCrypto::SignText(JSContext* aContext,
  1.2484 +                   const nsAString& aStringToSign,
  1.2485 +                   const nsAString& aCaOption,
  1.2486 +                   const Sequence<nsCString>& aArgs,
  1.2487 +                   nsAString& aReturn)
  1.2488 +{
  1.2489 +  // XXX This code should return error codes, but we're keeping this
  1.2490 +  //     backwards compatible with NS4.x and so we can't throw exceptions.
  1.2491 +  NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
  1.2492 +
  1.2493 +  aReturn.Truncate();
  1.2494 +
  1.2495 +  uint32_t argc = aArgs.Length();
  1.2496 +
  1.2497 +  if (!aCaOption.EqualsLiteral("auto") &&
  1.2498 +      !aCaOption.EqualsLiteral("ask")) {
  1.2499 +    NS_WARNING("caOption argument must be ask or auto");
  1.2500 +    aReturn.Append(internalError);
  1.2501 +
  1.2502 +    return;
  1.2503 +  }
  1.2504 +
  1.2505 +  // It was decided to always behave as if "ask" were specified.
  1.2506 +  // XXX Should we warn in the JS Console for auto?
  1.2507 +
  1.2508 +  nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
  1.2509 +  if (!uiContext) {
  1.2510 +    aReturn.Append(internalError);
  1.2511 +
  1.2512 +    return;
  1.2513 +  }
  1.2514 +
  1.2515 +  bool bestOnly = true;
  1.2516 +  bool validOnly = true;
  1.2517 +  CERTCertList* certList =
  1.2518 +    CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
  1.2519 +                              bestOnly, validOnly, uiContext);
  1.2520 +
  1.2521 +  uint32_t numCAs = argc;
  1.2522 +  if (numCAs > 0) {
  1.2523 +    nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
  1.2524 +    if (!caNames) {
  1.2525 +      aReturn.Append(internalError);
  1.2526 +      return;
  1.2527 +    }
  1.2528 +
  1.2529 +    uint32_t i;
  1.2530 +    for (i = 0; i < numCAs; ++i)
  1.2531 +      caNames[i] = const_cast<char*>(aArgs[i].get());
  1.2532 +
  1.2533 +    if (certList &&
  1.2534 +        CERT_FilterCertListByCANames(certList, numCAs, caNames,
  1.2535 +                                     certUsageEmailSigner) != SECSuccess) {
  1.2536 +      aReturn.Append(internalError);
  1.2537 +
  1.2538 +      return;
  1.2539 +    }
  1.2540 +  }
  1.2541 +
  1.2542 +  if (!certList || CERT_LIST_EMPTY(certList)) {
  1.2543 +    aReturn.AppendLiteral("error:noMatchingCert");
  1.2544 +
  1.2545 +    return;
  1.2546 +  }
  1.2547 +
  1.2548 +  nsCOMPtr<nsIFormSigningDialog> fsd =
  1.2549 +    do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
  1.2550 +  if (!fsd) {
  1.2551 +    aReturn.Append(internalError);
  1.2552 +
  1.2553 +    return;
  1.2554 +  }
  1.2555 +
  1.2556 +  nsCOMPtr<nsIDocument> document;
  1.2557 +  GetDocumentFromContext(aContext, getter_AddRefs(document));
  1.2558 +  if (!document) {
  1.2559 +    aReturn.Append(internalError);
  1.2560 +
  1.2561 +    return;
  1.2562 +  }
  1.2563 +
  1.2564 +  // Get the hostname from the URL of the document.
  1.2565 +  nsIURI* uri = document->GetDocumentURI();
  1.2566 +  if (!uri) {
  1.2567 +    aReturn.Append(internalError);
  1.2568 +
  1.2569 +    return;
  1.2570 +  }
  1.2571 +
  1.2572 +  nsresult rv;
  1.2573 +
  1.2574 +  nsCString host;
  1.2575 +  rv = uri->GetHost(host);
  1.2576 +  if (NS_FAILED(rv)) {
  1.2577 +    aReturn.Append(internalError);
  1.2578 +
  1.2579 +    return;
  1.2580 +  }
  1.2581 +
  1.2582 +  int32_t numberOfCerts = 0;
  1.2583 +  CERTCertListNode* node;
  1.2584 +  for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  1.2585 +       node = CERT_LIST_NEXT(node)) {
  1.2586 +    ++numberOfCerts;
  1.2587 +  }
  1.2588 +
  1.2589 +  ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList));
  1.2590 +
  1.2591 +  if (!nicknames) {
  1.2592 +    aReturn.Append(internalError);
  1.2593 +
  1.2594 +    return;
  1.2595 +  }
  1.2596 +
  1.2597 +  NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
  1.2598 +               "nicknames->numnicknames != numberOfCerts");
  1.2599 +
  1.2600 +  nsAutoArrayPtr<char16_t*> certNicknameList(new char16_t*[nicknames->numnicknames * 2]);
  1.2601 +  if (!certNicknameList) {
  1.2602 +    aReturn.Append(internalError);
  1.2603 +
  1.2604 +    return;
  1.2605 +  }
  1.2606 +
  1.2607 +  char16_t** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
  1.2608 +
  1.2609 +  int32_t certsToUse;
  1.2610 +  for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
  1.2611 +       !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
  1.2612 +       node = CERT_LIST_NEXT(node)) {
  1.2613 +    RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
  1.2614 +    if (tempCert) {
  1.2615 +      nsAutoString nickWithSerial, details;
  1.2616 +      rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
  1.2617 +                                     nickWithSerial, details);
  1.2618 +      if (NS_SUCCEEDED(rv)) {
  1.2619 +        certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
  1.2620 +        if (certNicknameList[certsToUse]) {
  1.2621 +          certDetailsList[certsToUse] = ToNewUnicode(details);
  1.2622 +          if (!certDetailsList[certsToUse]) {
  1.2623 +            nsMemory::Free(certNicknameList[certsToUse]);
  1.2624 +            continue;
  1.2625 +          }
  1.2626 +          ++certsToUse;
  1.2627 +        }
  1.2628 +      }
  1.2629 +    }
  1.2630 +  }
  1.2631 +
  1.2632 +  if (certsToUse == 0) {
  1.2633 +    aReturn.Append(internalError);
  1.2634 +
  1.2635 +    return;
  1.2636 +  }
  1.2637 +
  1.2638 +  NS_ConvertUTF8toUTF16 utf16Host(host);
  1.2639 +
  1.2640 +  CERTCertificate *signingCert = nullptr;
  1.2641 +  bool tryAgain, canceled;
  1.2642 +  nsAutoString password;
  1.2643 +  do {
  1.2644 +    // Throw up the form signing confirmation dialog and get back the index
  1.2645 +    // of the selected cert.
  1.2646 +    int32_t selectedIndex = -1;
  1.2647 +    rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
  1.2648 +                              const_cast<const char16_t**>(certNicknameList.get()),
  1.2649 +                              const_cast<const char16_t**>(certDetailsList),
  1.2650 +                              certsToUse, &selectedIndex, password,
  1.2651 +                              &canceled);
  1.2652 +    if (NS_FAILED(rv) || canceled) {
  1.2653 +      break; // out of tryAgain loop
  1.2654 +    }
  1.2655 +
  1.2656 +    int32_t j = 0;
  1.2657 +    for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  1.2658 +         node = CERT_LIST_NEXT(node)) {
  1.2659 +      if (j == selectedIndex) {
  1.2660 +        signingCert = CERT_DupCertificate(node->cert);
  1.2661 +        break; // out of cert list iteration loop
  1.2662 +      }
  1.2663 +      ++j;
  1.2664 +    }
  1.2665 +
  1.2666 +    if (!signingCert) {
  1.2667 +      rv = NS_ERROR_FAILURE;
  1.2668 +      break; // out of tryAgain loop
  1.2669 +    }
  1.2670 +
  1.2671 +    NS_ConvertUTF16toUTF8 pwUtf8(password);
  1.2672 +
  1.2673 +    tryAgain =
  1.2674 +      PK11_CheckUserPassword(signingCert->slot,
  1.2675 +                             const_cast<char *>(pwUtf8.get())) != SECSuccess;
  1.2676 +    // XXX we should show an error dialog before retrying
  1.2677 +  } while (tryAgain);
  1.2678 +
  1.2679 +  int32_t k;
  1.2680 +  for (k = 0; k < certsToUse; ++k) {
  1.2681 +    nsMemory::Free(certNicknameList[k]);
  1.2682 +    nsMemory::Free(certDetailsList[k]);
  1.2683 +  }
  1.2684 +
  1.2685 +  if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
  1.2686 +    aReturn.Append(internalError);
  1.2687 +
  1.2688 +    return;
  1.2689 +  }
  1.2690 +
  1.2691 +  if (canceled) {
  1.2692 +    aReturn.AppendLiteral("error:userCancel");
  1.2693 +
  1.2694 +    return;
  1.2695 +  }
  1.2696 +
  1.2697 +  SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
  1.2698 +  if (!privKey) {
  1.2699 +    aReturn.Append(internalError);
  1.2700 +
  1.2701 +    return;
  1.2702 +  }
  1.2703 +
  1.2704 +  nsAutoCString charset(document->GetDocumentCharacterSet());
  1.2705 +
  1.2706 +  // XXX Doing what nsFormSubmission::GetEncoder does (see
  1.2707 +  //     http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
  1.2708 +  if (charset.EqualsLiteral("ISO-8859-1")) {
  1.2709 +    charset.AssignLiteral("windows-1252");
  1.2710 +  }
  1.2711 +
  1.2712 +  nsCOMPtr<nsISaveAsCharset> encoder =
  1.2713 +    do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
  1.2714 +  if (encoder) {
  1.2715 +    rv = encoder->Init(charset.get(),
  1.2716 +                       (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
  1.2717 +                       nsISaveAsCharset::attr_FallbackDecimalNCR),
  1.2718 +                       0);
  1.2719 +  }
  1.2720 +
  1.2721 +  nsXPIDLCString buffer;
  1.2722 +  if (aStringToSign.Length() > 0) {
  1.2723 +    if (encoder && NS_SUCCEEDED(rv)) {
  1.2724 +      rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
  1.2725 +                            getter_Copies(buffer));
  1.2726 +      if (NS_FAILED(rv)) {
  1.2727 +        aReturn.Append(internalError);
  1.2728 +
  1.2729 +        return;
  1.2730 +      }
  1.2731 +    }
  1.2732 +    else {
  1.2733 +      AppendUTF16toUTF8(aStringToSign, buffer);
  1.2734 +    }
  1.2735 +  }
  1.2736 +
  1.2737 +  HASHContext *hc = HASH_Create(HASH_AlgSHA1);
  1.2738 +  if (!hc) {
  1.2739 +    aReturn.Append(internalError);
  1.2740 +
  1.2741 +    return;
  1.2742 +  }
  1.2743 +
  1.2744 +  unsigned char hash[SHA1_LENGTH];
  1.2745 +
  1.2746 +  SECItem digest;
  1.2747 +  digest.data = hash;
  1.2748 +
  1.2749 +  HASH_Begin(hc);
  1.2750 +  HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
  1.2751 +              buffer.Length());
  1.2752 +  HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
  1.2753 +  HASH_Destroy(hc);
  1.2754 +
  1.2755 +  nsCString p7;
  1.2756 +  SECStatus srv = SECFailure;
  1.2757 +
  1.2758 +  SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
  1.2759 +                                                       certUsageEmailSigner,
  1.2760 +                                                       nullptr, SEC_OID_SHA1,
  1.2761 +                                                       &digest, nullptr, uiContext);
  1.2762 +  if (ci) {
  1.2763 +    srv = SEC_PKCS7IncludeCertChain(ci, nullptr);
  1.2764 +    if (srv == SECSuccess) {
  1.2765 +      srv = SEC_PKCS7AddSigningTime(ci);
  1.2766 +      if (srv == SECSuccess) {
  1.2767 +        srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nullptr, nullptr,
  1.2768 +                              uiContext);
  1.2769 +      }
  1.2770 +    }
  1.2771 +
  1.2772 +    SEC_PKCS7DestroyContentInfo(ci);
  1.2773 +  }
  1.2774 +
  1.2775 +  if (srv != SECSuccess) {
  1.2776 +    aReturn.Append(internalError);
  1.2777 +
  1.2778 +    return;
  1.2779 +  }
  1.2780 +
  1.2781 +  SECItem binary_item;
  1.2782 +  binary_item.data = reinterpret_cast<unsigned char*>
  1.2783 +                                     (const_cast<char*>(p7.get()));
  1.2784 +  binary_item.len = p7.Length();
  1.2785 +
  1.2786 +  char *result = NSSBase64_EncodeItem(nullptr, nullptr, 0, &binary_item);
  1.2787 +  if (result) {
  1.2788 +    AppendASCIItoUTF16(result, aReturn);
  1.2789 +  }
  1.2790 +  else {
  1.2791 +    aReturn.Append(internalError);
  1.2792 +  }
  1.2793 +
  1.2794 +  PORT_Free(result);
  1.2795 +
  1.2796 +  return;
  1.2797 +}
  1.2798 +
  1.2799 +void
  1.2800 +nsCrypto::Logout(ErrorResult& aRv)
  1.2801 +{
  1.2802 +  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1.2803 +
  1.2804 +  nsresult rv;
  1.2805 +  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1.2806 +  if (NS_FAILED(rv)) {
  1.2807 +    aRv.Throw(rv);
  1.2808 +    return;
  1.2809 +  }
  1.2810 +
  1.2811 +  {
  1.2812 +    nsNSSShutDownPreventionLock locker;
  1.2813 +    PK11_LogoutAll();
  1.2814 +    SSL_ClearSessionCache();
  1.2815 +  }
  1.2816 +
  1.2817 +  rv = nssComponent->LogoutAuthenticatedPK11();
  1.2818 +  if (NS_FAILED(rv)) {
  1.2819 +    aRv.Throw(rv);
  1.2820 +  }
  1.2821 +}
  1.2822 +
  1.2823 +CRMFObject::CRMFObject()
  1.2824 +{
  1.2825 +  MOZ_COUNT_CTOR(CRMFObject);
  1.2826 +}
  1.2827 +
  1.2828 +CRMFObject::~CRMFObject()
  1.2829 +{
  1.2830 +  MOZ_COUNT_DTOR(CRMFObject);
  1.2831 +}
  1.2832 +
  1.2833 +JSObject*
  1.2834 +CRMFObject::WrapObject(JSContext *aCx, bool* aTookOwnership)
  1.2835 +{
  1.2836 +  return CRMFObjectBinding::Wrap(aCx, this, aTookOwnership);
  1.2837 +}
  1.2838 +
  1.2839 +void
  1.2840 +CRMFObject::GetRequest(nsAString& aRequest)
  1.2841 +{
  1.2842 +  aRequest.Assign(mBase64Request);
  1.2843 +}
  1.2844 +
  1.2845 +nsresult
  1.2846 +CRMFObject::SetCRMFRequest(char *inRequest)
  1.2847 +{
  1.2848 +  mBase64Request.AssignWithConversion(inRequest);  
  1.2849 +  return NS_OK;
  1.2850 +}
  1.2851 +
  1.2852 +#endif // MOZ_DISABLE_CRYPTOLEGACY
  1.2853 +
  1.2854 +nsPkcs11::nsPkcs11()
  1.2855 +{
  1.2856 +}
  1.2857 +
  1.2858 +nsPkcs11::~nsPkcs11()
  1.2859 +{
  1.2860 +}
  1.2861 +
  1.2862 +//Delete a PKCS11 module from the user's profile.
  1.2863 +NS_IMETHODIMP
  1.2864 +nsPkcs11::DeleteModule(const nsAString& aModuleName)
  1.2865 +{
  1.2866 +  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1.2867 +
  1.2868 +  nsNSSShutDownPreventionLock locker;
  1.2869 +  nsresult rv;
  1.2870 +  nsString errorMessage;
  1.2871 +
  1.2872 +  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1.2873 +  if (NS_FAILED(rv))
  1.2874 +    return rv;
  1.2875 +
  1.2876 +  if (aModuleName.IsEmpty()) {
  1.2877 +    return NS_ERROR_ILLEGAL_VALUE;
  1.2878 +  }
  1.2879 +  
  1.2880 +  NS_ConvertUTF16toUTF8 modName(aModuleName);
  1.2881 +  int32_t modType;
  1.2882 +  SECStatus srv = SECMOD_DeleteModule(modName.get(), &modType);
  1.2883 +  if (srv == SECSuccess) {
  1.2884 +    SECMODModule *module = SECMOD_FindModule(modName.get());
  1.2885 +    if (module) {
  1.2886 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
  1.2887 +      nssComponent->ShutdownSmartCardThread(module);
  1.2888 +#endif
  1.2889 +      SECMOD_DestroyModule(module);
  1.2890 +    }
  1.2891 +    rv = NS_OK;
  1.2892 +  } else {
  1.2893 +    rv = NS_ERROR_FAILURE;
  1.2894 +  }
  1.2895 +  return rv;
  1.2896 +}
  1.2897 +
  1.2898 +//Add a new PKCS11 module to the user's profile.
  1.2899 +NS_IMETHODIMP
  1.2900 +nsPkcs11::AddModule(const nsAString& aModuleName, 
  1.2901 +                    const nsAString& aLibraryFullPath, 
  1.2902 +                    int32_t aCryptoMechanismFlags, 
  1.2903 +                    int32_t aCipherFlags)
  1.2904 +{
  1.2905 +  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1.2906 +
  1.2907 +  nsNSSShutDownPreventionLock locker;
  1.2908 +  nsresult rv;
  1.2909 +  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1.2910 +
  1.2911 +  NS_ConvertUTF16toUTF8 moduleName(aModuleName);
  1.2912 +  nsCString fullPath;
  1.2913 +  // NSS doesn't support Unicode path.  Use native charset
  1.2914 +  NS_CopyUnicodeToNative(aLibraryFullPath, fullPath);
  1.2915 +  uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
  1.2916 +  uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
  1.2917 +  SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(), 
  1.2918 +                                      mechFlags, cipherFlags);
  1.2919 +  if (srv == SECSuccess) {
  1.2920 +    SECMODModule *module = SECMOD_FindModule(moduleName.get());
  1.2921 +    if (module) {
  1.2922 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
  1.2923 +      nssComponent->LaunchSmartCardThread(module);
  1.2924 +#endif
  1.2925 +      SECMOD_DestroyModule(module);
  1.2926 +    }
  1.2927 +  }
  1.2928 +
  1.2929 +  // The error message we report to the user depends directly on 
  1.2930 +  // what the return value for SEDMOD_AddNewModule is
  1.2931 +  switch (srv) {
  1.2932 +  case SECSuccess:
  1.2933 +    return NS_OK;
  1.2934 +  case SECFailure:
  1.2935 +    return NS_ERROR_FAILURE;
  1.2936 +  case -2:
  1.2937 +    return NS_ERROR_ILLEGAL_VALUE;
  1.2938 +  }
  1.2939 +  NS_ERROR("Bogus return value, this should never happen");
  1.2940 +  return NS_ERROR_FAILURE;
  1.2941 +}
  1.2942 +

mercurial