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