PageRenderTime 127ms CodeModel.GetById 14ms app.highlight 100ms RepoModel.GetById 1ms app.codeStats 0ms

/security/manager/ssl/src/nsCrypto.cpp

http://github.com/zpao/v8monkey
C++ | 3003 lines | 2170 code | 434 blank | 399 comment | 400 complexity | fd2d54d9f08a9afeb413eb9d2ac6fc86 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
   2 *
   3 * ***** BEGIN LICENSE BLOCK *****
   4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   5 *
   6 * The contents of this file are subject to the Mozilla Public License Version
   7 * 1.1 (the "License"); you may not use this file except in compliance with
   8 * the License. You may obtain a copy of the License at
   9 * http://www.mozilla.org/MPL/
  10 *
  11 * Software distributed under the License is distributed on an "AS IS" basis,
  12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13 * for the specific language governing rights and limitations under the
  14 * License.
  15 *
  16 * The Original Code is mozilla.org code.
  17 *
  18 * The Initial Developer of the Original Code is
  19 * Netscape Communications Corporation.
  20 * Portions created by the Initial Developer are Copyright (C) 2001
  21 * the Initial Developer. All Rights Reserved.
  22 *
  23 * Contributor(s):
  24 *   Javier Delgadillo <javi@netscape.com>
  25 *
  26 * Alternatively, the contents of this file may be used under the terms of
  27 * either the GNU General Public License Version 2 or later (the "GPL"), or
  28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29 * in which case the provisions of the GPL or the LGPL are applicable instead
  30 * of those above. If you wish to allow use of your version of this file only
  31 * under the terms of either the GPL or the LGPL, and not to allow others to
  32 * use your version of this file under the terms of the MPL, indicate your
  33 * decision by deleting the provisions above and replace them with the notice
  34 * and other provisions required by the GPL or the LGPL. If you do not delete
  35 * the provisions above, a recipient may use your version of this file under
  36 * the terms of any one of the MPL, the GPL or the LGPL.
  37 *
  38 * ***** END LICENSE BLOCK ***** */
  39#include "nsNSSComponent.h"
  40#include "nsCrypto.h"
  41#include "nsKeygenHandler.h"
  42#include "nsKeygenThread.h"
  43#include "nsNSSCertificate.h"
  44#include "nsNSSCertificateDB.h"
  45#include "nsPKCS12Blob.h"
  46#include "nsPK11TokenDB.h"
  47#include "nsThreadUtils.h"
  48#include "nsIServiceManager.h"
  49#include "nsIMemory.h"
  50#include "nsAutoPtr.h"
  51#include "nsAlgorithm.h"
  52#include "nsCRT.h"
  53#include "prprf.h"
  54#include "prmem.h"
  55#include "nsDOMCID.h"
  56#include "nsIDOMWindow.h"
  57#include "nsIDOMClassInfo.h"
  58#include "nsIDOMDocument.h"
  59#include "nsIDocument.h"
  60#include "nsIScriptObjectPrincipal.h"
  61#include "nsIScriptContext.h"
  62#include "nsIScriptGlobalObject.h"
  63#include "nsDOMJSUtils.h"
  64#include "nsIXPConnect.h"
  65#include "nsIRunnable.h"
  66#include "nsIWindowWatcher.h"
  67#include "nsIPrompt.h"
  68#include "nsIFilePicker.h"
  69#include "nsJSPrincipals.h"
  70#include "nsIPrincipal.h"
  71#include "nsIScriptSecurityManager.h"
  72#include "nsXPIDLString.h"
  73#include "nsIGenKeypairInfoDlg.h"
  74#include "nsIDOMCryptoDialogs.h"
  75#include "nsIFormSigningDialog.h"
  76#include "nsIJSContextStack.h"
  77#include "jsapi.h"
  78#include "jsdbgapi.h"
  79#include <ctype.h>
  80#include "nsReadableUtils.h"
  81#include "pk11func.h"
  82#include "keyhi.h"
  83#include "cryptohi.h"
  84#include "seccomon.h"
  85#include "secerr.h"
  86#include "sechash.h"
  87extern "C" {
  88#include "crmf.h"
  89#include "pk11pqg.h"
  90}
  91#include "cmmf.h"
  92#include "nssb64.h"
  93#include "base64.h"
  94#include "cert.h"
  95#include "certdb.h"
  96#include "secmod.h"
  97#include "nsISaveAsCharset.h"
  98
  99#include "ssl.h" // For SSL_ClearSessionCache
 100
 101#include "nsNSSCleaner.h"
 102NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
 103NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
 104NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
 105NSSCleanupAutoPtrClass(PK11SymKey, PK11_FreeSymKey)
 106NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
 107NSSCleanupAutoPtrClass_WithParam(SECItem, SECITEM_FreeItem, TrueParam, true)
 108
 109#include "nsNSSShutDown.h"
 110#include "nsNSSCertHelper.h"
 111
 112/*
 113 * These are the most common error strings that are returned
 114 * by the JavaScript methods in case of error.
 115 */
 116
 117#define JS_ERROR       "error:"
 118#define JS_ERROR_INTERNAL  JS_ERROR"internalError"
 119
 120#undef REPORT_INCORRECT_NUM_ARGS
 121
 122#define JS_OK_ADD_MOD                      3
 123#define JS_OK_DEL_EXTERNAL_MOD             2
 124#define JS_OK_DEL_INTERNAL_MOD             1
 125
 126#define JS_ERR_INTERNAL                   -1
 127#define JS_ERR_USER_CANCEL_ACTION         -2
 128#define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
 129#define JS_ERR_DEL_MOD                    -4
 130#define JS_ERR_ADD_MOD                    -5
 131#define JS_ERR_BAD_MODULE_NAME            -6
 132#define JS_ERR_BAD_DLL_NAME               -7
 133#define JS_ERR_BAD_MECHANISM_FLAGS        -8
 134#define JS_ERR_BAD_CIPHER_ENABLE_FLAGS    -9
 135#define JS_ERR_ADD_DUPLICATE_MOD          -10
 136
 137/*
 138 * This structure is used to store information for one key generation.
 139 * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
 140 * stores one of these structures for every key generation that happens.
 141 * The information stored in this structure is then used to set some
 142 * values in the CRMF request.
 143 */
 144typedef enum {
 145  rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
 146  ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
 147  dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
 148} nsKeyGenType;
 149
 150bool isECKeyGenType(nsKeyGenType kgt)
 151{
 152  switch (kgt)
 153  {
 154    case ecEnc:
 155    case ecDualUse:
 156    case ecSign:
 157    case ecNonrepudiation:
 158    case ecSignNonrepudiation:
 159      return true;
 160    
 161    default:
 162      break;
 163  }
 164
 165  return false;
 166}
 167
 168typedef struct nsKeyPairInfoStr {
 169  SECKEYPublicKey  *pubKey;     /* The putlic key associated with gen'd 
 170                                   priv key. */
 171  SECKEYPrivateKey *privKey;    /* The private key we generated */ 
 172  nsKeyGenType      keyGenType; /* What type of key gen are we doing.*/
 173
 174  CERTCertificate *ecPopCert;
 175                   /* null: use signing for pop
 176                      other than null: a cert that defines EC keygen params
 177                                       and will be used for dhMac PoP. */
 178
 179  SECKEYPublicKey  *ecPopPubKey;
 180                   /* extracted public key from ecPopCert */
 181} nsKeyPairInfo;
 182
 183
 184//This class is just used to pass arguments
 185//to the nsCryptoRunnable event.
 186class nsCryptoRunArgs : public nsISupports {
 187public:
 188  nsCryptoRunArgs();
 189  virtual ~nsCryptoRunArgs();
 190  nsCOMPtr<nsISupports> m_kungFuDeathGrip;
 191  JSContext *m_cx;
 192  JSObject  *m_scope;
 193  nsCOMPtr<nsIPrincipal> m_principals;
 194  nsXPIDLCString m_jsCallback;
 195  NS_DECL_ISUPPORTS
 196};
 197
 198//This class is used to run the callback code
 199//passed to crypto.generateCRMFRequest
 200//We have to do that for backwards compatibility
 201//reasons w/ PSM 1.x and Communciator 4.x
 202class nsCryptoRunnable : public nsIRunnable {
 203public:
 204  nsCryptoRunnable(nsCryptoRunArgs *args);
 205  virtual ~nsCryptoRunnable();
 206
 207  NS_IMETHOD Run ();
 208  NS_DECL_ISUPPORTS
 209private:
 210  nsCryptoRunArgs *m_args;
 211};
 212
 213
 214//We're going to inherit the memory passed
 215//into us.
 216//This class backs up an array of certificates
 217//as an event.
 218class nsP12Runnable : public nsIRunnable {
 219public:
 220  nsP12Runnable(nsIX509Cert **certArr, PRInt32 numCerts, nsIPK11Token *token);
 221  virtual ~nsP12Runnable();
 222
 223  NS_IMETHOD Run();
 224  NS_DECL_ISUPPORTS
 225private:
 226  nsCOMPtr<nsIPK11Token> mToken;
 227  nsIX509Cert **mCertArr;
 228  PRInt32       mNumCerts;
 229};
 230
 231// QueryInterface implementation for nsCrypto
 232NS_INTERFACE_MAP_BEGIN(nsCrypto)
 233  NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
 234  NS_INTERFACE_MAP_ENTRY(nsISupports)
 235  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Crypto)
 236NS_INTERFACE_MAP_END
 237
 238NS_IMPL_ADDREF(nsCrypto)
 239NS_IMPL_RELEASE(nsCrypto)
 240
 241// QueryInterface implementation for nsCRMFObject
 242NS_INTERFACE_MAP_BEGIN(nsCRMFObject)
 243  NS_INTERFACE_MAP_ENTRY(nsIDOMCRMFObject)
 244  NS_INTERFACE_MAP_ENTRY(nsISupports)
 245  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CRMFObject)
 246NS_INTERFACE_MAP_END
 247
 248NS_IMPL_ADDREF(nsCRMFObject)
 249NS_IMPL_RELEASE(nsCRMFObject)
 250
 251// QueryInterface implementation for nsPkcs11
 252NS_INTERFACE_MAP_BEGIN(nsPkcs11)
 253  NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
 254  NS_INTERFACE_MAP_ENTRY(nsISupports)
 255NS_INTERFACE_MAP_END
 256
 257NS_IMPL_ADDREF(nsPkcs11)
 258NS_IMPL_RELEASE(nsPkcs11)
 259
 260// ISupports implementation for nsCryptoRunnable
 261NS_IMPL_ISUPPORTS1(nsCryptoRunnable, nsIRunnable)
 262
 263// ISupports implementation for nsP12Runnable
 264NS_IMPL_ISUPPORTS1(nsP12Runnable, nsIRunnable)
 265
 266// ISupports implementation for nsCryptoRunArgs
 267NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
 268
 269static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 270
 271nsCrypto::nsCrypto() :
 272  mEnableSmartCardEvents(false)
 273{
 274}
 275
 276nsCrypto::~nsCrypto()
 277{
 278}
 279
 280NS_IMETHODIMP
 281nsCrypto::SetEnableSmartCardEvents(bool aEnable)
 282{
 283  nsresult rv = NS_OK;
 284
 285  // this has the side effect of starting the nssComponent (and initializing
 286  // NSS) even if it isn't already going. Starting the nssComponent is a 
 287  // prerequisite for getting smartCard events.
 288  if (aEnable) {
 289    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
 290  }
 291
 292  if (NS_FAILED(rv)) {
 293    return rv;
 294  }
 295
 296  mEnableSmartCardEvents = aEnable;
 297  return NS_OK;
 298}
 299
 300NS_IMETHODIMP
 301nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
 302{
 303  *aEnable = mEnableSmartCardEvents;
 304  return NS_OK;
 305}
 306
 307//A quick function to let us know if the key we're trying to generate
 308//can be escrowed.
 309static bool
 310ns_can_escrow(nsKeyGenType keyGenType)
 311{
 312  /* For now, we only escrow rsa-encryption and ec-encryption keys. */
 313  return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
 314}
 315
 316//Retrieve crypto.version so that callers know what
 317//version of PSM this is.
 318NS_IMETHODIMP
 319nsCrypto::GetVersion(nsAString& aVersion)
 320{
 321  aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING).get());
 322  return NS_OK;
 323}
 324
 325/*
 326 * Given an nsKeyGenType, return the PKCS11 mechanism that will
 327 * perform the correct key generation.
 328 */
 329static PRUint32
 330cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
 331{
 332  PRUint32 retMech;
 333
 334  switch (keyGenType) {
 335  case rsaEnc:
 336  case rsaDualUse:
 337  case rsaSign:
 338  case rsaNonrepudiation:
 339  case rsaSignNonrepudiation:
 340    retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
 341    break;
 342  case ecEnc:
 343  case ecDualUse:
 344  case ecSign:
 345  case ecNonrepudiation:
 346  case ecSignNonrepudiation:
 347    retMech = CKM_EC_KEY_PAIR_GEN;
 348    break;
 349  case dhEx:
 350    retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
 351    break;
 352  case dsaSign:
 353  case dsaSignNonrepudiation:
 354  case dsaNonrepudiation:
 355    retMech = CKM_DSA_KEY_PAIR_GEN;
 356    break;
 357  default:
 358    retMech = CKM_INVALID_MECHANISM;
 359  }
 360  return retMech;
 361}
 362
 363/*
 364 * This function converts a string read through JavaScript parameters
 365 * and translates it to the internal enumeration representing the
 366 * key gen type.
 367 */
 368static nsKeyGenType
 369cryptojs_interpret_key_gen_type(char *keyAlg)
 370{
 371  char *end;
 372  if (keyAlg == nsnull) {
 373    return invalidKeyGen;
 374  }
 375  /* First let's remove all leading and trailing white space */
 376  while (isspace(keyAlg[0])) keyAlg++;
 377  end = strchr(keyAlg, '\0');
 378  if (end == nsnull) {
 379    return invalidKeyGen;
 380  }
 381  end--;
 382  while (isspace(*end)) end--;
 383  end[1] = '\0';
 384  if (strcmp(keyAlg, "rsa-ex") == 0) {
 385    return rsaEnc;
 386  } else if (strcmp(keyAlg, "rsa-dual-use") == 0) {
 387    return rsaDualUse;
 388  } else if (strcmp(keyAlg, "rsa-sign") == 0) {
 389    return rsaSign;
 390  } else if (strcmp(keyAlg, "rsa-sign-nonrepudiation") == 0) {
 391    return rsaSignNonrepudiation;
 392  } else if (strcmp(keyAlg, "rsa-nonrepudiation") == 0) {
 393    return rsaNonrepudiation;
 394  } else if (strcmp(keyAlg, "ec-ex") == 0) {
 395    return ecEnc;
 396  } else if (strcmp(keyAlg, "ec-dual-use") == 0) {
 397    return ecDualUse;
 398  } else if (strcmp(keyAlg, "ec-sign") == 0) {
 399    return ecSign;
 400  } else if (strcmp(keyAlg, "ec-sign-nonrepudiation") == 0) {
 401    return ecSignNonrepudiation;
 402  } else if (strcmp(keyAlg, "ec-nonrepudiation") == 0) {
 403    return ecNonrepudiation;
 404  } else if (strcmp(keyAlg, "dsa-sign-nonrepudiation") == 0) {
 405    return dsaSignNonrepudiation;
 406  } else if (strcmp(keyAlg, "dsa-sign") ==0 ){
 407    return dsaSign;
 408  } else if (strcmp(keyAlg, "dsa-nonrepudiation") == 0) {
 409    return dsaNonrepudiation;
 410  } else if (strcmp(keyAlg, "dh-ex") == 0) {
 411    return dhEx;
 412  }
 413  return invalidKeyGen;
 414}
 415
 416/* 
 417 * input: null terminated char* pointing to (the remainder of) an
 418 * EC key param string.
 419 *
 420 * bool return value, false means "no more name=value pair found",
 421 *                    true means "found, see out params"
 422 * 
 423 * out param name: char * pointing to name (not zero terminated)
 424 * out param name_len: length of found name
 425 * out param value: char * pointing to value (not zero terminated)
 426 * out param value_len: length of found value
 427 * out param next_pair: to be used for a follow up call to this function
 428 */
 429
 430bool getNextNameValueFromECKeygenParamString(char *input,
 431                                               char *&name,
 432                                               int &name_len,
 433                                               char *&value,
 434                                               int &value_len,
 435                                               char *&next_call)
 436{
 437  if (!input || !*input)
 438    return false;
 439
 440  // we allow leading ; and leading space in front of each name value pair
 441
 442  while (*input && *input == ';')
 443    ++input;
 444
 445  while (*input && *input == ' ')
 446    ++input;
 447
 448  name = input;
 449
 450  while (*input && *input != '=')
 451    ++input;
 452
 453  if (*input != '=')
 454    return false;
 455
 456  name_len = input - name;
 457  ++input;
 458
 459  value = input;
 460
 461  while (*input && *input != ';')
 462    ++input;
 463
 464  value_len = input - value;
 465  next_call = input;
 466
 467  return true;
 468}
 469
 470//Take the string passed into us via crypto.generateCRMFRequest
 471//as the keygen type parameter and convert it to parameters 
 472//we can actually pass to the PKCS#11 layer.
 473static void*
 474nsConvertToActualKeyGenParams(PRUint32 keyGenMech, char *params,
 475                              PRUint32 paramLen, PRInt32 keySize,
 476                              nsKeyPairInfo *keyPairInfo)
 477{
 478  void *returnParams = nsnull;
 479
 480
 481  switch (keyGenMech) {
 482  case CKM_RSA_PKCS_KEY_PAIR_GEN:
 483  {
 484    // For RSA, we don't support passing in key generation arguments from
 485    // the JS code just yet.
 486    if (params)
 487      return nsnull;
 488
 489    PK11RSAGenParams *rsaParams;
 490    rsaParams = static_cast<PK11RSAGenParams*>
 491                           (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
 492                              
 493    if (rsaParams == nsnull) {
 494      return nsnull;
 495    }
 496    /* I'm just taking the same parameters used in 
 497     * certdlgs.c:GenKey
 498     */
 499    if (keySize > 0) {
 500      rsaParams->keySizeInBits = keySize;
 501    } else {
 502      rsaParams->keySizeInBits = 1024;
 503    }
 504    rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
 505    returnParams = rsaParams;
 506    break;
 507  }
 508  case CKM_EC_KEY_PAIR_GEN:
 509  {
 510    /*
 511     * keygen params for generating EC keys must be composed of name=value pairs,
 512     * multiple pairs allowed, separated using semicolon ;
 513     *
 514     * Either param "curve" or param "popcert" must be specified.
 515     * curve=name-of-curve
 516     * popcert=base64-encoded-cert
 517     *
 518     * When both params are specified, popcert will be used.
 519     * If no popcert param is given, or if popcert can not be decoded,
 520     * we will fall back to the curve param.
 521     *
 522     * Additional name=value pairs may be defined in the future.
 523     *
 524     * If param popcert is present and valid, the given certificate will be used
 525     * to determine the key generation params. In addition the certificate
 526     * will be used to produce a dhMac based Proof of Posession,
 527     * using the cert's public key, subject and issuer names,
 528     * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
 529     *
 530     * If neither param popcert nor param curve could be used,
 531     * tse a curve based on the keysize param.
 532     * NOTE: Here keysize is used only as an indication of
 533     * High/Medium/Low strength; elliptic curve
 534     * cryptography uses smaller keys than RSA to provide
 535     * equivalent security.
 536     */
 537
 538    char *curve = nsnull;
 539
 540    {
 541      // extract components of name=value list
 542
 543      char *next_input = params;
 544      char *name = nsnull;
 545      char *value = nsnull;
 546      int name_len = 0;
 547      int value_len = 0;
 548  
 549      while (getNextNameValueFromECKeygenParamString(
 550              next_input, name, name_len, value, value_len,
 551              next_input))
 552      {
 553        if (PL_strncmp(name, "curve", NS_MIN(name_len, 5)) == 0)
 554        {
 555          curve = PL_strndup(value, value_len);
 556        }
 557        else if (PL_strncmp(name, "popcert", NS_MIN(name_len, 7)) == 0)
 558        {
 559          char *certstr = PL_strndup(value, value_len);
 560          if (certstr) {
 561            keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
 562            PL_strfree(certstr);
 563
 564            if (keyPairInfo->ecPopCert)
 565            {
 566              keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
 567            }
 568          }
 569        }
 570      }
 571    }
 572
 573    // first try to use the params of the provided CA cert
 574    if (keyPairInfo->ecPopPubKey)
 575    {
 576      returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
 577    }
 578
 579    // if we did not yet find good params, do we have a curve name?
 580    if (!returnParams && curve)
 581    {
 582      returnParams = decode_ec_params(curve);
 583    }
 584
 585    // if we did not yet find good params, do something based on keysize
 586    if (!returnParams)
 587    {
 588      switch (keySize) {
 589      case 512:
 590      case 1024:
 591          returnParams = decode_ec_params("secp256r1");
 592          break;
 593      case 2048:
 594      default:
 595          returnParams = decode_ec_params("secp384r1");
 596          break;
 597      }
 598    }
 599
 600    if (curve)
 601      PL_strfree(curve);
 602
 603    break;
 604  }
 605  case CKM_DSA_KEY_PAIR_GEN:
 606  {
 607    // For DSA, we don't support passing in key generation arguments from
 608    // the JS code just yet.
 609    if (params)
 610      return nsnull;
 611
 612    PQGParams *pqgParams = nsnull;
 613    PQGVerify *vfy = nsnull;
 614    SECStatus  rv;
 615    int        index;
 616       
 617    index = PQG_PBITS_TO_INDEX(keySize);
 618    if (index == -1) {
 619      returnParams = nsnull;
 620      break;
 621    }
 622    rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
 623    if (vfy) {
 624      PK11_PQG_DestroyVerify(vfy);
 625    }
 626    if (rv != SECSuccess) {
 627      if (pqgParams) {
 628        PK11_PQG_DestroyParams(pqgParams);
 629      }
 630      return nsnull;
 631    }
 632    returnParams = pqgParams;
 633    break;
 634  }
 635  default:
 636    returnParams = nsnull;
 637  }
 638  return returnParams;
 639}
 640
 641//We need to choose which PKCS11 slot we're going to generate
 642//the key on.  Calls the default implementation provided by
 643//nsKeygenHandler.cpp
 644static PK11SlotInfo*
 645nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
 646{
 647  nsNSSShutDownPreventionLock locker;
 648  PRUint32 mechanism = cryptojs_convert_to_mechanism(keyGenType);
 649  PK11SlotInfo *slot = nsnull;
 650  nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
 651  if (NS_FAILED(rv)) {
 652    if (slot)
 653      PK11_FreeSlot(slot);
 654    slot = nsnull;
 655  }
 656  return slot;
 657}
 658
 659//Free the parameters that were passed into PK11_GenerateKeyPair
 660//depending on the mechanism type used.
 661static void
 662nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
 663{
 664  switch (keyGenMechanism) {
 665  case CKM_RSA_PKCS_KEY_PAIR_GEN:
 666    nsMemory::Free(params);
 667    break;
 668  case CKM_EC_KEY_PAIR_GEN:
 669    SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
 670    break;
 671  case CKM_DSA_KEY_PAIR_GEN:
 672    PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
 673    break;
 674  }
 675}
 676
 677//Function that is used to generate a single key pair.
 678//Once all the arguments have been parsed and processed, this
 679//function gets called and takes care of actually generating
 680//the key pair passing the appopriate parameters to the NSS
 681//functions.
 682static nsresult
 683cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 
 684                            PRInt32 keySize, char *params, 
 685                            nsIInterfaceRequestor *uiCxt,
 686                            PK11SlotInfo *slot, bool willEscrow)
 687                            
 688{
 689  nsIGeneratingKeypairInfoDialogs * dialogs;
 690  nsKeygenThread *KeygenRunnable = 0;
 691  nsCOMPtr<nsIKeygenThread> runnable;
 692
 693  PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
 694  void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 
 695                                                     (params) ? strlen(params):0, 
 696                                                     keySize, keyPairInfo);
 697
 698  if (!keyGenParams) {
 699    return NS_ERROR_INVALID_ARG;
 700  }
 701
 702  // Make sure the token has password already set on it before trying
 703  // to generate the key.
 704
 705  nsresult rv = setPassword(slot, uiCxt);
 706  if (NS_FAILED(rv))
 707    return rv;
 708
 709  if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
 710    return NS_ERROR_FAILURE;
 711 
 712
 713  // Smart cards will not let you extract a private key once 
 714  // it is on the smart card.  If we've been told to escrow
 715  // a private key that will ultimately wind up on a smart card,
 716  // then we'll generate the private key on the internal slot
 717  // as a temporary key, then move it to the destination slot. 
 718  // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
 719  //       so that the key has zero chance of being store in the
 720  //       user's key3.db file.  Which the slot returned by
 721  //       PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
 722  //       does not.
 723  PK11SlotInfo *intSlot = nsnull;
 724  PK11SlotInfoCleaner siCleaner(intSlot);
 725  
 726  PK11SlotInfo *origSlot = nsnull;
 727  bool isPerm;
 728
 729  if (willEscrow && !PK11_IsInternal(slot)) {
 730    intSlot = PK11_GetInternalSlot();
 731    NS_ASSERTION(intSlot,"Couldn't get the internal slot");
 732    isPerm = false;
 733    origSlot = slot;
 734    slot = intSlot;
 735  } else {
 736    isPerm = true;
 737  }
 738
 739  rv = getNSSDialogs((void**)&dialogs,
 740                     NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
 741                     NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
 742
 743  if (NS_SUCCEEDED(rv)) {
 744    KeygenRunnable = new nsKeygenThread();
 745    if (KeygenRunnable) {
 746      NS_ADDREF(KeygenRunnable);
 747    }
 748  }
 749
 750  if (NS_FAILED(rv) || !KeygenRunnable) {
 751    rv = NS_OK;
 752    keyPairInfo->privKey = PK11_GenerateKeyPair(slot, mechanism, keyGenParams,
 753                                                &keyPairInfo->pubKey, isPerm, 
 754                                                isPerm, uiCxt);
 755  } else {
 756    KeygenRunnable->SetParams( slot, mechanism, keyGenParams, isPerm, isPerm, uiCxt );
 757
 758    runnable = do_QueryInterface(KeygenRunnable);
 759
 760    if (runnable) {
 761      {
 762        nsPSMUITracker tracker;
 763        if (tracker.isUIForbidden()) {
 764          rv = NS_ERROR_NOT_AVAILABLE;
 765        }
 766        else {
 767          rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
 768          // We call join on the thread, 
 769          // so we can be sure that no simultaneous access to the passed parameters will happen.
 770          KeygenRunnable->Join();
 771        }
 772      }
 773
 774      NS_RELEASE(dialogs);
 775      if (NS_SUCCEEDED(rv)) {
 776        rv = KeygenRunnable->GetParams(&keyPairInfo->privKey, &keyPairInfo->pubKey);
 777      }
 778    }
 779  }
 780
 781  nsFreeKeyGenParams(mechanism, keyGenParams);
 782
 783  if (KeygenRunnable) {
 784    NS_RELEASE(KeygenRunnable);
 785  }
 786
 787  if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
 788    return NS_ERROR_FAILURE;
 789  }
 790 
 791
 792  //If we generated the key pair on the internal slot because the
 793  // keys were going to be escrowed, move the keys over right now.
 794  if (willEscrow && intSlot) {
 795    SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(origSlot, 
 796                                                    keyPairInfo->privKey,
 797                                                    keyPairInfo->pubKey,
 798                                                    true, true);
 799    SECKEYPrivateKeyCleaner pkCleaner(newPrivKey);
 800
 801    if (!newPrivKey)
 802      return NS_ERROR_FAILURE;
 803
 804    // The private key is stored on the selected slot now, and the copy we
 805    // ultimately use for escrowing when the time comes lives 
 806    // in the internal slot.  We will delete it from that slot
 807    // after the requests are made.  This call only gives up
 808    // our reference to the key object and does not actually 
 809    // physically remove it from the card itself.
 810    // The actual delete calls are being made in the destructors
 811    // of the cleaner helper instances.
 812  }  
 813
 814  return NS_OK;
 815}
 816
 817/*
 818 * FUNCTION: cryptojs_ReadArgsAndGenerateKey
 819 * -------------------------------------
 820 * INPUTS:
 821 *  cx
 822 *    The JSContext associated with the execution of the corresponging
 823 *    crypto.generateCRMFRequest call
 824 *  argv
 825 *    A pointer to an array of JavaScript parameters passed to the
 826 *    method crypto.generateCRMFRequest.  The array should have the
 827 *    3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
 828 *    the definition of crypto.generateCRMFRequest at the following
 829 *    document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
 830 *  keyGenType
 831 *    A structure used to store the information about the newly created
 832 *    key pair.
 833 *  uiCxt
 834 *    An interface requestor that would be used to get an nsIPrompt
 835 *    if we need to ask the user for a password.
 836 *  slotToUse
 837 *    The PKCS11 slot to use for generating the key pair. If nsnull, then
 838 *    this function should select a slot that can do the key generation 
 839 *    from the keytype associted with the keyPairInfo, and pass it back to
 840 *    the caller so that subsequence key generations can use the same slot. 
 841 *  willEscrow
 842 *    If true, then that means we will try to escrow the generated
 843 *    private key when building the CRMF request.  If false, then
 844 *    we will not try to escrow the private key.
 845 *
 846 * NOTES:
 847 * This function takes care of reading a set of 3 parameters that define
 848 * one key generation.  The argv pointer should be one that originates
 849 * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
 850 * The function interprets the argument in the first index as an integer and
 851 * passes that as the key size for the key generation-this parameter is
 852 * mandatory.  The second parameter is read in as a string.  This value can
 853 * be null in JavaScript world and everything will still work.  The third
 854 * parameter is a mandatory string that indicates what kind of key to generate.
 855 * There should always be 1-to-1 correspondence between the strings compared
 856 * in the function cryptojs_interpret_key_gen_type and the strings listed in
 857 * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
 858 * under the definition of the method generateCRMFRequest, for the parameter
 859 * "keyGenAlgN".  After reading the parameters, the function then 
 860 * generates the key pairs passing the parameters parsed from the JavaScript i
 861 * routine.  
 862 *
 863 * RETURN:
 864 * NS_OK if creating the Key was successful.  Any other return value
 865 * indicates an error.
 866 */
 867
 868static nsresult
 869cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
 870                                jsval *argv,
 871                                nsKeyPairInfo *keyGenType,
 872                                nsIInterfaceRequestor *uiCxt,
 873                                PK11SlotInfo **slot, bool willEscrow)
 874{
 875  JSString  *jsString;
 876  JSAutoByteString params, keyGenAlg;
 877  int    keySize;
 878  nsresult  rv;
 879
 880  if (!JSVAL_IS_INT(argv[0])) {
 881    JS_ReportError(cx, "%s%s\n", JS_ERROR,
 882                   "passed in non-integer for key size");
 883    return NS_ERROR_FAILURE;
 884  }
 885  keySize = JSVAL_TO_INT(argv[0]);
 886  if (!JSVAL_IS_NULL(argv[1])) {
 887    jsString = JS_ValueToString(cx,argv[1]);
 888    NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
 889    argv[1] = STRING_TO_JSVAL(jsString);
 890    params.encode(cx, jsString);
 891    NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
 892  }
 893
 894  if (JSVAL_IS_NULL(argv[2])) {
 895    JS_ReportError(cx,"%s%s\n", JS_ERROR,
 896             "key generation type not specified");
 897    return NS_ERROR_FAILURE;
 898  }
 899  jsString = JS_ValueToString(cx, argv[2]);
 900  NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
 901  argv[2] = STRING_TO_JSVAL(jsString);
 902  keyGenAlg.encode(cx, jsString);
 903  NS_ENSURE_TRUE(!!keyGenAlg, NS_ERROR_OUT_OF_MEMORY);
 904  keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg.ptr());
 905  if (keyGenType->keyGenType == invalidKeyGen) {
 906    JS_ReportError(cx, "%s%s%s", JS_ERROR,
 907                   "invalid key generation argument:",
 908                   keyGenAlg.ptr());
 909    goto loser;
 910  }
 911  if (*slot == nsnull) {
 912    *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
 913    if (*slot == nsnull)
 914      goto loser;
 915  }
 916
 917  rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
 918                                   *slot,willEscrow);
 919
 920  if (rv != NS_OK) {
 921    JS_ReportError(cx,"%s%s%s", JS_ERROR,
 922                   "could not generate the key for algorithm ",
 923                   keyGenAlg.ptr());
 924    goto loser;
 925  }
 926  return NS_OK;
 927loser:
 928  return NS_ERROR_FAILURE;
 929}
 930
 931//Utility funciton to free up the memory used by nsKeyPairInfo
 932//arrays.
 933static void
 934nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
 935{
 936  NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
 937  if (!keyids)
 938    return;
 939  int i;
 940  for (i=0; i<numIDs; i++) {
 941    if (keyids[i].pubKey)
 942      SECKEY_DestroyPublicKey(keyids[i].pubKey);
 943    if (keyids[i].privKey)
 944      SECKEY_DestroyPrivateKey(keyids[i].privKey);
 945    if (keyids[i].ecPopCert)
 946      CERT_DestroyCertificate(keyids[i].ecPopCert);
 947    if (keyids[i].ecPopPubKey)
 948      SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
 949  }
 950  delete []keyids;
 951}
 952
 953//Utility funciton used to free the genertaed cert request messages
 954static void
 955nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, PRInt32 numMessages)
 956{
 957  PRInt32 i;
 958  for (i=0; i<numMessages && certReqMsgs[i]; i++) {
 959    CRMF_DestroyCertReqMsg(certReqMsgs[i]);
 960  }
 961  delete []certReqMsgs;
 962}
 963
 964//If the form called for escrowing the private key we just generated,
 965//this function adds all the correct elements to the request.
 966//That consists of adding CRMFEncryptedKey to the reques as part
 967//of the CRMFPKIArchiveOptions Control.
 968static nsresult
 969nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
 970                     nsNSSCertificate *wrappingCert)
 971{
 972  if (!wrappingCert ||
 973      CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
 974    return NS_ERROR_FAILURE;
 975  }
 976  CERTCertificate *cert = wrappingCert->GetCert();
 977  if (!cert)
 978    return NS_ERROR_FAILURE;
 979
 980  CRMFEncryptedKey *encrKey = 
 981      CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert);
 982  CERT_DestroyCertificate(cert);
 983  if (!encrKey)
 984    return NS_ERROR_FAILURE;
 985
 986  CRMFPKIArchiveOptions *archOpt = 
 987      CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
 988  if (!archOpt) {
 989    CRMF_DestroyEncryptedKey(encrKey);
 990    return NS_ERROR_FAILURE;
 991  }
 992  SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
 993  CRMF_DestroyEncryptedKey(encrKey);
 994  CRMF_DestroyPKIArchiveOptions(archOpt);
 995  if (srv != SECSuccess)
 996    return NS_ERROR_FAILURE;
 997
 998  return NS_OK;
 999}
1000
1001//Set the Distinguished Name (Subject Name) for the cert
1002//being requested.
1003static nsresult
1004nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
1005{
1006  if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
1007    return NS_ERROR_FAILURE;
1008  }
1009  CERTName *subjectName = CERT_AsciiToName(reqDN);
1010  if (!subjectName) {
1011    return NS_ERROR_FAILURE;
1012  }
1013  SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
1014                                                   static_cast<void*>
1015                                                              (subjectName));
1016  CERT_DestroyName(subjectName);
1017  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
1018}
1019
1020//Set Registration Token Control on the request.
1021static nsresult
1022nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
1023{
1024  // this should never happen, but might as well add this.
1025  NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
1026  if (regToken){
1027    if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
1028      return NS_ERROR_FAILURE;
1029  
1030    SECItem src;
1031    src.data = (unsigned char*)regToken;
1032    src.len  = strlen(regToken);
1033    SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src, 
1034                                        SEC_ASN1_GET(SEC_UTF8StringTemplate));
1035
1036    if (!derEncoded)
1037      return NS_ERROR_FAILURE;
1038
1039    SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
1040    SECITEM_FreeItem(derEncoded,true);
1041    if (srv != SECSuccess)
1042      return NS_ERROR_FAILURE;
1043  }
1044  return NS_OK;
1045}
1046
1047//Set the Authenticator control on the cert reuest.  It's just
1048//a string that gets passed along.
1049static nsresult
1050nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
1051{
1052  //This should never happen, but might as well check.
1053  NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
1054  if (authenticator) {
1055    if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
1056      return NS_ERROR_FAILURE;
1057    
1058    SECItem src;
1059    src.data = (unsigned char*)authenticator;
1060    src.len  = strlen(authenticator);
1061    SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src,
1062                                     SEC_ASN1_GET(SEC_UTF8StringTemplate));
1063    if (!derEncoded)
1064      return NS_ERROR_FAILURE;
1065
1066    SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 
1067                                                            derEncoded);
1068    SECITEM_FreeItem(derEncoded, true);
1069    if (srv != SECSuccess)
1070      return NS_ERROR_FAILURE;
1071  }
1072  return NS_OK;
1073}
1074
1075// ASN1 DER encoding rules say that when encoding a BIT string,
1076// the length in the header for the bit string is the number 
1077// of "useful" bits in the BIT STRING.  So the function finds
1078// it and sets accordingly for the returned item.
1079static void
1080nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
1081{
1082  unsigned char onebyte;
1083  unsigned int i, len = 0;
1084
1085  /* to prevent warning on some platform at compile time */
1086  onebyte = '\0';
1087  /* Get the position of the right-most turn-on bit */
1088  for (i = 0; i < (value->len ) * 8; ++i) {
1089    if (i % 8 == 0)
1090      onebyte = value->data[i/8];
1091    if (onebyte & 0x80)
1092      len = i;
1093    onebyte <<= 1;
1094  }
1095
1096  bitsmap->data = value->data;
1097  /* Add one here since we work with base 1 */
1098  bitsmap->len = len + 1;
1099}
1100
1101//This next section defines all the functions that sets the 
1102//keyUsageExtension for all the different types of key gens
1103//we handle.  The keyUsageExtension is just a bit flag extension
1104//that we set in wrapper functions that call straight into
1105//nsSetKeyUsageExtension.  There is one wrapper funciton for each
1106//keyGenType.  The correct function will eventually be called 
1107//by going through a switch statement based on the nsKeyGenType
1108//in the nsKeyPairInfo struct.
1109static nsresult
1110nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
1111                       unsigned char   keyUsage)
1112{
1113  SECItem                 *encodedExt= nsnull;
1114  SECItem                  keyUsageValue = { (SECItemType) 0, nsnull, 0 };
1115  SECItem                  bitsmap = { (SECItemType) 0, nsnull, 0 };
1116  SECStatus                srv;
1117  CRMFCertExtension       *ext = nsnull;
1118  CRMFCertExtCreationInfo  extAddParams;
1119  SEC_ASN1Template         bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nsnull,
1120                                             sizeof(SECItem)};
1121
1122  keyUsageValue.data = &keyUsage;
1123  keyUsageValue.len  = 1;
1124  nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
1125
1126  encodedExt = SEC_ASN1EncodeItem(nsnull, nsnull, &bitsmap,&bitStrTemplate);
1127  if (encodedExt == nsnull) {
1128    goto loser;
1129  }
1130  ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
1131  if (ext == nsnull) {
1132      goto loser;
1133  }
1134  extAddParams.numExtensions = 1;
1135  extAddParams.extensions = &ext;
1136  srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
1137                                         &extAddParams);
1138  if (srv != SECSuccess) {
1139      goto loser;
1140  }
1141  CRMF_DestroyCertExtension(ext);
1142  SECITEM_FreeItem(encodedExt, true);
1143  return NS_OK;
1144 loser:
1145  if (ext) {
1146    CRMF_DestroyCertExtension(ext);
1147  }
1148  if (encodedExt) {
1149      SECITEM_FreeItem(encodedExt, true);
1150  }
1151  return NS_ERROR_FAILURE;
1152}
1153
1154static nsresult
1155nsSetRSADualUse(CRMFCertRequest *crmfReq)
1156{
1157  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
1158                           | KU_NON_REPUDIATION
1159                           | KU_KEY_ENCIPHERMENT;
1160
1161  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1162}
1163
1164static nsresult
1165nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
1166{
1167  unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
1168
1169  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1170}
1171
1172static nsresult
1173nsSetRSASign(CRMFCertRequest *crmfReq)
1174{
1175  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
1176
1177
1178  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1179}
1180
1181static nsresult
1182nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
1183{
1184  unsigned char keyUsage = KU_NON_REPUDIATION;
1185
1186  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1187}
1188
1189static nsresult
1190nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
1191{
1192  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
1193                           KU_NON_REPUDIATION;
1194
1195  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1196}
1197
1198static nsresult
1199nsSetECDualUse(CRMFCertRequest *crmfReq)
1200{
1201  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
1202                           | KU_NON_REPUDIATION
1203                           | KU_KEY_AGREEMENT;
1204
1205  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1206}
1207
1208static nsresult
1209nsSetECKeyEx(CRMFCertRequest *crmfReq)
1210{
1211  unsigned char keyUsage = KU_KEY_AGREEMENT;
1212
1213  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1214}
1215
1216static nsresult
1217nsSetECSign(CRMFCertRequest *crmfReq)
1218{
1219  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
1220
1221
1222  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1223}
1224
1225static nsresult
1226nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
1227{
1228  unsigned char keyUsage = KU_NON_REPUDIATION;
1229
1230  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1231}
1232
1233static nsresult
1234nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
1235{
1236  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
1237                           KU_NON_REPUDIATION;
1238
1239  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1240}
1241
1242static nsresult
1243nsSetDH(CRMFCertRequest *crmfReq)
1244{
1245  unsigned char keyUsage = KU_KEY_AGREEMENT;
1246
1247  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1248}
1249
1250static nsresult
1251nsSetDSASign(CRMFCertRequest *crmfReq)
1252{
1253  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
1254
1255  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1256}
1257
1258static nsresult
1259nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
1260{
1261  unsigned char keyUsage = KU_NON_REPUDIATION;
1262
1263  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1264}
1265
1266static nsresult
1267nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
1268{
1269  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
1270                           KU_NON_REPUDIATION;
1271
1272  return nsSetKeyUsageExtension(crmfReq, keyUsage);
1273}
1274
1275static nsresult
1276nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
1277{
1278  nsresult rv;
1279
1280  switch (keyGenType) {
1281  case rsaDualUse:
1282    rv = nsSetRSADualUse(crmfReq);
1283    break;
1284  case rsaEnc:
1285    rv = nsSetRSAKeyEx(crmfReq);
1286    break;
1287  case rsaSign:
1288    rv = nsSetRSASign(crmfReq);
1289    break;
1290  case rsaNonrepudiation:
1291    rv = nsSetRSANonRepudiation(crmfReq);
1292    break;
1293  case rsaSignNonrepudiation:
1294    rv = nsSetRSASignNonRepudiation(crmfReq);
1295    break;
1296  case ecDualUse:
1297    rv = nsSetECDualUse(crmfReq);
1298    break;
1299  case ecEnc:
1300    rv = nsSetECKeyEx(crmfReq);
1301    break;
1302  case ecSign:
1303    rv = nsSetECSign(crmfReq);
1304    break;
1305  case ecNonrepudiation:
1306    rv = nsSetECNonRepudiation(crmfReq);
1307    break;
1308  case ecSignNonrepudiation:
1309    rv = nsSetECSignNonRepudiation(crmfReq);
1310    break;
1311  case dhEx:
1312    rv = nsSetDH(crmfReq);
1313    break;
1314  case dsaSign:
1315    rv = nsSetDSASign(crmfReq);
1316    break;
1317  case dsaNonrepudiation:
1318    rv = nsSetDSANonRepudiation(crmfReq);
1319    break;
1320  case dsaSignNonrepudiation:
1321    rv = nsSetDSASignNonRepudiation(crmfReq);
1322    break;
1323  default:
1324    rv = NS_ERROR_FAILURE;
1325    break;
1326  }
1327  return rv;
1328}
1329
1330//Create a single CRMFCertRequest with all of the necessary parts 
1331//already installed.  The request returned by this function will
1332//have all the parts necessary and can just be added to a 
1333//Certificate Request Message.
1334static CRMFCertRequest*
1335nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 
1336                      char *authenticator, nsNSSCertificate *wrappingCert)
1337{
1338  PRUint32 reqID;
1339  nsresult rv;
1340
1341  //The draft says the ID of the request should be a random
1342  //number.  We don't have a way of tracking this number
1343  //to compare when the reply actually comes back,though.
1344  PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
1345  CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
1346  if (!certReq)
1347    return nsnull;
1348
1349  long version = SEC_CERTIFICATE_VERSION_3;
1350  SECStatus srv;
1351  CERTSubjectPublicKeyInfo *spki = nsnull;
1352  srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
1353  if (srv != SECSuccess)
1354    goto loser;
1355  
1356  spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
1357  if (!spki)
1358    goto loser;
1359
1360  srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
1361  SECKEY_DestroySubjectPublicKeyInfo(spki);
1362  if (srv != SECSuccess)
1363    goto loser;
1364
1365  if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
1366    rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
1367    if (NS_FAILED(rv))
1368      goto loser;
1369  }
1370  rv = nsSetDNForRequest(certReq, reqDN);
1371  if (NS_FAILED(rv))
1372    goto loser;
1373
1374  rv = nsSetRegToken(certReq, regToken);
1375  if (NS_FAILED(rv))
1376    goto loser;
1377
1378  rv = nsSetAuthenticator(certReq, authenticator);
1379  if (NS_FAILED(rv))
1380    goto loser;
1381
1382 rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 
1383  if (NS_FAILED(rv))
1384    goto loser;
1385
1386  return certReq;
1387loser:
1388  if (certReq) {
1389    CRMF_DestroyCertRequest(certReq);
1390  }
1391  return nsnull;
1392}
1393
1394/*
1395 * This function will set the Proof Of Possession (POP) for a request
1396 * associated with a key pair intended to do Key Encipherment.  Currently
1397 * this means encryption only keys.
1398 */
1399static nsresult
1400nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
1401{
1402  SECItem       bitString;
1403  unsigned char der[2];
1404  SECStatus     srv;
1405
1406  if (isEscrowed) {
1407    /* For proof of possession on escrowed keys, we use the
1408     * this Message option of POPOPrivKey and include a zero
1409     * length bit string in the POP field.  This is OK because the encrypted
1410     * private key already exists as part of the PKIArchiveOptions
1411     * Control and that for all intents and purposes proves that
1412     * we do own the private key.
1413     */
1414    der[0] = 0x03; /*We've got a bit string          */
1415    der[1] = 0x00; /*We've got a 0 length bit string */
1416    bitString.data = der;
1417    bitString.len  = 2;
1418    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
1419                                              crmfNoSubseqMess, &bitString);
1420  } else {
1421    /* If the encryption key is not being escrowed, then we set the 
1422     * Proof Of Possession to be a Challenge Response mechanism.
1423     */
1424    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
1425                                              crmfSubsequentMessage,
1426                                              crmfChallengeResp, nsnull);
1427  }
1428  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
1429}
1430
1431static void PR_CALLBACK
1432nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
1433
1434static void PR_CALLBACK
1435nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
1436
1437static nsresult
1438nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 
1439                                 nsKeyPairInfo  *keyInfo,
1440                                 CRMFCertRequest *certReq)
1441{
1442  // RFC 2511 Appendix A section 2 a) defines,
1443  // the "text" input for HMAC shall be the DER encoded version of
1444  // of the single cert request.
1445  // We'll produce that encoding and destroy it afterwards,
1446  // because when sending the complete package to the CA,
1447  // we'll use a different encoding, one that includes POP and
1448  // allows multiple requests to be sent in one step.
1449
1450  unsigned long der_request_len = 0;
1451  SECItem *der_request = NULL;
1452  SECItemCleanerTrueParam der_request_cleaner(der_request);
1453
1454  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
1455                                           nsCRMFEncoderItemCount, 
1456                                           &der_request_len))
1457    return NS_ERROR_FAILURE;
1458
1459  der_request = SECITEM_AllocItem(nsnull, nsnull, der_request_len);
1460  if (!der_request)
1461    return NS_ERROR_FAILURE;
1462
1463  // set len in returned SECItem back to zero, because it will
1464  // be used as the destination offset inside the 
1465  // nsCRMFEncoderItemStore callback.
1466
1467  der_request->len = 0;
1468
1469  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
1470                                           nsCRMFEncoderItemStore, 
1471                                           der_request))
1472    return NS_ERROR_FAILURE;
1473
1474  // RFC 2511 Appendix A section 2 c):
1475  // "A key K is derived from the shared secret Kec and the subject and
1476  //  issuer names in the CA's certificate as follows:
1477  //  K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
1478
1479  PK11SymKey *shared_secret = NULL;
1480  PK11SymKeyCleaner shared_secret_cleaner(shared_secret);
1481
1482  PK11SymKey *subject_and_secret = NULL;
1483  PK11SymKeyCleaner subject_and_secret_cleaner(subject_and_secret);
1484
1485  PK11SymKey *subject_and_secret_and_issuer = NULL;
1486  PK11SymKeyCleaner subject_and_secret_and_issuer_cleaner(subject_and_secret_and_issuer);
1487
1488  PK11SymKey *sha1_of_subject_and_secret_and_issuer = NULL;
1489  PK11SymKeyCleaner sha1_of_subject_and_secret_and_issuer_cleaner(sha1_of_subject_and_secret_and_issuer);
1490
1491  shared_secret = 
1492    PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
1493                          keyInfo->ecPopPubKey,  // SECKEYPublicKey *pubKey
1494                          false, // bool isSender
1495                          NULL, // SECItem *randomA
1496                          NULL, // SECItem *randomB
1497                          CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
1498                          CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
1499                          CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
1500                          0, // int keySize
1501                          CKD_NULL, // CK_ULONG kdf
1502                          NULL, // SECItem *sharedData
1503                          NULL); // void *wincx
1504
1505  if (!shared_secret)
1506    return NS_ERROR_FAILURE;
1507
1508  CK_KEY_DERIVATION_STRING_DATA concat_data_base;
1509  concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
1510  concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
1511  SECItem concat_data_base_item;
1512  concat_data_base_item.data = (unsigned char*)&concat_data_base;
1513  concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
1514
1515  subject_and_secret =
1516    PK11_Derive(shared_secret, // PK11SymKey *baseKey
1517                CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
1518                &concat_data_base_item, // SECItem *param
1519                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
1520                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
1521                0); // int keySize
1522
1523  if (!subject_and_secret)
1524    return NS_ERROR_FAILURE;
1525
1526  CK_KEY_DERIVATION_STRING_DATA concat_base_data;
1527  concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
1528  concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
1529  SECItem concat_base_data_item;
1530  concat_base_data_item.data = (unsigned char*)&concat_base_data;
1531  concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
1532
1533  subject_and_secret_and_issuer =
1534    PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
1535                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
1536                &concat_base_data_item, // SECItem *param
1537                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
1538                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
1539                0); // int keySize
1540
1541  if (!subject_and_secret_and_issuer)
1542    return NS_ERROR_FAILURE;
1543
1544  sha1_of_subject_and_secret_and_issuer =
1545    PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
1546                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
1547                NULL, // SECItem *param
1548                CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
1549                CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
1550                0); // int keySize
1551
1552  if (!sha1_of_subject_and_secret_and_issuer)
1553    return NS_ERROR_FAILURE;
1554
1555  PK11Context *context = NULL;
1556  PK11ContextCleanerTrueParam context_cleaner(context);
1557
1558  SECItem ignore;
1559  ignore.data = 0;
1560  ignore.len = 0;
1561
1562  context = 
1563    PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
1564                               CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
1565                               sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
1566                               &ignore); // SECItem *param
1567
1568  if (!context)
1569    return NS_ERROR_FAILURE;
1570
1571  if (SECSuccess != PK11_DigestBegin(context))
1572    return NS_ERROR_FAILURE;
1573
1574  if (SECSuccess != 
1575      PK11_DigestOp(context, der_request->data, der_request->len))
1576    return NS_ERROR_FAILURE;
1577
1578  SECItem *result_hmac_sha1_item = NULL;
1579  SECItemCleanerTrueParam result_hmac_sha1_item_cleaner(result_hmac_sha1_item);
1580
1581  result_hmac_sha1_item = SECITEM_AllocItem(nsnull, nsnull, SHA1_LENGTH);
1582  if (!result_hmac_sha1_item)
1583    return NS_ERROR_FAILURE;
1584
1585  if (SECSuccess !=
1586      PK11_DigestFinal(context, 
1587                       result_hmac_sha1_item->data, 
1588                       &result_hmac_sha1_item->len, 
1589                       SHA1_LENGTH))
1590    return NS_ERROR_FAILURE;
1591
1592  if (SECSuccess !=
1593      CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
1594                                        crmfNoSubseqMess, result_hmac_sha1_item))
1595    return NS_ERROR_FAILURE;
1596
1597  return NS_OK;
1598}
1599
1600static nsresult
1601nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 
1602                       nsKeyPairInfo  *keyInfo,
1603                       CRMFCertR

Large files files are truncated, but you can click here to view the full file