PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/security/nss/lib/dev/devtoken.c

http://github.com/zpao/v8monkey
C | 1616 lines | 1376 code | 89 blank | 151 comment | 279 complexity | 04adeedaeac06c307438fecc2eac89db 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. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Netscape Communications Corporation.
  18. * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. #ifdef DEBUG
  37. static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.56 $ $Date: 2011/07/12 21:29:20 $";
  38. #endif /* DEBUG */
  39. #include "pkcs11.h"
  40. #ifndef DEVM_H
  41. #include "devm.h"
  42. #endif /* DEVM_H */
  43. #ifndef CKHELPER_H
  44. #include "ckhelper.h"
  45. #endif /* CKHELPER_H */
  46. #include "pk11func.h"
  47. #include "dev3hack.h"
  48. #include "secerr.h"
  49. extern const NSSError NSS_ERROR_NOT_FOUND;
  50. extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
  51. extern const NSSError NSS_ERROR_PKCS11;
  52. /* The number of object handles to grab during each call to C_FindObjects */
  53. #define OBJECT_STACK_SIZE 16
  54. NSS_IMPLEMENT PRStatus
  55. nssToken_Destroy (
  56. NSSToken *tok
  57. )
  58. {
  59. if (tok) {
  60. if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
  61. PZ_DestroyLock(tok->base.lock);
  62. nssTokenObjectCache_Destroy(tok->cache);
  63. /* The token holds the first/last reference to the slot.
  64. * When the token is actually destroyed, that ref must go too.
  65. */
  66. (void)nssSlot_Destroy(tok->slot);
  67. return nssArena_Destroy(tok->base.arena);
  68. }
  69. }
  70. return PR_SUCCESS;
  71. }
  72. NSS_IMPLEMENT void
  73. nssToken_Remove (
  74. NSSToken *tok
  75. )
  76. {
  77. nssTokenObjectCache_Clear(tok->cache);
  78. }
  79. NSS_IMPLEMENT void
  80. NSSToken_Destroy (
  81. NSSToken *tok
  82. )
  83. {
  84. (void)nssToken_Destroy(tok);
  85. }
  86. NSS_IMPLEMENT NSSToken *
  87. nssToken_AddRef (
  88. NSSToken *tok
  89. )
  90. {
  91. PR_ATOMIC_INCREMENT(&tok->base.refCount);
  92. return tok;
  93. }
  94. NSS_IMPLEMENT NSSSlot *
  95. nssToken_GetSlot (
  96. NSSToken *tok
  97. )
  98. {
  99. return nssSlot_AddRef(tok->slot);
  100. }
  101. NSS_IMPLEMENT void *
  102. nssToken_GetCryptokiEPV (
  103. NSSToken *token
  104. )
  105. {
  106. return nssSlot_GetCryptokiEPV(token->slot);
  107. }
  108. NSS_IMPLEMENT nssSession *
  109. nssToken_GetDefaultSession (
  110. NSSToken *token
  111. )
  112. {
  113. return token->defaultSession;
  114. }
  115. NSS_IMPLEMENT NSSUTF8 *
  116. nssToken_GetName (
  117. NSSToken *tok
  118. )
  119. {
  120. if (tok == NULL) {
  121. return "";
  122. }
  123. if (tok->base.name[0] == 0) {
  124. (void) nssSlot_IsTokenPresent(tok->slot);
  125. }
  126. return tok->base.name;
  127. }
  128. NSS_IMPLEMENT NSSUTF8 *
  129. NSSToken_GetName (
  130. NSSToken *token
  131. )
  132. {
  133. return nssToken_GetName(token);
  134. }
  135. NSS_IMPLEMENT PRBool
  136. nssToken_IsLoginRequired (
  137. NSSToken *token
  138. )
  139. {
  140. return (token->ckFlags & CKF_LOGIN_REQUIRED);
  141. }
  142. NSS_IMPLEMENT PRBool
  143. nssToken_NeedsPINInitialization (
  144. NSSToken *token
  145. )
  146. {
  147. return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
  148. }
  149. NSS_IMPLEMENT PRStatus
  150. nssToken_DeleteStoredObject (
  151. nssCryptokiObject *instance
  152. )
  153. {
  154. CK_RV ckrv;
  155. PRStatus status;
  156. PRBool createdSession = PR_FALSE;
  157. NSSToken *token = instance->token;
  158. nssSession *session = NULL;
  159. void *epv = nssToken_GetCryptokiEPV(instance->token);
  160. if (token->cache) {
  161. nssTokenObjectCache_RemoveObject(token->cache, instance);
  162. }
  163. if (instance->isTokenObject) {
  164. if (token->defaultSession &&
  165. nssSession_IsReadWrite(token->defaultSession)) {
  166. session = token->defaultSession;
  167. } else {
  168. session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
  169. createdSession = PR_TRUE;
  170. }
  171. }
  172. if (session == NULL) {
  173. return PR_FAILURE;
  174. }
  175. nssSession_EnterMonitor(session);
  176. ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
  177. nssSession_ExitMonitor(session);
  178. if (createdSession) {
  179. nssSession_Destroy(session);
  180. }
  181. status = PR_SUCCESS;
  182. if (ckrv != CKR_OK) {
  183. status = PR_FAILURE;
  184. /* use the error stack to pass the PKCS #11 error out */
  185. nss_SetError(ckrv);
  186. nss_SetError(NSS_ERROR_PKCS11);
  187. }
  188. return status;
  189. }
  190. static nssCryptokiObject *
  191. import_object (
  192. NSSToken *tok,
  193. nssSession *sessionOpt,
  194. CK_ATTRIBUTE_PTR objectTemplate,
  195. CK_ULONG otsize
  196. )
  197. {
  198. nssSession *session = NULL;
  199. PRBool createdSession = PR_FALSE;
  200. nssCryptokiObject *object = NULL;
  201. CK_OBJECT_HANDLE handle;
  202. CK_RV ckrv;
  203. void *epv = nssToken_GetCryptokiEPV(tok);
  204. if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
  205. if (sessionOpt) {
  206. if (!nssSession_IsReadWrite(sessionOpt)) {
  207. nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
  208. return NULL;
  209. }
  210. session = sessionOpt;
  211. } else if (tok->defaultSession &&
  212. nssSession_IsReadWrite(tok->defaultSession)) {
  213. session = tok->defaultSession;
  214. } else {
  215. session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
  216. createdSession = PR_TRUE;
  217. }
  218. } else {
  219. session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  220. }
  221. if (session == NULL) {
  222. nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
  223. return NULL;
  224. }
  225. nssSession_EnterMonitor(session);
  226. ckrv = CKAPI(epv)->C_CreateObject(session->handle,
  227. objectTemplate, otsize,
  228. &handle);
  229. nssSession_ExitMonitor(session);
  230. if (ckrv == CKR_OK) {
  231. object = nssCryptokiObject_Create(tok, session, handle);
  232. } else {
  233. nss_SetError(ckrv);
  234. nss_SetError(NSS_ERROR_PKCS11);
  235. }
  236. if (createdSession) {
  237. nssSession_Destroy(session);
  238. }
  239. return object;
  240. }
  241. static nssCryptokiObject **
  242. create_objects_from_handles (
  243. NSSToken *tok,
  244. nssSession *session,
  245. CK_OBJECT_HANDLE *handles,
  246. PRUint32 numH
  247. )
  248. {
  249. nssCryptokiObject **objects;
  250. objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
  251. if (objects) {
  252. PRInt32 i;
  253. for (i=0; i<(PRInt32)numH; i++) {
  254. objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
  255. if (!objects[i]) {
  256. for (--i; i>0; --i) {
  257. nssCryptokiObject_Destroy(objects[i]);
  258. }
  259. nss_ZFreeIf(objects);
  260. objects = NULL;
  261. break;
  262. }
  263. }
  264. }
  265. return objects;
  266. }
  267. static nssCryptokiObject **
  268. find_objects (
  269. NSSToken *tok,
  270. nssSession *sessionOpt,
  271. CK_ATTRIBUTE_PTR obj_template,
  272. CK_ULONG otsize,
  273. PRUint32 maximumOpt,
  274. PRStatus *statusOpt
  275. )
  276. {
  277. CK_RV ckrv = CKR_OK;
  278. CK_ULONG count;
  279. CK_OBJECT_HANDLE *objectHandles = NULL;
  280. CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
  281. PRUint32 arraySize, numHandles;
  282. void *epv = nssToken_GetCryptokiEPV(tok);
  283. nssCryptokiObject **objects;
  284. nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  285. /* Don't ask the module to use an invalid session handle. */
  286. if (!session || session->handle == CK_INVALID_SESSION) {
  287. ckrv = CKR_SESSION_HANDLE_INVALID;
  288. goto loser;
  289. }
  290. /* the arena is only for the array of object handles */
  291. if (maximumOpt > 0) {
  292. arraySize = maximumOpt;
  293. } else {
  294. arraySize = OBJECT_STACK_SIZE;
  295. }
  296. numHandles = 0;
  297. if (arraySize <= OBJECT_STACK_SIZE) {
  298. objectHandles = staticObjects;
  299. } else {
  300. objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
  301. }
  302. if (!objectHandles) {
  303. ckrv = CKR_HOST_MEMORY;
  304. goto loser;
  305. }
  306. nssSession_EnterMonitor(session); /* ==== session lock === */
  307. /* Initialize the find with the template */
  308. ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
  309. obj_template, otsize);
  310. if (ckrv != CKR_OK) {
  311. nssSession_ExitMonitor(session);
  312. goto loser;
  313. }
  314. while (PR_TRUE) {
  315. /* Issue the find for up to arraySize - numHandles objects */
  316. ckrv = CKAPI(epv)->C_FindObjects(session->handle,
  317. objectHandles + numHandles,
  318. arraySize - numHandles,
  319. &count);
  320. if (ckrv != CKR_OK) {
  321. nssSession_ExitMonitor(session);
  322. goto loser;
  323. }
  324. /* bump the number of found objects */
  325. numHandles += count;
  326. if (maximumOpt > 0 || numHandles < arraySize) {
  327. /* When a maximum is provided, the search is done all at once,
  328. * so the search is finished. If the number returned was less
  329. * than the number sought, the search is finished.
  330. */
  331. break;
  332. }
  333. /* the array is filled, double it and continue */
  334. arraySize *= 2;
  335. if (objectHandles == staticObjects) {
  336. objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
  337. if (objectHandles) {
  338. PORT_Memcpy(objectHandles, staticObjects,
  339. OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
  340. }
  341. } else {
  342. objectHandles = nss_ZREALLOCARRAY(objectHandles,
  343. CK_OBJECT_HANDLE,
  344. arraySize);
  345. }
  346. if (!objectHandles) {
  347. nssSession_ExitMonitor(session);
  348. ckrv = CKR_HOST_MEMORY;
  349. goto loser;
  350. }
  351. }
  352. ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
  353. nssSession_ExitMonitor(session); /* ==== end session lock === */
  354. if (ckrv != CKR_OK) {
  355. goto loser;
  356. }
  357. if (numHandles > 0) {
  358. objects = create_objects_from_handles(tok, session,
  359. objectHandles, numHandles);
  360. } else {
  361. nss_SetError(NSS_ERROR_NOT_FOUND);
  362. objects = NULL;
  363. }
  364. if (objectHandles && objectHandles != staticObjects) {
  365. nss_ZFreeIf(objectHandles);
  366. }
  367. if (statusOpt) *statusOpt = PR_SUCCESS;
  368. return objects;
  369. loser:
  370. if (objectHandles && objectHandles != staticObjects) {
  371. nss_ZFreeIf(objectHandles);
  372. }
  373. /*
  374. * These errors should be treated the same as if the objects just weren't
  375. * found..
  376. */
  377. if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
  378. (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
  379. (ckrv == CKR_DATA_INVALID) ||
  380. (ckrv == CKR_DATA_LEN_RANGE) ||
  381. (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
  382. (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
  383. (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
  384. nss_SetError(NSS_ERROR_NOT_FOUND);
  385. if (statusOpt) *statusOpt = PR_SUCCESS;
  386. } else {
  387. nss_SetError(ckrv);
  388. nss_SetError(NSS_ERROR_PKCS11);
  389. if (statusOpt) *statusOpt = PR_FAILURE;
  390. }
  391. return (nssCryptokiObject **)NULL;
  392. }
  393. static nssCryptokiObject **
  394. find_objects_by_template (
  395. NSSToken *token,
  396. nssSession *sessionOpt,
  397. CK_ATTRIBUTE_PTR obj_template,
  398. CK_ULONG otsize,
  399. PRUint32 maximumOpt,
  400. PRStatus *statusOpt
  401. )
  402. {
  403. CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
  404. nssCryptokiObject **objects = NULL;
  405. PRUint32 i;
  406. if (!token) {
  407. PORT_SetError(SEC_ERROR_NO_TOKEN);
  408. if (statusOpt)
  409. *statusOpt = PR_FAILURE;
  410. return NULL;
  411. }
  412. for (i=0; i<otsize; i++) {
  413. if (obj_template[i].type == CKA_CLASS) {
  414. objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
  415. break;
  416. }
  417. }
  418. PR_ASSERT(i < otsize);
  419. if (i == otsize) {
  420. PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  421. if (statusOpt) *statusOpt = PR_FAILURE;
  422. return NULL;
  423. }
  424. /* If these objects are being cached, try looking there first */
  425. if (token->cache &&
  426. nssTokenObjectCache_HaveObjectClass(token->cache, objclass))
  427. {
  428. PRStatus status;
  429. objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
  430. objclass,
  431. obj_template,
  432. otsize,
  433. maximumOpt,
  434. &status);
  435. if (status == PR_SUCCESS) {
  436. if (statusOpt) *statusOpt = status;
  437. return objects;
  438. }
  439. }
  440. /* Either they are not cached, or cache failed; look on token. */
  441. objects = find_objects(token, sessionOpt,
  442. obj_template, otsize,
  443. maximumOpt, statusOpt);
  444. return objects;
  445. }
  446. extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
  447. NSS_IMPLEMENT nssCryptokiObject *
  448. nssToken_ImportCertificate (
  449. NSSToken *tok,
  450. nssSession *sessionOpt,
  451. NSSCertificateType certType,
  452. NSSItem *id,
  453. const NSSUTF8 *nickname,
  454. NSSDER *encoding,
  455. NSSDER *issuer,
  456. NSSDER *subject,
  457. NSSDER *serial,
  458. NSSASCII7 *email,
  459. PRBool asTokenObject
  460. )
  461. {
  462. PRStatus status;
  463. CK_CERTIFICATE_TYPE cert_type;
  464. CK_ATTRIBUTE_PTR attr;
  465. CK_ATTRIBUTE cert_tmpl[10];
  466. CK_ULONG ctsize;
  467. nssTokenSearchType searchType;
  468. nssCryptokiObject *rvObject = NULL;
  469. if (!tok) {
  470. PORT_SetError(SEC_ERROR_NO_TOKEN);
  471. return NULL;
  472. }
  473. if (certType == NSSCertificateType_PKIX) {
  474. cert_type = CKC_X_509;
  475. } else {
  476. return (nssCryptokiObject *)NULL;
  477. }
  478. NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
  479. if (asTokenObject) {
  480. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  481. searchType = nssTokenSearchType_TokenOnly;
  482. } else {
  483. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  484. searchType = nssTokenSearchType_SessionOnly;
  485. }
  486. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  487. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE, cert_type);
  488. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
  489. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
  490. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
  491. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
  492. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  493. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
  494. if (email) {
  495. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
  496. }
  497. NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
  498. /* see if the cert is already there */
  499. rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
  500. sessionOpt,
  501. issuer,
  502. serial,
  503. searchType,
  504. NULL);
  505. if (rvObject) {
  506. NSSItem existingDER;
  507. NSSSlot *slot = nssToken_GetSlot(tok);
  508. nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
  509. if (!session) {
  510. nssCryptokiObject_Destroy(rvObject);
  511. nssSlot_Destroy(slot);
  512. return (nssCryptokiObject *)NULL;
  513. }
  514. /* Reject any attempt to import a new cert that has the same
  515. * issuer/serial as an existing cert, but does not have the
  516. * same encoding
  517. */
  518. NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
  519. NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
  520. NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
  521. status = nssCKObject_GetAttributes(rvObject->handle,
  522. cert_tmpl, ctsize, NULL,
  523. session, slot);
  524. NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
  525. if (status == PR_SUCCESS) {
  526. if (!nssItem_Equal(encoding, &existingDER, NULL)) {
  527. nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
  528. status = PR_FAILURE;
  529. }
  530. nss_ZFreeIf(existingDER.data);
  531. }
  532. if (status == PR_FAILURE) {
  533. nssCryptokiObject_Destroy(rvObject);
  534. nssSession_Destroy(session);
  535. nssSlot_Destroy(slot);
  536. return (nssCryptokiObject *)NULL;
  537. }
  538. /* according to PKCS#11, label, ID, issuer, and serial number
  539. * may change after the object has been created. For PKIX, the
  540. * last two attributes can't change, so for now we'll only worry
  541. * about the first two.
  542. */
  543. NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
  544. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
  545. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
  546. NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
  547. /* reset the mutable attributes on the token */
  548. nssCKObject_SetAttributes(rvObject->handle,
  549. cert_tmpl, ctsize,
  550. session, slot);
  551. if (!rvObject->label && nickname) {
  552. rvObject->label = nssUTF8_Duplicate(nickname, NULL);
  553. }
  554. nssSession_Destroy(session);
  555. nssSlot_Destroy(slot);
  556. } else {
  557. /* Import the certificate onto the token */
  558. rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
  559. }
  560. if (rvObject && tok->cache) {
  561. /* The cache will overwrite the attributes if the object already
  562. * exists.
  563. */
  564. nssTokenObjectCache_ImportObject(tok->cache, rvObject,
  565. CKO_CERTIFICATE,
  566. cert_tmpl, ctsize);
  567. }
  568. return rvObject;
  569. }
  570. /* traverse all objects of the given class - this should only happen
  571. * if the token has been marked as "traversable"
  572. */
  573. NSS_IMPLEMENT nssCryptokiObject **
  574. nssToken_FindObjects (
  575. NSSToken *token,
  576. nssSession *sessionOpt,
  577. CK_OBJECT_CLASS objclass,
  578. nssTokenSearchType searchType,
  579. PRUint32 maximumOpt,
  580. PRStatus *statusOpt
  581. )
  582. {
  583. CK_ATTRIBUTE_PTR attr;
  584. CK_ATTRIBUTE obj_template[2];
  585. CK_ULONG obj_size;
  586. nssCryptokiObject **objects;
  587. NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
  588. /* Set the search to token/session only if provided */
  589. if (searchType == nssTokenSearchType_SessionOnly) {
  590. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  591. } else if (searchType == nssTokenSearchType_TokenOnly ||
  592. searchType == nssTokenSearchType_TokenForced) {
  593. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  594. }
  595. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
  596. NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
  597. if (searchType == nssTokenSearchType_TokenForced) {
  598. objects = find_objects(token, sessionOpt,
  599. obj_template, obj_size,
  600. maximumOpt, statusOpt);
  601. } else {
  602. objects = find_objects_by_template(token, sessionOpt,
  603. obj_template, obj_size,
  604. maximumOpt, statusOpt);
  605. }
  606. return objects;
  607. }
  608. NSS_IMPLEMENT nssCryptokiObject **
  609. nssToken_FindCertificatesBySubject (
  610. NSSToken *token,
  611. nssSession *sessionOpt,
  612. NSSDER *subject,
  613. nssTokenSearchType searchType,
  614. PRUint32 maximumOpt,
  615. PRStatus *statusOpt
  616. )
  617. {
  618. CK_ATTRIBUTE_PTR attr;
  619. CK_ATTRIBUTE subj_template[3];
  620. CK_ULONG stsize;
  621. nssCryptokiObject **objects;
  622. NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
  623. /* Set the search to token/session only if provided */
  624. if (searchType == nssTokenSearchType_SessionOnly) {
  625. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  626. } else if (searchType == nssTokenSearchType_TokenOnly) {
  627. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  628. }
  629. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  630. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  631. NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
  632. /* now locate the token certs matching this template */
  633. objects = find_objects_by_template(token, sessionOpt,
  634. subj_template, stsize,
  635. maximumOpt, statusOpt);
  636. return objects;
  637. }
  638. NSS_IMPLEMENT nssCryptokiObject **
  639. nssToken_FindCertificatesByNickname (
  640. NSSToken *token,
  641. nssSession *sessionOpt,
  642. const NSSUTF8 *name,
  643. nssTokenSearchType searchType,
  644. PRUint32 maximumOpt,
  645. PRStatus *statusOpt
  646. )
  647. {
  648. CK_ATTRIBUTE_PTR attr;
  649. CK_ATTRIBUTE nick_template[3];
  650. CK_ULONG ntsize;
  651. nssCryptokiObject **objects;
  652. NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
  653. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
  654. /* Set the search to token/session only if provided */
  655. if (searchType == nssTokenSearchType_SessionOnly) {
  656. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  657. } else if (searchType == nssTokenSearchType_TokenOnly) {
  658. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  659. }
  660. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  661. NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
  662. /* now locate the token certs matching this template */
  663. objects = find_objects_by_template(token, sessionOpt,
  664. nick_template, ntsize,
  665. maximumOpt, statusOpt);
  666. if (!objects) {
  667. /* This is to workaround the fact that PKCS#11 doesn't specify
  668. * whether the '\0' should be included. XXX Is that still true?
  669. * im - this is not needed by the current softoken. However, I'm
  670. * leaving it in until I have surveyed more tokens to see if it needed.
  671. * well, its needed by the builtin token...
  672. */
  673. nick_template[0].ulValueLen++;
  674. objects = find_objects_by_template(token, sessionOpt,
  675. nick_template, ntsize,
  676. maximumOpt, statusOpt);
  677. }
  678. return objects;
  679. }
  680. /* XXX
  681. * This function *does not* use the token object cache, because not even
  682. * the softoken will return a value for CKA_NSS_EMAIL from a call
  683. * to GetAttributes. The softoken does allow searches with that attribute,
  684. * it just won't return a value for it.
  685. */
  686. NSS_IMPLEMENT nssCryptokiObject **
  687. nssToken_FindCertificatesByEmail (
  688. NSSToken *token,
  689. nssSession *sessionOpt,
  690. NSSASCII7 *email,
  691. nssTokenSearchType searchType,
  692. PRUint32 maximumOpt,
  693. PRStatus *statusOpt
  694. )
  695. {
  696. CK_ATTRIBUTE_PTR attr;
  697. CK_ATTRIBUTE email_template[3];
  698. CK_ULONG etsize;
  699. nssCryptokiObject **objects;
  700. NSS_CK_TEMPLATE_START(email_template, attr, etsize);
  701. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
  702. /* Set the search to token/session only if provided */
  703. if (searchType == nssTokenSearchType_SessionOnly) {
  704. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  705. } else if (searchType == nssTokenSearchType_TokenOnly) {
  706. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  707. }
  708. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  709. NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
  710. /* now locate the token certs matching this template */
  711. objects = find_objects(token, sessionOpt,
  712. email_template, etsize,
  713. maximumOpt, statusOpt);
  714. if (!objects) {
  715. /* This is to workaround the fact that PKCS#11 doesn't specify
  716. * whether the '\0' should be included. XXX Is that still true?
  717. * im - this is not needed by the current softoken. However, I'm
  718. * leaving it in until I have surveyed more tokens to see if it needed.
  719. * well, its needed by the builtin token...
  720. */
  721. email_template[0].ulValueLen++;
  722. objects = find_objects(token, sessionOpt,
  723. email_template, etsize,
  724. maximumOpt, statusOpt);
  725. }
  726. return objects;
  727. }
  728. NSS_IMPLEMENT nssCryptokiObject **
  729. nssToken_FindCertificatesByID (
  730. NSSToken *token,
  731. nssSession *sessionOpt,
  732. NSSItem *id,
  733. nssTokenSearchType searchType,
  734. PRUint32 maximumOpt,
  735. PRStatus *statusOpt
  736. )
  737. {
  738. CK_ATTRIBUTE_PTR attr;
  739. CK_ATTRIBUTE id_template[3];
  740. CK_ULONG idtsize;
  741. nssCryptokiObject **objects;
  742. NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
  743. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
  744. /* Set the search to token/session only if provided */
  745. if (searchType == nssTokenSearchType_SessionOnly) {
  746. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  747. } else if (searchType == nssTokenSearchType_TokenOnly) {
  748. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  749. }
  750. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  751. NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
  752. /* now locate the token certs matching this template */
  753. objects = find_objects_by_template(token, sessionOpt,
  754. id_template, idtsize,
  755. maximumOpt, statusOpt);
  756. return objects;
  757. }
  758. /*
  759. * decode the serial item and return our result.
  760. * NOTE serialDecode's data is really stored in serial. Don't free it.
  761. */
  762. static PRStatus
  763. nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
  764. {
  765. unsigned char *data = (unsigned char *)serial->data;
  766. int data_left, data_len, index;
  767. if ((serial->size >= 3) && (data[0] == 0x2)) {
  768. /* remove the der encoding of the serial number before generating the
  769. * key.. */
  770. data_left = serial->size-2;
  771. data_len = data[1];
  772. index = 2;
  773. /* extended length ? (not very likely for a serial number) */
  774. if (data_len & 0x80) {
  775. int len_count = data_len & 0x7f;
  776. data_len = 0;
  777. data_left -= len_count;
  778. if (data_left > 0) {
  779. while (len_count --) {
  780. data_len = (data_len << 8) | data[index++];
  781. }
  782. }
  783. }
  784. /* XXX leaving any leading zeros on the serial number for backwards
  785. * compatibility
  786. */
  787. /* not a valid der, must be just an unlucky serial number value */
  788. if (data_len == data_left) {
  789. serialDecode->size = data_len;
  790. serialDecode->data = &data[index];
  791. return PR_SUCCESS;
  792. }
  793. }
  794. return PR_FAILURE;
  795. }
  796. NSS_IMPLEMENT nssCryptokiObject *
  797. nssToken_FindCertificateByIssuerAndSerialNumber (
  798. NSSToken *token,
  799. nssSession *sessionOpt,
  800. NSSDER *issuer,
  801. NSSDER *serial,
  802. nssTokenSearchType searchType,
  803. PRStatus *statusOpt
  804. )
  805. {
  806. CK_ATTRIBUTE_PTR attr;
  807. CK_ATTRIBUTE_PTR serialAttr;
  808. CK_ATTRIBUTE cert_template[4];
  809. CK_ULONG ctsize;
  810. nssCryptokiObject **objects;
  811. nssCryptokiObject *rvObject = NULL;
  812. NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
  813. if (!token) {
  814. PORT_SetError(SEC_ERROR_NO_TOKEN);
  815. if (statusOpt)
  816. *statusOpt = PR_FAILURE;
  817. return NULL;
  818. }
  819. /* Set the search to token/session only if provided */
  820. if (searchType == nssTokenSearchType_SessionOnly) {
  821. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  822. } else if ((searchType == nssTokenSearchType_TokenOnly) ||
  823. (searchType == nssTokenSearchType_TokenForced)) {
  824. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  825. }
  826. /* Set the unique id */
  827. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  828. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
  829. serialAttr = attr;
  830. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
  831. NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
  832. /* get the object handle */
  833. if (searchType == nssTokenSearchType_TokenForced) {
  834. objects = find_objects(token, sessionOpt,
  835. cert_template, ctsize,
  836. 1, statusOpt);
  837. } else {
  838. objects = find_objects_by_template(token, sessionOpt,
  839. cert_template, ctsize,
  840. 1, statusOpt);
  841. }
  842. if (objects) {
  843. rvObject = objects[0];
  844. nss_ZFreeIf(objects);
  845. }
  846. /*
  847. * NSS used to incorrectly store serial numbers in their decoded form.
  848. * because of this old tokens have decoded serial numbers.
  849. */
  850. if (!objects) {
  851. NSSItem serialDecode;
  852. PRStatus status;
  853. status = nssToken_decodeSerialItem(serial, &serialDecode);
  854. if (status != PR_SUCCESS) {
  855. return NULL;
  856. }
  857. NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
  858. if (searchType == nssTokenSearchType_TokenForced) {
  859. objects = find_objects(token, sessionOpt,
  860. cert_template, ctsize,
  861. 1, statusOpt);
  862. } else {
  863. objects = find_objects_by_template(token, sessionOpt,
  864. cert_template, ctsize,
  865. 1, statusOpt);
  866. }
  867. if (objects) {
  868. rvObject = objects[0];
  869. nss_ZFreeIf(objects);
  870. }
  871. }
  872. return rvObject;
  873. }
  874. NSS_IMPLEMENT nssCryptokiObject *
  875. nssToken_FindCertificateByEncodedCertificate (
  876. NSSToken *token,
  877. nssSession *sessionOpt,
  878. NSSBER *encodedCertificate,
  879. nssTokenSearchType searchType,
  880. PRStatus *statusOpt
  881. )
  882. {
  883. CK_ATTRIBUTE_PTR attr;
  884. CK_ATTRIBUTE cert_template[3];
  885. CK_ULONG ctsize;
  886. nssCryptokiObject **objects;
  887. nssCryptokiObject *rvObject = NULL;
  888. NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
  889. /* Set the search to token/session only if provided */
  890. if (searchType == nssTokenSearchType_SessionOnly) {
  891. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  892. } else if (searchType == nssTokenSearchType_TokenOnly) {
  893. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  894. }
  895. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  896. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
  897. NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
  898. /* get the object handle */
  899. objects = find_objects_by_template(token, sessionOpt,
  900. cert_template, ctsize,
  901. 1, statusOpt);
  902. if (objects) {
  903. rvObject = objects[0];
  904. nss_ZFreeIf(objects);
  905. }
  906. return rvObject;
  907. }
  908. NSS_IMPLEMENT nssCryptokiObject **
  909. nssToken_FindPrivateKeys (
  910. NSSToken *token,
  911. nssSession *sessionOpt,
  912. nssTokenSearchType searchType,
  913. PRUint32 maximumOpt,
  914. PRStatus *statusOpt
  915. )
  916. {
  917. CK_ATTRIBUTE_PTR attr;
  918. CK_ATTRIBUTE key_template[2];
  919. CK_ULONG ktsize;
  920. nssCryptokiObject **objects;
  921. NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
  922. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
  923. if (searchType == nssTokenSearchType_SessionOnly) {
  924. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  925. } else if (searchType == nssTokenSearchType_TokenOnly) {
  926. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  927. }
  928. NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
  929. objects = find_objects_by_template(token, sessionOpt,
  930. key_template, ktsize,
  931. maximumOpt, statusOpt);
  932. return objects;
  933. }
  934. /* XXX ?there are no session cert objects, so only search token objects */
  935. NSS_IMPLEMENT nssCryptokiObject *
  936. nssToken_FindPrivateKeyByID (
  937. NSSToken *token,
  938. nssSession *sessionOpt,
  939. NSSItem *keyID
  940. )
  941. {
  942. CK_ATTRIBUTE_PTR attr;
  943. CK_ATTRIBUTE key_template[3];
  944. CK_ULONG ktsize;
  945. nssCryptokiObject **objects;
  946. nssCryptokiObject *rvKey = NULL;
  947. NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
  948. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
  949. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  950. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
  951. NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
  952. objects = find_objects_by_template(token, sessionOpt,
  953. key_template, ktsize,
  954. 1, NULL);
  955. if (objects) {
  956. rvKey = objects[0];
  957. nss_ZFreeIf(objects);
  958. }
  959. return rvKey;
  960. }
  961. /* XXX ?there are no session cert objects, so only search token objects */
  962. NSS_IMPLEMENT nssCryptokiObject *
  963. nssToken_FindPublicKeyByID (
  964. NSSToken *token,
  965. nssSession *sessionOpt,
  966. NSSItem *keyID
  967. )
  968. {
  969. CK_ATTRIBUTE_PTR attr;
  970. CK_ATTRIBUTE key_template[3];
  971. CK_ULONG ktsize;
  972. nssCryptokiObject **objects;
  973. nssCryptokiObject *rvKey = NULL;
  974. NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
  975. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
  976. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  977. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
  978. NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
  979. objects = find_objects_by_template(token, sessionOpt,
  980. key_template, ktsize,
  981. 1, NULL);
  982. if (objects) {
  983. rvKey = objects[0];
  984. nss_ZFreeIf(objects);
  985. }
  986. return rvKey;
  987. }
  988. static void
  989. sha1_hash(NSSItem *input, NSSItem *output)
  990. {
  991. NSSAlgorithmAndParameters *ap;
  992. PK11SlotInfo *internal = PK11_GetInternalSlot();
  993. NSSToken *token = PK11Slot_GetNSSToken(internal);
  994. ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
  995. (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  996. PK11_FreeSlot(token->pk11slot);
  997. nss_ZFreeIf(ap);
  998. }
  999. static void
  1000. md5_hash(NSSItem *input, NSSItem *output)
  1001. {
  1002. NSSAlgorithmAndParameters *ap;
  1003. PK11SlotInfo *internal = PK11_GetInternalSlot();
  1004. NSSToken *token = PK11Slot_GetNSSToken(internal);
  1005. ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
  1006. (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  1007. PK11_FreeSlot(token->pk11slot);
  1008. nss_ZFreeIf(ap);
  1009. }
  1010. static CK_TRUST
  1011. get_ck_trust (
  1012. nssTrustLevel nssTrust
  1013. )
  1014. {
  1015. CK_TRUST t;
  1016. switch (nssTrust) {
  1017. case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
  1018. case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR;
  1019. break;
  1020. case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
  1021. case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
  1022. case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
  1023. case nssTrustLevel_Unknown:
  1024. default: t = CKT_NSS_TRUST_UNKNOWN; break;
  1025. }
  1026. return t;
  1027. }
  1028. NSS_IMPLEMENT nssCryptokiObject *
  1029. nssToken_ImportTrust (
  1030. NSSToken *tok,
  1031. nssSession *sessionOpt,
  1032. NSSDER *certEncoding,
  1033. NSSDER *certIssuer,
  1034. NSSDER *certSerial,
  1035. nssTrustLevel serverAuth,
  1036. nssTrustLevel clientAuth,
  1037. nssTrustLevel codeSigning,
  1038. nssTrustLevel emailProtection,
  1039. PRBool stepUpApproved,
  1040. PRBool asTokenObject
  1041. )
  1042. {
  1043. nssCryptokiObject *object;
  1044. CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1045. CK_TRUST ckSA, ckCA, ckCS, ckEP;
  1046. CK_ATTRIBUTE_PTR attr;
  1047. CK_ATTRIBUTE trust_tmpl[11];
  1048. CK_ULONG tsize;
  1049. PRUint8 sha1[20]; /* this is cheating... */
  1050. PRUint8 md5[16];
  1051. NSSItem sha1_result, md5_result;
  1052. sha1_result.data = sha1; sha1_result.size = sizeof sha1;
  1053. md5_result.data = md5; md5_result.size = sizeof md5;
  1054. sha1_hash(certEncoding, &sha1_result);
  1055. md5_hash(certEncoding, &md5_result);
  1056. ckSA = get_ck_trust(serverAuth);
  1057. ckCA = get_ck_trust(clientAuth);
  1058. ckCS = get_ck_trust(codeSigning);
  1059. ckEP = get_ck_trust(emailProtection);
  1060. NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
  1061. if (asTokenObject) {
  1062. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1063. } else {
  1064. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1065. }
  1066. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
  1067. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
  1068. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
  1069. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
  1070. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH, &md5_result);
  1071. /* now set the trust values */
  1072. NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, ckSA);
  1073. NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, ckCA);
  1074. NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, ckCS);
  1075. NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
  1076. if (stepUpApproved) {
  1077. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
  1078. &g_ck_true);
  1079. } else {
  1080. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
  1081. &g_ck_false);
  1082. }
  1083. NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
  1084. /* import the trust object onto the token */
  1085. object = import_object(tok, sessionOpt, trust_tmpl, tsize);
  1086. if (object && tok->cache) {
  1087. nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
  1088. trust_tmpl, tsize);
  1089. }
  1090. return object;
  1091. }
  1092. NSS_IMPLEMENT nssCryptokiObject *
  1093. nssToken_FindTrustForCertificate (
  1094. NSSToken *token,
  1095. nssSession *sessionOpt,
  1096. NSSDER *certEncoding,
  1097. NSSDER *certIssuer,
  1098. NSSDER *certSerial,
  1099. nssTokenSearchType searchType
  1100. )
  1101. {
  1102. CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1103. CK_ATTRIBUTE_PTR attr;
  1104. CK_ATTRIBUTE tobj_template[5];
  1105. CK_ULONG tobj_size;
  1106. nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1107. nssCryptokiObject *object = NULL, **objects;
  1108. /* Don't ask the module to use an invalid session handle. */
  1109. if (!session || session->handle == CK_INVALID_SESSION) {
  1110. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1111. return object;
  1112. }
  1113. NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
  1114. if (searchType == nssTokenSearchType_TokenOnly) {
  1115. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1116. }
  1117. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
  1118. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
  1119. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
  1120. NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
  1121. objects = find_objects_by_template(token, session,
  1122. tobj_template, tobj_size,
  1123. 1, NULL);
  1124. if (objects) {
  1125. object = objects[0];
  1126. nss_ZFreeIf(objects);
  1127. }
  1128. return object;
  1129. }
  1130. NSS_IMPLEMENT nssCryptokiObject *
  1131. nssToken_ImportCRL (
  1132. NSSToken *token,
  1133. nssSession *sessionOpt,
  1134. NSSDER *subject,
  1135. NSSDER *encoding,
  1136. PRBool isKRL,
  1137. NSSUTF8 *url,
  1138. PRBool asTokenObject
  1139. )
  1140. {
  1141. nssCryptokiObject *object;
  1142. CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1143. CK_ATTRIBUTE_PTR attr;
  1144. CK_ATTRIBUTE crl_tmpl[6];
  1145. CK_ULONG crlsize;
  1146. NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
  1147. if (asTokenObject) {
  1148. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1149. } else {
  1150. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1151. }
  1152. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
  1153. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  1154. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
  1155. NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
  1156. if (isKRL) {
  1157. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
  1158. } else {
  1159. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
  1160. }
  1161. NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
  1162. /* import the crl object onto the token */
  1163. object = import_object(token, sessionOpt, crl_tmpl, crlsize);
  1164. if (object && token->cache) {
  1165. nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
  1166. crl_tmpl, crlsize);
  1167. }
  1168. return object;
  1169. }
  1170. NSS_IMPLEMENT nssCryptokiObject **
  1171. nssToken_FindCRLsBySubject (
  1172. NSSToken *token,
  1173. nssSession *sessionOpt,
  1174. NSSDER *subject,
  1175. nssTokenSearchType searchType,
  1176. PRUint32 maximumOpt,
  1177. PRStatus *statusOpt
  1178. )
  1179. {
  1180. CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1181. CK_ATTRIBUTE_PTR attr;
  1182. CK_ATTRIBUTE crlobj_template[3];
  1183. CK_ULONG crlobj_size;
  1184. nssCryptokiObject **objects = NULL;
  1185. nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1186. /* Don't ask the module to use an invalid session handle. */
  1187. if (!session || session->handle == CK_INVALID_SESSION) {
  1188. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1189. return objects;
  1190. }
  1191. NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
  1192. if (searchType == nssTokenSearchType_SessionOnly) {
  1193. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1194. } else if (searchType == nssTokenSearchType_TokenOnly ||
  1195. searchType == nssTokenSearchType_TokenForced) {
  1196. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1197. }
  1198. NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
  1199. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  1200. NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
  1201. objects = find_objects_by_template(token, session,
  1202. crlobj_template, crlobj_size,
  1203. maximumOpt, statusOpt);
  1204. return objects;
  1205. }
  1206. NSS_IMPLEMENT PRStatus
  1207. nssToken_GetCachedObjectAttributes (
  1208. NSSToken *token,
  1209. NSSArena *arenaOpt,
  1210. nssCryptokiObject *object,
  1211. CK_OBJECT_CLASS objclass,
  1212. CK_ATTRIBUTE_PTR atemplate,
  1213. CK_ULONG atlen
  1214. )
  1215. {
  1216. if (!token->cache) {
  1217. return PR_FAILURE;
  1218. }
  1219. return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
  1220. object, objclass,
  1221. atemplate, atlen);
  1222. }
  1223. NSS_IMPLEMENT NSSItem *
  1224. nssToken_Digest (
  1225. NSSToken *tok,
  1226. nssSession *sessionOpt,
  1227. NSSAlgorithmAndParameters *ap,
  1228. NSSItem *data,
  1229. NSSItem *rvOpt,
  1230. NSSArena *arenaOpt
  1231. )
  1232. {
  1233. CK_RV ckrv;
  1234. CK_ULONG digestLen;
  1235. CK_BYTE_PTR digest;
  1236. NSSItem *rvItem = NULL;
  1237. void *epv = nssToken_GetCryptokiEPV(tok);
  1238. nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1239. /* Don't ask the module to use an invalid session handle. */
  1240. if (!session || session->handle == CK_INVALID_SESSION) {
  1241. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1242. return rvItem;
  1243. }
  1244. nssSession_EnterMonitor(session);
  1245. ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1246. if (ckrv != CKR_OK) {
  1247. nssSession_ExitMonitor(session);
  1248. return NULL;
  1249. }
  1250. #if 0
  1251. /* XXX the standard says this should work, but it doesn't */
  1252. ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
  1253. if (ckrv != CKR_OK) {
  1254. nssSession_ExitMonitor(session);
  1255. return NULL;
  1256. }
  1257. #endif
  1258. digestLen = 0; /* XXX for now */
  1259. digest = NULL;
  1260. if (rvOpt) {
  1261. if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1262. nssSession_ExitMonitor(session);
  1263. /* the error should be bad args */
  1264. return NULL;
  1265. }
  1266. if (rvOpt->data) {
  1267. digest = rvOpt->data;
  1268. }
  1269. digestLen = rvOpt->size;
  1270. }
  1271. if (!digest) {
  1272. digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1273. if (!digest) {
  1274. nssSession_ExitMonitor(session);
  1275. return NULL;
  1276. }
  1277. }
  1278. ckrv = CKAPI(epv)->C_Digest(session->handle,
  1279. (CK_BYTE_PTR)data->data,
  1280. (CK_ULONG)data->size,
  1281. (CK_BYTE_PTR)digest,
  1282. &digestLen);
  1283. nssSession_ExitMonitor(session);
  1284. if (ckrv != CKR_OK) {
  1285. nss_ZFreeIf(digest);
  1286. return NULL;
  1287. }
  1288. if (!rvOpt) {
  1289. rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1290. }
  1291. return rvItem;
  1292. }
  1293. NSS_IMPLEMENT PRStatus
  1294. nssToken_BeginDigest (
  1295. NSSToken *tok,
  1296. nssSession *sessionOpt,
  1297. NSSAlgorithmAndParameters *ap
  1298. )
  1299. {
  1300. CK_RV ckrv;
  1301. void *epv = nssToken_GetCryptokiEPV(tok);
  1302. nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1303. /* Don't ask the module to use an invalid session handle. */
  1304. if (!session || session->handle == CK_INVALID_SESSION) {
  1305. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1306. return PR_FAILURE;
  1307. }
  1308. nssSession_EnterMonitor(session);
  1309. ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1310. nssSession_ExitMonitor(session);
  1311. return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1312. }
  1313. NSS_IMPLEMENT PRStatus
  1314. nssToken_ContinueDigest (
  1315. NSSToken *tok,
  1316. nssSession *sessionOpt,
  1317. NSSItem *item
  1318. )
  1319. {
  1320. CK_RV ckrv;
  1321. void *epv = nssToken_GetCryptokiEPV(tok);
  1322. nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1323. /* Don't ask the module to use an invalid session handle. */
  1324. if (!session || session->handle == CK_INVALID_SESSION) {
  1325. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1326. return PR_FAILURE;
  1327. }
  1328. nssSession_EnterMonitor(session);
  1329. ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
  1330. (CK_BYTE_PTR)item->data,
  1331. (CK_ULONG)item->size);
  1332. nssSession_ExitMonitor(session);
  1333. return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1334. }
  1335. NSS_IMPLEMENT NSSItem *
  1336. nssToken_FinishDigest (
  1337. NSSToken *tok,
  1338. nssSession *sessionOpt,
  1339. NSSItem *rvOpt,
  1340. NSSArena *arenaOpt
  1341. )
  1342. {
  1343. CK_RV ckrv;
  1344. CK_ULONG digestLen;
  1345. CK_BYTE_PTR digest;
  1346. NSSItem *rvItem = NULL;
  1347. void *epv = nssToken_GetCryptokiEPV(tok);
  1348. nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1349. /* Don't ask the module to use an invalid session handle. */
  1350. if (!session || session->handle == CK_INVALID_SESSION) {
  1351. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1352. return NULL;
  1353. }
  1354. nssSession_EnterMonitor(session);
  1355. ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
  1356. if (ckrv != CKR_OK || digestLen == 0) {
  1357. nssSession_ExitMonitor(session);
  1358. return NULL;
  1359. }
  1360. digest = NULL;
  1361. if (rvOpt) {
  1362. if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1363. nssSession_ExitMonitor(session);
  1364. /* the error should be bad args */
  1365. return NULL;
  1366. }
  1367. if (rvOpt->data) {
  1368. digest = rvOpt->data;
  1369. }
  1370. digestLen = rvOpt->size;
  1371. }
  1372. if (!digest) {
  1373. digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1374. if (!digest) {
  1375. nssSession_ExitMonitor(session);
  1376. return NULL;
  1377. }
  1378. }
  1379. ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
  1380. nssSession_ExitMonitor(session);
  1381. if (ckrv != CKR_OK) {
  1382. nss_ZFreeIf(digest);
  1383. return NULL;
  1384. }
  1385. if (!rvOpt) {
  1386. rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1387. }
  1388. return rvItem;
  1389. }
  1390. NSS_IMPLEMENT PRBool
  1391. nssToken_IsPresent (
  1392. NSSToken *token
  1393. )
  1394. {
  1395. return nssSlot_IsTokenPresent(token->slot);
  1396. }
  1397. /* Sigh. The methods to find objects declared above cause problems with
  1398. * the low-level object cache in the softoken -- the objects are found in
  1399. * toto, then one wave of GetAttributes is done, then another. Having a
  1400. * large number of objects causes the cache to be thrashed, as the objects
  1401. * are gone before there's any chance to ask for their attributes.
  1402. * So, for now, bringing back traversal methods for certs. This way all of
  1403. * the cert's attributes can be grabbed immediately after finding it,
  1404. * increasing the likelihood that the cache takes care of it.
  1405. */
  1406. NSS_IMPLEMENT PRStatus
  1407. nssToken_TraverseCertificates (
  1408. NSSToken *token,
  1409. nssSession *sessionOpt,
  1410. nssTokenSearchType searchType,
  1411. PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
  1412. void *arg
  1413. )
  1414. {
  1415. CK_RV ckrv;
  1416. CK_ULONG count;
  1417. CK_OBJECT_HANDLE *objectHandles;
  1418. CK_ATTRIBUTE_PTR attr;
  1419. CK_ATTRIBUTE cert_template[2];
  1420. CK_ULONG ctsize;
  1421. NSSArena *arena;
  1422. PRStatus status;
  1423. PRUint32 arraySize, numHandles;
  1424. nssCryptokiObject **objects;
  1425. void *epv = nssToken_GetCryptokiEPV(token);
  1426. nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
  1427. /* Don't ask the module to use an invalid session handle. */
  1428. if (!session || session->handle == CK_INVALID_SESSION) {
  1429. PORT_SetError(SEC_ERROR_NO_TOKEN);
  1430. return PR_FAILURE;
  1431. }
  1432. /* template for all certs */
  1433. NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
  1434. if (searchType == nssTokenSearchType_SessionOnly) {
  1435. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1436. } else if (searchType == nssTokenSearchType_TokenOnly ||
  1437. searchType == nssTokenSearchType_TokenForced) {
  1438. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1439. }
  1440. NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  1441. NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
  1442. /* the arena is only for the array of object handles */
  1443. arena = nssArena_Create();
  1444. if (!arena) {
  1445. return PR_FAILURE;
  1446. }
  1447. arraySize = OBJECT_STACK_SIZE;
  1448. numHandles = 0;
  1449. objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
  1450. if (!objectHandles) {
  1451. goto loser;
  1452. }
  1453. nssSession_EnterMonitor(session); /* ==== session lock === */
  1454. /* Initialize the find with the template */
  1455. ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
  1456. cert_template, ctsize);
  1457. if (ckrv != CKR_OK) {
  1458. nssSession_ExitMonitor(session);
  1459. goto loser;
  1460. }
  1461. while (PR_TRUE) {
  1462. /* Issue the find for up to arraySize - numHandles objects */
  1463. ckrv = CKAPI(epv)->C_FindObjects(session->handle,
  1464. objectHandles + numHandles,
  1465. arraySize - numHandles,
  1466. &count);
  1467. if (ckrv != CKR_OK) {
  1468. nssSession_ExitMonitor(session);
  1469. goto loser;
  1470. }
  1471. /* bump the number of found objects */
  1472. numHandles += count;
  1473. if (numHandles < arraySize) {
  1474. break;
  1475. }
  1476. /* the array is filled, double it and continue */
  1477. arraySize *= 2;
  1478. objectHandles = nss_ZREALLOCARRAY(objectHandles,
  1479. CK_OBJECT_HANDLE,
  1480. arraySize);
  1481. if (!objectHandles) {
  1482. nssSession_ExitMonitor(session);
  1483. goto loser;
  1484. }
  1485. }
  1486. ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
  1487. nssSession_ExitMonitor(session); /* ==== end session lock === */
  1488. if (ckrv != CKR_OK) {
  1489. goto loser;
  1490. }
  1491. if (numHandles > 0) {
  1492. objects = create_objects_from_handles(token, session,
  1493. objectHandles, numHandles);
  1494. if (objects) {
  1495. nssCryptokiObject **op;
  1496. for (op = objects; *op; op++) {
  1497. status = (*callback)(*op, arg);
  1498. }
  1499. nss_ZFreeIf(objects);
  1500. }
  1501. }
  1502. nssArena_Destroy(arena);
  1503. return PR_SUCCESS;
  1504. loser:
  1505. nssArena_Destroy(arena);
  1506. return PR_FAILURE;
  1507. }
  1508. NSS_IMPLEMENT PRBool
  1509. nssToken_IsPrivateKeyAvailable (
  1510. NSSToken *token,
  1511. NSSCertificate *c,
  1512. nssCryptokiObject *instance
  1513. )
  1514. {
  1515. CK_OBJECT_CLASS theClass;
  1516. if (token == NULL) return PR_FALSE;
  1517. if (c == NULL) return PR_FALSE;
  1518. theClass = CKO_PRIVATE_KEY;
  1519. if (!nssSlot_IsLoggedIn(token->slot)) {
  1520. theClass = CKO_PUBLIC_KEY;
  1521. }
  1522. if (PK11_MatchItem(token->pk11slot, instance->handle, theClass)
  1523. != CK_INVALID_HANDLE) {
  1524. return PR_TRUE;
  1525. }
  1526. return PR_FALSE;
  1527. }