PageRenderTime 63ms CodeModel.GetById 18ms RepoModel.GetById 0ms 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
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
  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. CRMFCertRequest *certReq)
  1397. {
  1398. // Depending on the type of cert request we'll try
  1399. // POP mechanisms in different order,
  1400. // and add the result to the cert request message.
  1401. //
  1402. // For any signing or dual use cert,
  1403. // try signing first,
  1404. // fall back to DHMAC if we can
  1405. // (EC cert requests that provide keygen param "popcert"),
  1406. // otherwise fail.
  1407. //
  1408. // For encryption only certs that get escrowed, this is sufficient.
  1409. //
  1410. // For encryption only certs, that are not being escrowed,
  1411. // try DHMAC if we can
  1412. // (EC cert requests that provide keygen param "popcert"),
  1413. // otherwise we'll indicate challenge response should be used.
  1414. bool isEncryptionOnlyCertRequest = false;
  1415. bool escrowEncryptionOnlyCert = false;
  1416. switch (keyInfo->keyGenType)
  1417. {
  1418. case rsaEnc:
  1419. case ecEnc:
  1420. isEncryptionOnlyCertRequest = true;
  1421. break;
  1422. case rsaSign:
  1423. case rsaDualUse:
  1424. case rsaNonrepudiation:
  1425. case rsaSignNonrepudiation:
  1426. case ecSign:
  1427. case ecDualUse:
  1428. case ecNonrepudiation:
  1429. case ecSignNonrepudiation:
  1430. case dsaSign:
  1431. case dsaNonrepudiation:
  1432. case dsaSignNonrepudiation:
  1433. break;
  1434. case dhEx:
  1435. /* This case may be supported in the future, but for now, we just fall
  1436. * though to the default case and return an error for diffie-hellman keys.
  1437. */
  1438. default:
  1439. return NS_ERROR_FAILURE;
  1440. };
  1441. if (isEncryptionOnlyCertRequest)
  1442. {
  1443. escrowEncryptionOnlyCert =
  1444. CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
  1445. }
  1446. bool gotDHMACParameters = false;
  1447. if (isECKeyGenType(keyInfo->keyGenType) &&
  1448. keyInfo->ecPopCert &&
  1449. keyInfo->ecPopPubKey)
  1450. {
  1451. gotDHMACParameters = true;
  1452. }
  1453. if (isEncryptionOnlyCertRequest)
  1454. {
  1455. if (escrowEncryptionOnlyCert)
  1456. return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
  1457. if (gotDHMACParameters)
  1458. return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1459. return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
  1460. }
  1461. // !isEncryptionOnlyCertRequest
  1462. SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
  1463. keyInfo->privKey,
  1464. keyInfo->pubKey, nsnull,
  1465. nsnull, nsnull);
  1466. if (srv == SECSuccess)
  1467. return NS_OK;
  1468. if (!gotDHMACParameters)
  1469. return NS_ERROR_FAILURE;
  1470. return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
  1471. }
  1472. static void PR_CALLBACK
  1473. nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
  1474. {
  1475. unsigned long *count = (unsigned long *)arg;
  1476. *count += len;
  1477. }
  1478. static void PR_CALLBACK
  1479. nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
  1480. {
  1481. SECItem *dest = (SECItem *)arg;
  1482. memcpy(dest->data + dest->len, buf, len);
  1483. dest->len += len;
  1484. }
  1485. static SECItem*
  1486. nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
  1487. {
  1488. unsigned long len = 0;
  1489. if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
  1490. != SECSuccess) {
  1491. return nsnull;
  1492. }
  1493. SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
  1494. if (dest == nsnull) {
  1495. return nsnull;
  1496. }
  1497. dest->type = siBuffer;
  1498. dest->data = (unsigned char *)PORT_Alloc(len);
  1499. if (dest->data == nsnull) {
  1500. PORT_Free(dest);
  1501. return nsnull;
  1502. }
  1503. dest->len = 0;
  1504. if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
  1505. != SECSuccess) {
  1506. SECITEM_FreeItem(dest, true);
  1507. return nsnull;
  1508. }
  1509. return dest;
  1510. }
  1511. //Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
  1512. //requesting one or more certificates to be issued. This function
  1513. //creates a single cert request per key pair and then appends it to
  1514. //a message that is ultimately sent off to a CA.
  1515. static char*
  1516. nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, PRInt32 numRequests,
  1517. char *reqDN, char *regToken, char *authenticator,
  1518. nsNSSCertificate *wrappingCert)
  1519. {
  1520. // We'use the goto notation for clean-up purposes in this function
  1521. // that calls the C API of NSS.
  1522. PRInt32 i;
  1523. // The ASN1 encoder in NSS wants the last entry in the array to be
  1524. // NULL so that it knows when the last element is.
  1525. CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
  1526. CRMFCertRequest *certReq;
  1527. if (!certReqMsgs)
  1528. return nsnull;
  1529. memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
  1530. SECStatus srv;
  1531. nsresult rv;
  1532. SECItem *encodedReq;
  1533. char *retString;
  1534. for (i=0; i<numRequests; i++) {
  1535. certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
  1536. wrappingCert);
  1537. if (!certReq)
  1538. goto loser;
  1539. certReqMsgs[i] = CRMF_CreateCertReqMsg();
  1540. if (!certReqMsgs[i])
  1541. goto loser;
  1542. srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
  1543. if (srv != SECSuccess)
  1544. goto loser;
  1545. rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
  1546. if (NS_FAILED(rv))
  1547. goto loser;
  1548. CRMF_DestroyCertRequest(certReq);
  1549. }
  1550. encodedReq = nsEncodeCertReqMessages(certReqMsgs);
  1551. nsFreeCertReqMessages(certReqMsgs, numRequests);
  1552. retString = NSSBase64_EncodeItem (nsnull, nsnull, 0, encodedReq);
  1553. SECITEM_FreeItem(encodedReq, true);
  1554. return retString;
  1555. loser:
  1556. nsFreeCertReqMessages(certReqMsgs,numRequests);
  1557. return nsnull;;
  1558. }
  1559. static nsISupports *
  1560. GetISupportsFromContext(JSContext *cx)
  1561. {
  1562. if (JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
  1563. return static_cast<nsISupports *>(JS_GetContextPrivate(cx));
  1564. return nsnull;
  1565. }
  1566. //The top level method which is a member of nsIDOMCrypto
  1567. //for generate a base64 encoded CRMF request.
  1568. NS_IMETHODIMP
  1569. nsCrypto::GenerateCRMFRequest(nsIDOMCRMFObject** aReturn)
  1570. {
  1571. nsNSSShutDownPreventionLock locker;
  1572. *aReturn = nsnull;
  1573. nsresult nrv;
  1574. nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &nrv));
  1575. NS_ENSURE_SUCCESS(nrv, nrv);
  1576. nsAXPCNativeCallContext *ncc = nsnull;
  1577. nrv = xpc->GetCurrentNativeCallContext(&ncc);
  1578. NS_ENSURE_SUCCESS(nrv, nrv);
  1579. if (!ncc)
  1580. return NS_ERROR_NOT_AVAILABLE;
  1581. PRUint32 argc;
  1582. ncc->GetArgc(&argc);
  1583. jsval *argv = nsnull;
  1584. nrv = ncc->GetArgvPtr(&argv);
  1585. NS_ENSURE_SUCCESS(nrv, nrv);
  1586. JSContext *cx;
  1587. nrv = ncc->GetJSContext(&cx);
  1588. NS_ENSURE_SUCCESS(nrv, nrv);
  1589. JSObject* script_obj = nsnull;
  1590. nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
  1591. JSAutoRequest ar(cx);
  1592. /*
  1593. * Get all of the parameters.
  1594. */
  1595. if (argc < 5 || ((argc-5) % 3) != 0) {
  1596. JS_ReportError(cx, "%s", "%s%s\n", JS_ERROR,
  1597. "incorrect number of parameters");
  1598. return NS_ERROR_FAILURE;
  1599. }
  1600. if (JSVAL_IS_NULL(argv[0])) {
  1601. JS_ReportError(cx, "%s%s\n", JS_ERROR, "no DN specified");
  1602. return NS_ERROR_FAILURE;
  1603. }
  1604. JSString *jsString = JS_ValueToString(cx,argv[0]);
  1605. NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
  1606. argv[0] = STRING_TO_JSVAL(jsString);
  1607. JSAutoByteString reqDN(cx,jsString);
  1608. NS_ENSURE_TRUE(!!reqDN, NS_ERROR_OUT_OF_MEMORY);
  1609. JSAutoByteString regToken;
  1610. if (!JSVAL_IS_NULL(argv[1])) {
  1611. jsString = JS_ValueToString(cx, argv[1]);
  1612. NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
  1613. argv[1] = STRING_TO_JSVAL(jsString);
  1614. regToken.encode(cx, jsString);
  1615. NS_ENSURE_TRUE(!!regToken, NS_ERROR_OUT_OF_MEMORY);
  1616. }
  1617. JSAutoByteString authenticator;
  1618. if (!JSVAL_IS_NULL(argv[2])) {
  1619. jsString = JS_ValueToString(cx, argv[2]);
  1620. NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
  1621. argv[2] = STRING_TO_JSVAL(jsString);
  1622. authenticator.encode(cx, jsString);
  1623. NS_ENSURE_TRUE(!!authenticator, NS_ERROR_OUT_OF_MEMORY);
  1624. }
  1625. JSAutoByteString eaCert;
  1626. if (!JSVAL_IS_NULL(argv[3])) {
  1627. jsString = JS_ValueToString(cx, argv[3]);
  1628. NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
  1629. argv[3] = STRING_TO_JSVAL(jsString);
  1630. eaCert.encode(cx, jsString);
  1631. NS_ENSURE_TRUE(!!eaCert, NS_ERROR_OUT_OF_MEMORY);
  1632. }
  1633. if (JSVAL_IS_NULL(argv[4])) {
  1634. JS_ReportError(cx, "%s%s\n", JS_ERROR, "no completion "
  1635. "function specified");
  1636. return NS_ERROR_FAILURE;
  1637. }
  1638. jsString = JS_ValueToString(cx, argv[4]);
  1639. NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
  1640. argv[4] = STRING_TO_JSVAL(jsString);
  1641. JSAutoByteString jsCallback(cx, jsString);
  1642. NS_ENSURE_TRUE(!!jsCallback, NS_ERROR_OUT_OF_MEMORY);
  1643. nrv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx),
  1644. static_cast<nsIDOMCrypto *>(this),
  1645. NS_GET_IID(nsIDOMCrypto), getter_AddRefs(holder));
  1646. NS_ENSURE_SUCCESS(nrv, nrv);
  1647. nrv = holder->GetJSObject(&script_obj);
  1648. NS_ENSURE_SUCCESS(nrv, nrv);
  1649. //Put up some UI warning that someone is trying to
  1650. //escrow the private key.
  1651. //Don't addref this copy. That way ths reference goes away
  1652. //at the same the nsIX09Cert ref goes away.
  1653. nsNSSCertificate *escrowCert = nsnull;
  1654. nsCOMPtr<nsIX509Cert> nssCert;
  1655. bool willEscrow = false;
  1656. if (!!eaCert) {
  1657. SECItem certDer = {siBuffer, nsnull, 0};
  1658. SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, eaCert.ptr());
  1659. if (srv != SECSuccess) {
  1660. return NS_ERROR_FAILURE;
  1661. }
  1662. CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1663. &certDer, nsnull, false,
  1664. true);
  1665. if (!cert)
  1666. return NS_ERROR_FAILURE;
  1667. escrowCert = nsNSSCertificate::Create(cert);
  1668. CERT_DestroyCertificate(cert);
  1669. nssCert = escrowCert;
  1670. if (!nssCert)
  1671. return NS_ERROR_OUT_OF_MEMORY;
  1672. nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
  1673. nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
  1674. NS_GET_IID(nsIDOMCryptoDialogs),
  1675. NS_DOMCRYPTODIALOGS_CONTRACTID);
  1676. if (NS_FAILED(rv))
  1677. return rv;
  1678. bool okay=false;
  1679. {
  1680. nsPSMUITracker tracker;
  1681. if (tracker.isUIForbidden()) {
  1682. okay = false;
  1683. }
  1684. else {
  1685. dialogs->ConfirmKeyEscrow(nssCert, &okay);
  1686. }
  1687. }
  1688. if (!okay)
  1689. return NS_OK;
  1690. willEscrow = true;
  1691. }
  1692. nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
  1693. PRInt32 numRequests = (argc - 5)/3;
  1694. nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
  1695. if (keyids == nsnull) {
  1696. JS_ReportError(cx, "%s\n", JS_ERROR_INTERNAL);
  1697. return NS_ERROR_OUT_OF_MEMORY;
  1698. }
  1699. memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
  1700. int keyInfoIndex;
  1701. PRUint32 i;
  1702. PK11SlotInfo *slot = nsnull;
  1703. // Go through all of the arguments and generate the appropriate key pairs.
  1704. for (i=5,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
  1705. nrv = cryptojs_ReadArgsAndGenerateKey(cx, &argv[i], &keyids[keyInfoIndex],
  1706. uiCxt, &slot, willEscrow);
  1707. if (NS_FAILED(nrv)) {
  1708. if (slot)
  1709. PK11_FreeSlot(slot);
  1710. nsFreeKeyPairInfo(keyids,numRequests);
  1711. return nrv;
  1712. }
  1713. }
  1714. // By this time we'd better have a slot for the key gen.
  1715. NS_ASSERTION(slot, "There was no slot selected for key generation");
  1716. if (slot)
  1717. PK11_FreeSlot(slot);
  1718. char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
  1719. reqDN.ptr(),regToken.ptr(),
  1720. authenticator.ptr(),
  1721. escrowCert);
  1722. #ifdef DEBUG_javi
  1723. printf ("Created the folloing CRMF request:\n%s\n", encodedRequest);
  1724. #endif
  1725. if (!encodedRequest) {
  1726. nsFreeKeyPairInfo(keyids, numRequests);
  1727. return NS_ERROR_FAILURE;
  1728. }
  1729. nsCRMFObject *newObject = new nsCRMFObject();
  1730. if (newObject == nsnull) {
  1731. JS_ReportError(cx, "%s%s\n", JS_ERROR, "could not create crmf JS object");
  1732. nsFreeKeyPairInfo(keyids,numRequests);
  1733. return NS_ERROR_OUT_OF_MEMORY;
  1734. }
  1735. newObject->SetCRMFRequest(encodedRequest);
  1736. *aReturn = newObject;
  1737. //Give a reference to the returnee.
  1738. NS_ADDREF(*aReturn);
  1739. nsFreeKeyPairInfo(keyids, numRequests);
  1740. //
  1741. // Post an event on the UI queue so that the JS gets called after
  1742. // we return control to the JS layer. Why do we have to this?
  1743. // Because when this API was implemented for PSM 1.x w/ Communicator,
  1744. // the only way to make this method work was to have a callback
  1745. // in the JS layer that got called after key generation had happened.
  1746. // So for backwards compatibility, we return control and then just post
  1747. // an event to call the JS the script provides as the code to execute
  1748. // when the request has been generated.
  1749. //
  1750. nsCOMPtr<nsIScriptSecurityManager> secMan =
  1751. do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
  1752. NS_ENSURE_TRUE(secMan, NS_ERROR_UNEXPECTED);
  1753. nsCOMPtr<nsIPrincipal> principals;
  1754. nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals));
  1755. NS_ENSURE_SUCCESS(rv, rv);
  1756. NS_ENSURE_TRUE(principals, NS_ERROR_UNEXPECTED);
  1757. nsCryptoRunArgs *args = new nsCryptoRunArgs();
  1758. if (!args)
  1759. return NS_ERROR_OUT_OF_MEMORY;
  1760. args->m_cx = cx;
  1761. args->m_kungFuDeathGrip = GetISupportsFromContext(cx);
  1762. args->m_scope = JS_GetParent(script_obj);
  1763. args->m_jsCallback.Adopt(!!jsCallback ? nsCRT::strdup(jsCallback.ptr()) : 0);
  1764. args->m_principals = principals;
  1765. nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args);
  1766. if (!cryptoRunnable)
  1767. return NS_ERROR_OUT_OF_MEMORY;
  1768. rv = NS_DispatchToMainThread(cryptoRunnable);
  1769. if (NS_FAILED(rv))
  1770. delete cryptoRunnable;
  1771. return rv;
  1772. }
  1773. // Reminder that we inherit the memory passed into us here.
  1774. // An implementation to let us back up certs as an event.
  1775. nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, PRInt32 numCerts,
  1776. nsIPK11Token *token)
  1777. {
  1778. mCertArr = certArr;
  1779. mNumCerts = numCerts;
  1780. mToken = token;
  1781. }
  1782. nsP12Runnable::~nsP12Runnable()
  1783. {
  1784. PRInt32 i;
  1785. for (i=0; i<mNumCerts; i++) {
  1786. NS_IF_RELEASE(mCertArr[i]);
  1787. }
  1788. delete []mCertArr;
  1789. }
  1790. //Implementation that backs cert(s) into a PKCS12 file
  1791. NS_IMETHODIMP
  1792. nsP12Runnable::Run()
  1793. {
  1794. NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
  1795. nsNSSShutDownPreventionLock locker;
  1796. NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
  1797. nsString final;
  1798. nsString temp;
  1799. nsresult rv;
  1800. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1801. if (NS_FAILED(rv))
  1802. return rv;
  1803. //Build up the message that let's the user know we're trying to
  1804. //make PKCS12 backups of the new certs.
  1805. nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
  1806. final.Append(NS_LITERAL_STRING("\n\n").get());
  1807. nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
  1808. final.Append(temp.get());
  1809. final.Append(NS_LITERAL_STRING("\n\n").get());
  1810. nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
  1811. final.Append(temp.get());
  1812. nsNSSComponent::ShowAlertWithConstructedString(final);
  1813. nsCOMPtr<nsIFilePicker> filePicker =
  1814. do_CreateInstance("@mozilla.org/filepicker;1", &rv);
  1815. if (!filePicker) {
  1816. NS_ERROR("Could not create a file picker when backing up certs.");
  1817. return rv;
  1818. }
  1819. nsCOMPtr<nsIWindowWatcher> wwatch =
  1820. (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
  1821. NS_ENSURE_SUCCESS(rv, rv);
  1822. nsCOMPtr<nsIDOMWindow> window;
  1823. wwatch->GetActiveWindow(getter_AddRefs(window));
  1824. nsString filePickMessage;
  1825. nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
  1826. filePickMessage);
  1827. rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
  1828. NS_ENSURE_SUCCESS(rv, rv);
  1829. filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
  1830. NS_LITERAL_STRING("*.p12"));
  1831. filePicker->AppendFilters(nsIFilePicker::filterAll);
  1832. PRInt16 dialogReturn;
  1833. filePicker->Show(&dialogReturn);
  1834. if (dialogReturn == nsIFilePicker::returnCancel)
  1835. return NS_OK; //User canceled. It'd be nice if they couldn't,
  1836. //but oh well.
  1837. nsCOMPtr<nsILocalFile> localFile;
  1838. rv = filePicker->GetFile(getter_AddRefs(localFile));
  1839. if (NS_FAILED(rv))
  1840. return NS_ERROR_FAILURE;
  1841. nsPKCS12Blob p12Cxt;
  1842. p12Cxt.SetToken(mToken);
  1843. p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
  1844. return NS_OK;
  1845. }
  1846. nsCryptoRunArgs::nsCryptoRunArgs()
  1847. {
  1848. }
  1849. nsCryptoRunArgs::~nsCryptoRunArgs() {}
  1850. nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
  1851. {
  1852. nsNSSShutDownPreventionLock locker;
  1853. NS_ASSERTION(args,"Passed nsnull to nsCryptoRunnable constructor.");
  1854. m_args = args;
  1855. NS_IF_ADDREF(m_args);
  1856. JS_AddNamedObjectRoot(args->m_cx, &args->m_scope,"nsCryptoRunnable::mScope");
  1857. }
  1858. nsCryptoRunnable::~nsCryptoRunnable()
  1859. {
  1860. nsNSSShutDownPreventionLock locker;
  1861. {
  1862. JSAutoRequest ar(m_args->m_cx);
  1863. JS_RemoveObjectRoot(m_args->m_cx, &m_args->m_scope);
  1864. }
  1865. NS_IF_RELEASE(m_args);
  1866. }
  1867. //Implementation that runs the callback passed to
  1868. //crypto.generateCRMFRequest as an event.
  1869. NS_IMETHODIMP
  1870. nsCryptoRunnable::Run()
  1871. {
  1872. nsNSSShutDownPreventionLock locker;
  1873. JSPrincipals *principals;
  1874. JSContext *cx = m_args->m_cx;
  1875. JSAutoRequest ar(cx);
  1876. JSAutoEnterCompartment ac;
  1877. if (!ac.enter(cx, m_args->m_scope)) {
  1878. return NS_ERROR_FAILURE;
  1879. }
  1880. nsresult rv = m_args->m_principals->GetJSPrincipals(cx, &principals);
  1881. if (NS_FAILED(rv))
  1882. return NS_ERROR_FAILURE;
  1883. // make sure the right context is on the stack. must not return w/out popping
  1884. nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
  1885. if (!stack || NS_FAILED(stack->Push(cx))) {
  1886. JSPRINCIPALS_DROP(cx, principals);
  1887. return NS_ERROR_FAILURE;
  1888. }
  1889. jsval retval;
  1890. if (JS_EvaluateScriptForPrincipals(cx, m_args->m_scope, principals,
  1891. m_args->m_jsCallback,
  1892. strlen(m_args->m_jsCallback),
  1893. nsnull, 0,
  1894. &retval) != JS_TRUE) {
  1895. rv = NS_ERROR_FAILURE;
  1896. }
  1897. stack->Pop(nsnull);
  1898. JSPRINCIPALS_DROP(cx, principals);
  1899. return rv;
  1900. }
  1901. //Quick helper function to check if a newly issued cert
  1902. //already exists in the user's database.
  1903. static bool
  1904. nsCertAlreadyExists(SECItem *derCert)
  1905. {
  1906. CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
  1907. CERTCertificate *cert;
  1908. bool retVal = false;
  1909. cert = CERT_FindCertByDERCert(handle, derCert);
  1910. if (cert) {
  1911. if (cert->isperm && !cert->nickname && !cert->emailAddr) {
  1912. //If the cert doesn't have a nickname or email addr, it is
  1913. //bogus cruft, so delete it.
  1914. SEC_DeletePermCertificate(cert);
  1915. } else if (cert->isperm) {
  1916. retVal = true;
  1917. }
  1918. CERT_DestroyCertificate(cert);
  1919. }
  1920. return retVal;
  1921. }
  1922. static PRInt32
  1923. nsCertListCount(CERTCertList *certList)
  1924. {
  1925. PRInt32 numCerts = 0;
  1926. CERTCertListNode *node;
  1927. node = CERT_LIST_HEAD(certList);
  1928. while (!CERT_LIST_END(node, certList)) {
  1929. numCerts++;
  1930. node = CERT_LIST_NEXT(node);
  1931. }
  1932. return numCerts;
  1933. }
  1934. //Import user certificates that arrive as a CMMF base64 encoded
  1935. //string.
  1936. NS_IMETHODIMP
  1937. nsCrypto::ImportUserCertificates(const nsAString& aNickname,
  1938. const nsAString& aCmmfResponse,
  1939. bool aDoForcedBackup,
  1940. nsAString& aReturn)
  1941. {
  1942. nsNSSShutDownPreventionLock locker;
  1943. char *nickname=nsnull, *cmmfResponse=nsnull;
  1944. CMMFCertRepContent *certRepContent = nsnull;
  1945. int numResponses = 0;
  1946. nsIX509Cert **certArr = nsnull;
  1947. int i;
  1948. CMMFCertResponse *currResponse;
  1949. CMMFPKIStatus reqStatus;
  1950. CERTCertificate *currCert;
  1951. PK11SlotInfo *slot;
  1952. nsCAutoString localNick;
  1953. nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  1954. nsresult rv = NS_OK;
  1955. CERTCertList *caPubs = nsnull;
  1956. nsCOMPtr<nsIPK11Token> token;
  1957. nickname = ToNewCString(aNickname);
  1958. cmmfResponse = ToNewCString(aCmmfResponse);
  1959. if (nsCRT::strcmp("null", nickname) == 0) {
  1960. nsMemory::Free(nickname);
  1961. nickname = nsnull;
  1962. }
  1963. SECItem cmmfDer = {siBuffer, nsnull, 0};
  1964. SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
  1965. if (srv != SECSuccess) {
  1966. rv = NS_ERROR_FAILURE;
  1967. goto loser;
  1968. }
  1969. certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
  1970. (const char*)cmmfDer.data,
  1971. cmmfDer.len);
  1972. if (!certRepContent) {
  1973. rv = NS_ERROR_FAILURE;
  1974. goto loser;
  1975. }
  1976. numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
  1977. if (aDoForcedBackup) {
  1978. //We've been asked to force the user to back up these
  1979. //certificates. Let's keep an array of them around which
  1980. //we pass along to the nsP12Runnable to use.
  1981. certArr = new nsIX509Cert*[numResponses];
  1982. // If this is NULL, chances are we're gonna fail really soon,
  1983. // but let's try to keep going just in case.
  1984. if (!certArr)
  1985. aDoForcedBackup = false;
  1986. memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
  1987. }
  1988. for (i=0; i<numResponses; i++) {
  1989. currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
  1990. if (!currResponse) {
  1991. rv = NS_ERROR_FAILURE;
  1992. goto loser;
  1993. }
  1994. reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
  1995. if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
  1996. // The CA didn't give us the cert we requested.
  1997. rv = NS_ERROR_FAILURE;
  1998. goto loser;
  1999. }
  2000. currCert = CMMF_CertResponseGetCertificate(currResponse,
  2001. CERT_GetDefaultCertDB());
  2002. if (!currCert) {
  2003. rv = NS_ERROR_FAILURE;
  2004. goto loser;
  2005. }
  2006. if (nsCertAlreadyExists(&currCert->derCert)) {
  2007. if (aDoForcedBackup) {
  2008. certArr[i] = nsNSSCertificate::Create(currCert);
  2009. if (!certArr[i])
  2010. goto loser;
  2011. NS_ADDREF(certArr[i]);
  2012. }
  2013. CERT_DestroyCertificate(currCert);
  2014. CMMF_DestroyCertResponse(currResponse);
  2015. continue;
  2016. }
  2017. // Let's figure out which nickname to give the cert. If
  2018. // a certificate with the same subject name already exists,
  2019. // then just use that one, otherwise, get the default nickname.
  2020. if (currCert->nickname) {
  2021. localNick = currCert->nickname;
  2022. }
  2023. else if (nickname == nsnull || nickname[0] == '\0') {
  2024. nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick);
  2025. } else {
  2026. //This is the case where we're getting a brand new
  2027. //cert that doesn't have the same subjectName as a cert
  2028. //that already exists in our db and the CA page has
  2029. //designated a nickname to use for the newly issued cert.
  2030. localNick = nickname;
  2031. }
  2032. {
  2033. char *cast_const_away = const_cast<char*>(localNick.get());
  2034. slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
  2035. }
  2036. if (slot == nsnull) {
  2037. rv = NS_ERROR_FAILURE;
  2038. goto loser;
  2039. }
  2040. if (aDoForcedBackup) {
  2041. certArr[i] = nsNSSCertificate::Create(currCert);
  2042. if (!certArr[i])
  2043. goto loser;
  2044. NS_ADDREF(certArr[i]);
  2045. }
  2046. CERT_DestroyCertificate(currCert);
  2047. if (!token)
  2048. token = new nsPK11Token(slot);
  2049. PK11_FreeSlot(slot);
  2050. CMMF_DestroyCertResponse(currResponse);
  2051. }
  2052. //Let the loser: label take care of freeing up our reference to
  2053. //nickname (This way we don't free it twice and avoid crashing.
  2054. //That would be a good thing.
  2055. //Import the root chain into the cert db.
  2056. caPubs = CMMF_CertRepContentGetCAPubs(certRepContent);
  2057. if (caPubs) {
  2058. PRInt32 numCAs = nsCertListCount(caPubs);
  2059. NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
  2060. if (numCAs > 0) {
  2061. CERTCertListNode *node;
  2062. SECItem *derCerts;
  2063. derCerts = static_cast<SECItem*>
  2064. (nsMemory::Alloc(sizeof(SECItem)*numCAs));
  2065. if (!derCerts) {
  2066. rv = NS_ERROR_OUT_OF_MEMORY;
  2067. goto loser;
  2068. }
  2069. for (node = CERT_LIST_HEAD(caPubs), i=0;
  2070. !CERT_LIST_END(node, caPubs);
  2071. node = CERT_LIST_NEXT(node), i++) {
  2072. derCerts[i] = node->cert->derCert;
  2073. }
  2074. nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx);
  2075. nsMemory::Free(derCerts);
  2076. }
  2077. CERT_DestroyCertList(caPubs);
  2078. }
  2079. if (aDoForcedBackup) {
  2080. // I can't pop up a file picker from the depths of JavaScript,
  2081. // so I'll just post an event on the UI queue to do the backups
  2082. // later.
  2083. nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
  2084. token);
  2085. if (!p12Runnable) {
  2086. rv = NS_ERROR_FAILURE;
  2087. goto loser;
  2088. }
  2089. // null out the certArr pointer which has now been inherited by
  2090. // the nsP12Runnable instance so that we don't free up the
  2091. // memory on the way out.
  2092. certArr = nsnull;
  2093. rv = NS_DispatchToMainThread(p12Runnable);
  2094. if (NS_FAILED(rv))
  2095. goto loser;
  2096. }
  2097. loser:
  2098. if (certArr) {
  2099. for (i=0; i<numResponses; i++) {
  2100. NS_IF_RELEASE(certArr[i]);
  2101. }
  2102. delete []certArr;
  2103. }
  2104. aReturn.Assign(EmptyString());
  2105. if (nickname) {
  2106. NS_Free(nickname);
  2107. }
  2108. if (cmmfResponse) {
  2109. NS_Free(cmmfResponse);
  2110. }
  2111. if (certRepContent) {
  2112. CMMF_DestroyCertRepContent(certRepContent);
  2113. }
  2114. return rv;
  2115. }
  2116. NS_IMETHODIMP
  2117. nsCrypto::PopChallengeResponse(const nsAString& aChallenge,
  2118. nsAString& aReturn)
  2119. {
  2120. return NS_ERROR_NOT_IMPLEMENTED;
  2121. }
  2122. NS_IMETHODIMP
  2123. nsCrypto::Random(PRInt32 aNumBytes, nsAString& aReturn)
  2124. {
  2125. return NS_ERROR_NOT_IMPLEMENTED;
  2126. }
  2127. static void
  2128. GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
  2129. {
  2130. // Get the script context.
  2131. nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
  2132. if (!scriptContext) {
  2133. return;
  2134. }
  2135. nsCOMPtr<nsIDOMWindow> domWindow =
  2136. do_QueryInterface(scriptContext->GetGlobalObject());
  2137. if (!domWindow) {
  2138. return;
  2139. }
  2140. nsCOMPtr<nsIDOMDocument> domDocument;
  2141. domWindow->GetDocument(getter_AddRefs(domDocument));
  2142. if (!domDocument) {
  2143. return;
  2144. }
  2145. CallQueryInterface(domDocument, aDocument);
  2146. return;
  2147. }
  2148. void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
  2149. {
  2150. ((nsCString*)arg)->Append(buf, len);
  2151. }
  2152. NS_IMETHODIMP
  2153. nsCrypto::SignText(const nsAString& aStringToSign, const nsAString& aCaOption,
  2154. nsAString& aResult)
  2155. {
  2156. // XXX This code should return error codes, but we're keeping this
  2157. // backwards compatible with NS4.x and so we can't throw exceptions.
  2158. NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
  2159. aResult.Truncate();
  2160. nsAXPCNativeCallContext* ncc = nsnull;
  2161. nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
  2162. if (xpc) {
  2163. xpc->GetCurrentNativeCallContext(&ncc);
  2164. }
  2165. if (!ncc) {
  2166. aResult.Append(internalError);
  2167. return NS_OK;
  2168. }
  2169. PRUint32 argc;
  2170. ncc->GetArgc(&argc);
  2171. JSContext *cx;
  2172. ncc->GetJSContext(&cx);
  2173. if (!cx) {
  2174. aResult.Append(internalError);
  2175. return NS_OK;
  2176. }
  2177. if (!aCaOption.EqualsLiteral("auto") &&
  2178. !aCaOption.EqualsLiteral("ask")) {
  2179. JS_ReportError(cx, "%s%s\n", JS_ERROR, "caOption argument must be ask or auto");
  2180. aResult.Append(internalError);
  2181. return NS_OK;
  2182. }
  2183. // It was decided to always behave as if "ask" were specified.
  2184. // XXX Should we warn in the JS Console for auto?
  2185. nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
  2186. if (!uiContext) {
  2187. aResult.Append(internalError);
  2188. return NS_OK;
  2189. }
  2190. bool bestOnly = true;
  2191. bool validOnly = true;
  2192. CERTCertList* certList =
  2193. CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
  2194. bestOnly, validOnly, uiContext);
  2195. PRUint32 numCAs = argc - 2;
  2196. if (numCAs > 0) {
  2197. jsval *argv = nsnull;
  2198. ncc->GetArgvPtr(&argv);
  2199. nsAutoArrayPtr<JSAutoByteString> caNameBytes(new JSAutoByteString[numCAs]);
  2200. if (!caNameBytes) {
  2201. aResult.Append(internalError);
  2202. return NS_OK;
  2203. }
  2204. JSAutoRequest ar(cx);
  2205. PRUint32 i;
  2206. for (i = 2; i < argc; ++i) {
  2207. JSString *caName = JS_ValueToString(cx, argv[i]);
  2208. NS_ENSURE_TRUE(caName, NS_ERROR_OUT_OF_MEMORY);
  2209. argv[i] = STRING_TO_JSVAL(caName);
  2210. caNameBytes[i - 2].encode(cx, caName);
  2211. NS_ENSURE_TRUE(!!caNameBytes[i - 2], NS_ERROR_OUT_OF_MEMORY);
  2212. }
  2213. nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
  2214. if (!caNames) {
  2215. aResult.Append(internalError);
  2216. return NS_OK;
  2217. }
  2218. for (i = 0; i < numCAs; ++i)
  2219. caNames[i] = caNameBytes[i].ptr();
  2220. if (certList &&
  2221. CERT_FilterCertListByCANames(certList, numCAs, caNames,
  2222. certUsageEmailSigner) != SECSuccess) {
  2223. aResult.Append(internalError);
  2224. return NS_OK;
  2225. }
  2226. }
  2227. if (!certList || CERT_LIST_EMPTY(certList)) {
  2228. aResult.AppendLiteral("error:noMatchingCert");
  2229. return NS_OK;
  2230. }
  2231. nsCOMPtr<nsIFormSigningDialog> fsd =
  2232. do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
  2233. if (!fsd) {
  2234. aResult.Append(internalError);
  2235. return NS_OK;
  2236. }
  2237. nsCOMPtr<nsIDocument> document;
  2238. GetDocumentFromContext(cx, getter_AddRefs(document));
  2239. if (!document) {
  2240. aResult.Append(internalError);
  2241. return NS_OK;
  2242. }
  2243. // Get the hostname from the URL of the document.
  2244. nsIURI* uri = document->GetDocumentURI();
  2245. if (!uri) {
  2246. aResult.Append(internalError);
  2247. return NS_OK;
  2248. }
  2249. nsresult rv;
  2250. nsCString host;
  2251. rv = uri->GetHost(host);
  2252. if (NS_FAILED(rv)) {
  2253. aResult.Append(internalError);
  2254. return NS_OK;
  2255. }
  2256. PRInt32 numberOfCerts = 0;
  2257. CERTCertListNode* node;
  2258. for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  2259. node = CERT_LIST_NEXT(node)) {
  2260. ++numberOfCerts;
  2261. }
  2262. CERTCertNicknames* nicknames = getNSSCertNicknamesFromCertList(certList);
  2263. if (!nicknames) {
  2264. aResult.Append(internalError);
  2265. return NS_OK;
  2266. }
  2267. CERTCertNicknamesCleaner cnc(nicknames);
  2268. NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
  2269. "nicknames->numnicknames != numberOfCerts");
  2270. nsAutoArrayPtr<PRUnichar*> certNicknameList(new PRUnichar*[nicknames->numnicknames * 2]);
  2271. if (!certNicknameList) {
  2272. aResult.Append(internalError);
  2273. return NS_OK;
  2274. }
  2275. PRUnichar** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
  2276. PRInt32 certsToUse;
  2277. for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
  2278. !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
  2279. node = CERT_LIST_NEXT(node)) {
  2280. nsRefPtr<nsNSSCertificate> tempCert = nsNSSCertificate::Create(node->cert);
  2281. if (tempCert) {
  2282. nsAutoString nickWithSerial, details;
  2283. rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
  2284. nickWithSerial, details);
  2285. if (NS_SUCCEEDED(rv)) {
  2286. certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
  2287. if (certNicknameList[certsToUse]) {
  2288. certDetailsList[certsToUse] = ToNewUnicode(details);
  2289. if (!certDetailsList[certsToUse]) {
  2290. nsMemory::Free(certNicknameList[certsToUse]);
  2291. continue;
  2292. }
  2293. ++certsToUse;
  2294. }
  2295. }
  2296. }
  2297. }
  2298. if (certsToUse == 0) {
  2299. aResult.Append(internalError);
  2300. return NS_OK;
  2301. }
  2302. NS_ConvertUTF8toUTF16 utf16Host(host);
  2303. CERTCertificate *signingCert = nsnull;
  2304. bool tryAgain, canceled;
  2305. nsAutoString password;
  2306. do {
  2307. // Throw up the form signing confirmation dialog and get back the index
  2308. // of the selected cert.
  2309. PRInt32 selectedIndex = -1;
  2310. rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
  2311. const_cast<const PRUnichar**>(certNicknameList.get()),
  2312. const_cast<const PRUnichar**>(certDetailsList),
  2313. certsToUse, &selectedIndex, password,
  2314. &canceled);
  2315. if (NS_FAILED(rv) || canceled) {
  2316. break; // out of tryAgain loop
  2317. }
  2318. PRInt32 j = 0;
  2319. for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
  2320. node = CERT_LIST_NEXT(node)) {
  2321. if (j == selectedIndex) {
  2322. signingCert = CERT_DupCertificate(node->cert);
  2323. break; // out of cert list iteration loop
  2324. }
  2325. ++j;
  2326. }
  2327. if (!signingCert) {
  2328. rv = NS_ERROR_FAILURE;
  2329. break; // out of tryAgain loop
  2330. }
  2331. NS_ConvertUTF16toUTF8 pwUtf8(password);
  2332. tryAgain =
  2333. PK11_CheckUserPassword(signingCert->slot,
  2334. const_cast<char *>(pwUtf8.get())) != SECSuccess;
  2335. // XXX we should show an error dialog before retrying
  2336. } while (tryAgain);
  2337. PRInt32 k;
  2338. for (k = 0; k < certsToUse; ++k) {
  2339. nsMemory::Free(certNicknameList[k]);
  2340. nsMemory::Free(certDetailsList[k]);
  2341. }
  2342. if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
  2343. aResult.Append(internalError);
  2344. return NS_OK;
  2345. }
  2346. if (canceled) {
  2347. aResult.AppendLiteral("error:userCancel");
  2348. return NS_OK;
  2349. }
  2350. SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
  2351. if (!privKey) {
  2352. aResult.Append(internalError);
  2353. return NS_OK;
  2354. }
  2355. nsCAutoString charset(document->GetDocumentCharacterSet());
  2356. // XXX Doing what nsFormSubmission::GetEncoder does (see
  2357. // http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
  2358. if (charset.EqualsLiteral("ISO-8859-1")) {
  2359. charset.AssignLiteral("windows-1252");
  2360. }
  2361. nsCOMPtr<nsISaveAsCharset> encoder =
  2362. do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
  2363. if (encoder) {
  2364. rv = encoder->Init(charset.get(),
  2365. (nsISaveAsCharset::attr_EntityAfterCharsetConv +
  2366. nsISaveAsCharset::attr_FallbackDecimalNCR),
  2367. 0);
  2368. }
  2369. nsXPIDLCString buffer;
  2370. if (aStringToSign.Length() > 0) {
  2371. if (encoder && NS_SUCCEEDED(rv)) {
  2372. rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
  2373. getter_Copies(buffer));
  2374. if (NS_FAILED(rv)) {
  2375. aResult.Append(internalError);
  2376. return NS_OK;
  2377. }
  2378. }
  2379. else {
  2380. AppendUTF16toUTF8(aStringToSign, buffer);
  2381. }
  2382. }
  2383. HASHContext *hc = HASH_Create(HASH_AlgSHA1);
  2384. if (!hc) {
  2385. aResult.Append(internalError);
  2386. return NS_OK;
  2387. }
  2388. unsigned char hash[SHA1_LENGTH];
  2389. SECItem digest;
  2390. digest.data = hash;
  2391. HASH_Begin(hc);
  2392. HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
  2393. buffer.Length());
  2394. HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
  2395. HASH_Destroy(hc);
  2396. nsCString p7;
  2397. SECStatus srv = SECFailure;
  2398. SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
  2399. certUsageEmailSigner,
  2400. nsnull, SEC_OID_SHA1,
  2401. &digest, nsnull, uiContext);
  2402. if (ci) {
  2403. srv = SEC_PKCS7IncludeCertChain(ci, nsnull);
  2404. if (srv == SECSuccess) {
  2405. srv = SEC_PKCS7AddSigningTime(ci);
  2406. if (srv == SECSuccess) {
  2407. srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nsnull, nsnull,
  2408. uiContext);
  2409. }
  2410. }
  2411. SEC_PKCS7DestroyContentInfo(ci);
  2412. }
  2413. if (srv != SECSuccess) {
  2414. aResult.Append(internalError);
  2415. return NS_OK;
  2416. }
  2417. SECItem binary_item;
  2418. binary_item.data = reinterpret_cast<unsigned char*>
  2419. (const_cast<char*>(p7.get()));
  2420. binary_item.len = p7.Length();
  2421. char *result = NSSBase64_EncodeItem(nsnull, nsnull, 0, &binary_item);
  2422. if (result) {
  2423. AppendASCIItoUTF16(result, aResult);
  2424. }
  2425. else {
  2426. aResult.Append(internalError);
  2427. }
  2428. PORT_Free(result);
  2429. return NS_OK;
  2430. }
  2431. //Logout out of all installed PKCS11 tokens.
  2432. NS_IMETHODIMP
  2433. nsCrypto::Logout()
  2434. {
  2435. nsresult rv;
  2436. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2437. if (NS_FAILED(rv))
  2438. return rv;
  2439. {
  2440. nsNSSShutDownPreventionLock locker;
  2441. PK11_LogoutAll();
  2442. SSL_ClearSessionCache();
  2443. }
  2444. return nssComponent->LogoutAuthenticatedPK11();
  2445. }
  2446. NS_IMETHODIMP
  2447. nsCrypto::DisableRightClick()
  2448. {
  2449. return NS_ERROR_NOT_IMPLEMENTED;
  2450. }
  2451. nsCRMFObject::nsCRMFObject()
  2452. {
  2453. }
  2454. nsCRMFObject::~nsCRMFObject()
  2455. {
  2456. }
  2457. nsresult
  2458. nsCRMFObject::init()
  2459. {
  2460. return NS_OK;
  2461. }
  2462. NS_IMETHODIMP
  2463. nsCRMFObject::GetRequest(nsAString& aRequest)
  2464. {
  2465. aRequest.Assign(mBase64Request);
  2466. return NS_OK;
  2467. }
  2468. nsresult
  2469. nsCRMFObject::SetCRMFRequest(char *inRequest)
  2470. {
  2471. mBase64Request.AssignWithConversion(inRequest);
  2472. return NS_OK;
  2473. }
  2474. nsPkcs11::nsPkcs11()
  2475. {
  2476. }
  2477. nsPkcs11::~nsPkcs11()
  2478. {
  2479. }
  2480. //Quick function to confirm with the user.
  2481. bool
  2482. confirm_user(const PRUnichar *message)
  2483. {
  2484. PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
  2485. nsCOMPtr<nsIPrompt> prompter;
  2486. (void) nsNSSComponent::GetNewPrompter(getter_AddRefs(prompter));
  2487. if (prompter) {
  2488. nsPSMUITracker tracker;
  2489. if (!tracker.isUIForbidden()) {
  2490. // The actual value is irrelevant but we shouldn't be handing out
  2491. // malformed JSBools to XPConnect.
  2492. bool checkState = false;
  2493. prompter->ConfirmEx(0, message,
  2494. (nsIPrompt::BUTTON_DELAY_ENABLE) +
  2495. (nsIPrompt::BUTTON_POS_1_DEFAULT) +
  2496. (nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0) +
  2497. (nsIPrompt::BUTTON_TITLE_CANCEL * nsIPrompt::BUTTON_POS_1),
  2498. nsnull, nsnull, nsnull, nsnull, &checkState, &buttonPressed);
  2499. }
  2500. }
  2501. return (buttonPressed == 0);
  2502. }
  2503. //Delete a PKCS11 module from the user's profile.
  2504. NS_IMETHODIMP
  2505. nsPkcs11::DeleteModule(const nsAString& aModuleName)
  2506. {
  2507. nsNSSShutDownPreventionLock locker;
  2508. nsresult rv;
  2509. nsString errorMessage;
  2510. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2511. if (NS_FAILED(rv))
  2512. return rv;
  2513. if (aModuleName.IsEmpty()) {
  2514. return NS_ERROR_ILLEGAL_VALUE;
  2515. }
  2516. char *modName = ToNewCString(aModuleName);
  2517. PRInt32 modType;
  2518. SECStatus srv = SECMOD_DeleteModule(modName, &modType);
  2519. if (srv == SECSuccess) {
  2520. SECMODModule *module = SECMOD_FindModule(modName);
  2521. if (module) {
  2522. nssComponent->ShutdownSmartCardThread(module);
  2523. SECMOD_DestroyModule(module);
  2524. }
  2525. rv = NS_OK;
  2526. } else {
  2527. rv = NS_ERROR_FAILURE;
  2528. }
  2529. NS_Free(modName);
  2530. return rv;
  2531. }
  2532. //Add a new PKCS11 module to the user's profile.
  2533. NS_IMETHODIMP
  2534. nsPkcs11::AddModule(const nsAString& aModuleName,
  2535. const nsAString& aLibraryFullPath,
  2536. PRInt32 aCryptoMechanismFlags,
  2537. PRInt32 aCipherFlags)
  2538. {
  2539. nsNSSShutDownPreventionLock locker;
  2540. nsresult rv;
  2541. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  2542. char *moduleName = ToNewCString(aModuleName);
  2543. char *fullPath = ToNewCString(aLibraryFullPath);
  2544. PRUint32 mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
  2545. PRUint32 cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
  2546. SECStatus srv = SECMOD_AddNewModule(moduleName, fullPath,
  2547. mechFlags, cipherFlags);
  2548. if (srv == SECSuccess) {
  2549. SECMODModule *module = SECMOD_FindModule(moduleName);
  2550. if (module) {
  2551. nssComponent->LaunchSmartCardThread(module);
  2552. SECMOD_DestroyModule(module);
  2553. }
  2554. }
  2555. nsMemory::Free(moduleName);
  2556. nsMemory::Free(fullPath);
  2557. // The error message we report to the user depends directly on
  2558. // what the return value for SEDMOD_AddNewModule is
  2559. switch (srv) {
  2560. case SECSuccess:
  2561. return NS_OK;
  2562. case SECFailure:
  2563. return NS_ERROR_FAILURE;
  2564. case -2:
  2565. return NS_ERROR_ILLEGAL_VALUE;
  2566. }
  2567. NS_ERROR("Bogus return value, this should never happen");
  2568. return NS_ERROR_FAILURE;
  2569. }