slots.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. /* slots.c - Slot management.
  2. Copyright (C) 2006 g10 Code GmbH
  3. This file is part of Scute[1].
  4. [1] Derived from the RSA Security Inc. PKCS #11 Cryptographic Token
  5. Interface (Cryptoki).
  6. Scute is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. Scute is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Scute; if not, write to the Free Software Foundation,
  16. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. In addition, as a special exception, g10 Code GmbH gives permission
  18. to link this library: with the Mozilla Foundation's code for
  19. Mozilla (or with modified versions of it that use the same license
  20. as the "Mozilla" code), and distribute the linked executables. You
  21. must obey the GNU General Public License in all respects for all of
  22. the code used other than "Mozilla". If you modify this file, you
  23. may extend this exception to your version of the file, but you are
  24. not obligated to do so. If you do not wish to do so, delete this
  25. exception statement from your version. */
  26. #if HAVE_CONFIG_H
  27. #include <config.h>
  28. #endif
  29. #include <assert.h>
  30. #include <stdbool.h>
  31. #include <string.h>
  32. #include "cryptoki.h"
  33. #include "table.h"
  34. #include "error-mapping.h"
  35. #include "slots.h"
  36. #include "agent.h"
  37. #include "support.h"
  38. #include "debug.h"
  39. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  40. /* A session is just a slot identifier with a per-slot session
  41. identifier. */
  42. /* Must be power of two. */
  43. #define SLOT_MAX (1 << 15)
  44. #define SESSION_SLOT_MASK (SLOT_MAX - 1)
  45. #define SESSION_SLOT_SHIFT 16
  46. #define SESSION_MAX (1 << SESSION_SLOT_SHIFT)
  47. #define SESSION_ID_MASK (SESSION_MAX - 1)
  48. /* Get slot ID from session. */
  49. #define SESSION_SLOT(session) \
  50. ((session >> SESSION_SLOT_SHIFT) & SESSION_SLOT_MASK)
  51. /* Get session ID from session. */
  52. #define SESSION_ID(session) (session & SESSION_ID_MASK)
  53. /* Because the slot is already 1-based, we can make the session 0-based. */
  54. #define SESSION_BUILD_ID(slot, session) \
  55. (((slot & SESSION_SLOT_MASK) << SESSION_SLOT_SHIFT) \
  56. | (session & SESSION_ID_MASK))
  57. /* We use one-based IDs. */
  58. #define OBJECT_ID_TO_IDX(id) (id - 1)
  59. #define OBJECT_IDX_TO_ID(idx) (idx + 1)
  60. struct object
  61. {
  62. /* Every table entry must start with a void pointer, but we don't
  63. use it here. */
  64. void *dummy;
  65. CK_ATTRIBUTE_PTR attributes;
  66. CK_ULONG attributes_count;
  67. };
  68. /* The dummy pointer we use for table entries. */
  69. #define DUMMY_PTR ((void *) 0xdeadbeef)
  70. /* A mechanism. */
  71. struct mechanism
  72. {
  73. /* Every table entry must start with a void pointer, but we don't
  74. use it here. */
  75. void *dummy;
  76. CK_MECHANISM_TYPE type;
  77. CK_MECHANISM_INFO info;
  78. };
  79. /* We use one-based IDs. */
  80. #define MECHANISM_ID_TO_IDX(id) (id - 1)
  81. #define MECHANISM_IDX_TO_ID(idx) (idx + 1)
  82. /* The session state. */
  83. struct session
  84. {
  85. /* Every table entry must start with a void pointer, but we don't
  86. use it here. */
  87. void *dummy;
  88. /* True iff read-write session. */
  89. bool rw;
  90. /* The list of objects for the current search. */
  91. object_iterator_t *search_result;
  92. /* The length of the list of objects for the current search. */
  93. int search_result_len;
  94. /* The signing key. */
  95. CK_OBJECT_HANDLE signing_key;
  96. };
  97. /* The slot status. */
  98. typedef enum
  99. {
  100. SLOT_STATUS_USED = 0,
  101. SLOT_STATUS_DEAD = 1
  102. } slot_status_t;
  103. struct slot
  104. {
  105. /* Every table entry must start with a void pointer, but we don't
  106. use it here. */
  107. void *dummy;
  108. /* The slot status. Starts out as 0 (pristine). */
  109. slot_status_t status;
  110. /* The slot login status. Starts out as 0 (public). */
  111. slot_login_t login;
  112. /* True iff a token is present. */
  113. bool token_present;
  114. /* The supported mechanisms. */
  115. struct hurd_table mechanisms;
  116. /* The sessions. */
  117. struct hurd_table sessions;
  118. /* The objects on the token. */
  119. struct hurd_table objects;
  120. /* The info about the current token. */
  121. struct agent_card_info_s info;
  122. };
  123. /* The slot table. */
  124. static struct hurd_table slots = HURD_TABLE_INITIALIZER (sizeof (struct slot));
  125. /* We use one-based IDs. */
  126. #define SLOT_ID_TO_IDX(id) (id - 1)
  127. #define SLOT_IDX_TO_ID(idx) (idx + 1)
  128. /* Initialize the slot list. */
  129. CK_RV
  130. scute_slots_initialize (void)
  131. {
  132. /* FIXME: Implement this properly. Ensure that we stay within SLOT_MAX.
  133. Use a second slot for email? */
  134. error_t err;
  135. unsigned int idx;
  136. struct mechanism mechanism;
  137. struct slot slot;
  138. slot.dummy = DUMMY_PTR;
  139. slot.status = SLOT_STATUS_USED;
  140. slot.token_present = false;
  141. slot.login = SLOT_LOGIN_PUBLIC;
  142. hurd_table_init (&slot.sessions, sizeof (struct session));
  143. hurd_table_init (&slot.mechanisms, sizeof (struct mechanism));
  144. mechanism.dummy = DUMMY_PTR;
  145. mechanism.type = CKM_RSA_PKCS;
  146. mechanism.info.ulMinKeySize = 1024;
  147. mechanism.info.ulMaxKeySize = 1024;
  148. mechanism.info.flags = CKF_HW | CKF_SIGN;
  149. err = hurd_table_enter (&slot.mechanisms, &mechanism, &idx);
  150. if (err)
  151. {
  152. hurd_table_destroy (&slot.mechanisms);
  153. hurd_table_destroy (&slot.sessions);
  154. return scute_sys_to_ck (err);
  155. }
  156. hurd_table_init (&slot.objects, sizeof (struct object));
  157. err = hurd_table_enter (&slots, &slot, &idx);
  158. if (err)
  159. {
  160. hurd_table_destroy (&slot.objects);
  161. hurd_table_destroy (&slot.mechanisms);
  162. hurd_table_destroy (&slot.sessions);
  163. return scute_sys_to_ck (err);
  164. }
  165. return CKR_OK;
  166. }
  167. void scute_slots_finalize (void)
  168. {
  169. /* FIXME FIXME FIXME: Implement this. */
  170. }
  171. static void
  172. object_free (struct object *objp)
  173. {
  174. while (0 < objp->attributes_count--)
  175. free (objp->attributes[objp->attributes_count].pValue);
  176. free (objp->attributes);
  177. }
  178. /* Update the slot SLOT. */
  179. CK_RV
  180. slots_update_slot (slot_iterator_t id)
  181. {
  182. unsigned int idx = SLOT_ID_TO_IDX (id);
  183. struct slot *slot = hurd_table_lookup (&slots, idx);
  184. gpg_error_t err;
  185. assert (slot);
  186. if (slot->token_present)
  187. {
  188. err = scute_agent_check_status ();
  189. if (gpg_err_code (err) == GPG_ERR_CARD_REMOVED)
  190. {
  191. /* FIXME: Reset the whole thing. */
  192. /* FIXME: Code duplication with close_all_sessions. */
  193. HURD_TABLE_ITERATE (&slot->sessions, sid)
  194. {
  195. slot_close_session (id, sid);
  196. }
  197. HURD_TABLE_ITERATE (&slot->objects, oidx)
  198. {
  199. object_free (HURD_TABLE_LOOKUP (&slot->objects, oidx));
  200. hurd_table_remove (&slot->objects, oidx);
  201. }
  202. scute_agent_release_card_info (&slot->info);
  203. slot->token_present = false;
  204. }
  205. else if (err)
  206. return scute_gpg_err_to_ck (err);
  207. else
  208. return 0;
  209. }
  210. /* At this point, the card was or is removed, and we need to reopen
  211. the session, if possible. */
  212. err = scute_agent_learn (&slot->info);
  213. /* First check if this is really an OpenPGP card. FIXME: Should
  214. probably report the error in a better way. */
  215. if (!err && (!slot->info.serialno
  216. || strncmp (slot->info.serialno, "D27600012401", 12)
  217. || strlen (slot->info.serialno) != 32))
  218. {
  219. DEBUG ("Not an OpenPGP card");
  220. err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
  221. }
  222. if (gpg_err_code (err) == GPG_ERR_CARD_REMOVED
  223. || gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
  224. /* Nothing to do. */
  225. ;
  226. else if (err)
  227. return scute_gpg_err_to_ck (err);
  228. else
  229. {
  230. struct object objects[2];
  231. unsigned int oidxs[2];
  232. objects[0].dummy = DUMMY_PTR;
  233. objects[1].dummy = DUMMY_PTR;
  234. /* FIXME: Should be grip3. */
  235. err = scute_gpgsm_get_cert (slot->info.grip3,
  236. &objects[0].attributes,
  237. &objects[0].attributes_count,
  238. &objects[1].attributes,
  239. &objects[1].attributes_count);
  240. if (err)
  241. return scute_gpg_err_to_ck (err);
  242. err = hurd_table_enter (&slot->objects, &objects[0], &oidxs[0]);
  243. if (err)
  244. {
  245. object_free (&objects[0]);
  246. object_free (&objects[1]);
  247. return err;
  248. }
  249. err = hurd_table_enter (&slot->objects, &objects[1], &oidxs[1]);
  250. if (err)
  251. {
  252. hurd_table_remove (&slot->objects, oidxs[0]);
  253. object_free (&objects[0]);
  254. object_free (&objects[1]);
  255. return err;
  256. }
  257. /* FIXME: Perform the initialization of the token. */
  258. slot->token_present = true;
  259. }
  260. return CKR_OK;
  261. }
  262. /* Update the slot list by finding new devices. Please note that
  263. Mozilla NSS currently assumes that the slot list never shrinks (see
  264. TODO file for a discussion). This is the only function allowed to
  265. manipulate the slot list. */
  266. CK_RV
  267. slots_update (void)
  268. {
  269. HURD_TABLE_ITERATE (&slots, idx)
  270. {
  271. CK_RV err;
  272. err = slots_update_slot (SLOT_IDX_TO_ID (idx));
  273. if (err)
  274. return err;
  275. }
  276. return CKR_OK;
  277. }
  278. /* Begin iterating over the list of slots. If succeeds, will be
  279. followed up by a slot_iterate_end. */
  280. CK_RV
  281. slots_iterate_begin (slot_iterator_t *slot)
  282. {
  283. unsigned int idx = 0;
  284. /* FIXME: Protect against modification of slot status from here
  285. until slots_iterate_end. */
  286. while (idx < HURD_TABLE_EXTENT (&slots) && !hurd_table_lookup (&slots, idx))
  287. idx++;
  288. *slot = SLOT_IDX_TO_ID (idx);
  289. return CKR_OK;
  290. }
  291. /* Continue iterating over the list of slots. */
  292. CK_RV
  293. slots_iterate_next (slot_iterator_t *slot)
  294. {
  295. unsigned int idx = SLOT_ID_TO_IDX (*slot);
  296. do
  297. idx++;
  298. while (idx < HURD_TABLE_EXTENT (&slots) && !hurd_table_lookup (&slots, idx));
  299. *slot = SLOT_IDX_TO_ID (idx);
  300. return CKR_OK;
  301. }
  302. /* Stop iterating over the list of slots. */
  303. CK_RV
  304. slots_iterate_end (slot_iterator_t *slot)
  305. {
  306. /* FIXME: Nothing to do at this point. Release lock held by
  307. slots_iterate_begin. */
  308. return 0;
  309. }
  310. /* Return true iff the previous slot was the last one. */
  311. bool
  312. slots_iterate_last (slot_iterator_t *slot)
  313. {
  314. unsigned int idx = SLOT_ID_TO_IDX (*slot);
  315. return idx >= HURD_TABLE_EXTENT (&slots);
  316. }
  317. /* Acquire the slot for the slot ID ID. */
  318. CK_RV
  319. slots_lookup (CK_SLOT_ID id, slot_iterator_t *slot)
  320. {
  321. unsigned int idx = SLOT_ID_TO_IDX (id);
  322. if (idx >= HURD_TABLE_EXTENT (&slots))
  323. return CKR_SLOT_ID_INVALID;
  324. if (!hurd_table_lookup (&slots, idx))
  325. return CKR_DEVICE_ERROR;
  326. *slot = SLOT_IDX_TO_ID (idx);
  327. return CKR_OK;
  328. }
  329. /* Return true iff a token is present in slot SLOT. */
  330. bool
  331. slot_token_present (slot_iterator_t id)
  332. {
  333. unsigned int idx = SLOT_ID_TO_IDX (id);
  334. struct slot *slot = hurd_table_lookup (&slots, idx);
  335. assert (slot);
  336. return slot->token_present;
  337. }
  338. /* Return the token label. */
  339. char *
  340. slot_token_label (slot_iterator_t id)
  341. {
  342. unsigned int idx = SLOT_ID_TO_IDX (id);
  343. struct slot *slot = hurd_table_lookup (&slots, idx);
  344. assert (slot);
  345. /* slots_update() makes sure this is valid. */
  346. return slot->info.serialno;
  347. }
  348. /* Get the manufacturer of the token. */
  349. char *
  350. slot_token_manufacturer (slot_iterator_t id)
  351. {
  352. unsigned int idx = SLOT_ID_TO_IDX (id);
  353. struct slot *slot = hurd_table_lookup (&slots, idx);
  354. unsigned int uval;
  355. assert (slot);
  356. /* slots_update() makes sure this is valid. */
  357. uval = xtoi_2 (slot->info.serialno + 16) * 256
  358. + xtoi_2 (slot->info.serialno + 18);
  359. /* Note: Make sure that there is no colon or linefeed in the string. */
  360. switch (uval)
  361. {
  362. case 0:
  363. case 0xffff: return "test card";
  364. case 0x0001: return "PPC Card Systems";
  365. case 0x0002: return "Prism";
  366. case 0x0003: return "OpenFortress";
  367. default: return "unknown";
  368. }
  369. }
  370. /* Get the manufacturer of the token. */
  371. char *
  372. slot_token_application (slot_iterator_t id)
  373. {
  374. unsigned int idx = SLOT_ID_TO_IDX (id);
  375. struct slot *slot = hurd_table_lookup (&slots, idx);
  376. assert (slot);
  377. /* slots_update() makes sure this is correct. */
  378. return "OpenPGP";
  379. }
  380. /* Get the serial number of the token. Must not write more than 16
  381. bytes starting from DST. */
  382. int
  383. slot_token_serial (slot_iterator_t id, char *dst)
  384. {
  385. unsigned int idx = SLOT_ID_TO_IDX (id);
  386. struct slot *slot = hurd_table_lookup (&slots, idx);
  387. int i;
  388. assert (slot);
  389. /* slots_update() makes sure serialno is valid. */
  390. for (i = 0; i < 8; i++)
  391. dst[i] = slot->info.serialno[20 + i];
  392. return 8;
  393. }
  394. /* Get the manufacturer of the token. */
  395. void
  396. slot_token_version (slot_iterator_t id, CK_BYTE *hw_major, CK_BYTE *hw_minor,
  397. CK_BYTE *fw_major, CK_BYTE *fw_minor)
  398. {
  399. unsigned int idx = SLOT_ID_TO_IDX (id);
  400. struct slot *slot = hurd_table_lookup (&slots, idx);
  401. assert (slot);
  402. /* slots_update() makes sure serialno is valid. */
  403. *hw_major = xtoi_2 (slot->info.serialno + 12);
  404. *hw_minor = xtoi_2 (slot->info.serialno + 14);
  405. *fw_major = 0;
  406. *fw_minor = 0;
  407. }
  408. /* Get the maximum and minimum pin length. */
  409. void
  410. slot_token_maxpinlen (slot_iterator_t id, CK_ULONG *max, CK_ULONG *min)
  411. {
  412. unsigned int idx = SLOT_ID_TO_IDX (id);
  413. struct slot *slot = hurd_table_lookup (&slots, idx);
  414. assert (slot);
  415. *max = MIN (slot->info.chvmaxlen[0], slot->info.chvmaxlen[1]);
  416. /* FIXME: This is true at least for the user pin (CHV1 and CHV2). */
  417. *min = 6;
  418. }
  419. /* Get the maximum and the actual pin count. */
  420. void
  421. slot_token_pincount (slot_iterator_t id, int *max, int *len)
  422. {
  423. unsigned int idx = SLOT_ID_TO_IDX (id);
  424. struct slot *slot = hurd_table_lookup (&slots, idx);
  425. assert (slot);
  426. *max = 3;
  427. *len = MIN (slot->info.chvretry[0], slot->info.chvretry[1]);
  428. }
  429. /* Return the ID of slot SLOT. */
  430. CK_SLOT_ID
  431. slot_get_id (slot_iterator_t id)
  432. {
  433. unsigned int idx = SLOT_ID_TO_IDX (id);
  434. struct slot *slot = hurd_table_lookup (&slots, idx);
  435. assert (slot);
  436. return id;
  437. }
  438. /* Mechanism management. */
  439. /* Begin iterating over the list of mechanisms. If succeeds, will be
  440. followed up by a slot_iterate_end. */
  441. CK_RV
  442. mechanisms_iterate_begin (slot_iterator_t id,
  443. mechanism_iterator_t *mechanism)
  444. {
  445. unsigned int idx = SLOT_ID_TO_IDX (id);
  446. struct slot *slot = hurd_table_lookup (&slots, idx);
  447. unsigned int midx = 0;
  448. assert (slot);
  449. while (midx < HURD_TABLE_EXTENT (&slot->mechanisms)
  450. && !hurd_table_lookup (&slot->mechanisms, midx))
  451. midx++;
  452. *mechanism = MECHANISM_IDX_TO_ID (midx);
  453. return CKR_OK;
  454. }
  455. /* Continue iterating over the list of mechanisms. */
  456. CK_RV
  457. mechanisms_iterate_next (slot_iterator_t id, mechanism_iterator_t *mechanism)
  458. {
  459. unsigned int idx = SLOT_ID_TO_IDX (id);
  460. struct slot *slot = hurd_table_lookup (&slots, idx);
  461. unsigned int midx = MECHANISM_ID_TO_IDX (*mechanism);
  462. assert (slot);
  463. do
  464. midx++;
  465. while (midx < HURD_TABLE_EXTENT (&slot->mechanisms)
  466. && !hurd_table_lookup (&slot->mechanisms, midx));
  467. *mechanism = MECHANISM_IDX_TO_ID (midx);
  468. return CKR_OK;
  469. }
  470. /* Stop iterating over the list of mechanisms. */
  471. CK_RV
  472. mechanisms_iterate_end (slot_iterator_t id, mechanism_iterator_t *mechanism)
  473. {
  474. /* Nothing to do. */
  475. return 0;
  476. }
  477. /* Return true iff the previous slot was the last one. */
  478. bool
  479. mechanisms_iterate_last (slot_iterator_t id, mechanism_iterator_t *mechanism)
  480. {
  481. unsigned int idx = SLOT_ID_TO_IDX (id);
  482. struct slot *slot = hurd_table_lookup (&slots, idx);
  483. unsigned int midx = MECHANISM_ID_TO_IDX (*mechanism);
  484. assert (slot);
  485. return midx >= HURD_TABLE_EXTENT (&slot->mechanisms);
  486. }
  487. /* Acquire the mechanism TYPE for the slot id ID. */
  488. CK_RV
  489. mechanisms_lookup (slot_iterator_t id, mechanism_iterator_t *mid,
  490. CK_MECHANISM_TYPE type)
  491. {
  492. unsigned int idx = SLOT_ID_TO_IDX (id);
  493. struct slot *slot = hurd_table_lookup (&slots, idx);
  494. assert (slot);
  495. HURD_TABLE_ITERATE (&slot->mechanisms, midx)
  496. {
  497. struct mechanism *mechanism;
  498. mechanism = (struct mechanism *)
  499. HURD_TABLE_LOOKUP (&slot->mechanisms, midx);
  500. if (mechanism->type == type)
  501. {
  502. *mid = MECHANISM_IDX_TO_ID (midx);
  503. return CKR_OK;
  504. }
  505. }
  506. return CKR_MECHANISM_INVALID;
  507. }
  508. /* Return the type of mechanism MID in slot ID. */
  509. CK_MECHANISM_TYPE
  510. mechanism_get_type (slot_iterator_t id, mechanism_iterator_t mid)
  511. {
  512. unsigned int idx = SLOT_ID_TO_IDX (id);
  513. struct slot *slot = hurd_table_lookup (&slots, idx);
  514. unsigned int midx = MECHANISM_ID_TO_IDX (mid);
  515. struct mechanism *mechanism;
  516. assert (slot);
  517. mechanism = hurd_table_lookup (&slot->mechanisms, midx);
  518. assert (mechanism);
  519. return mechanism->type;
  520. }
  521. /* Return the info of mechanism MID. */
  522. CK_MECHANISM_INFO_PTR
  523. mechanism_get_info (slot_iterator_t id, mechanism_iterator_t mid)
  524. {
  525. unsigned int idx = SLOT_ID_TO_IDX (id);
  526. struct slot *slot = hurd_table_lookup (&slots, idx);
  527. unsigned int midx = MECHANISM_ID_TO_IDX (mid);
  528. struct mechanism *mechanism;
  529. assert (slot);
  530. mechanism = hurd_table_lookup (&slot->mechanisms, midx);
  531. assert (mechanism);
  532. return &mechanism->info;
  533. }
  534. /* Session management. */
  535. /* Create a new session. */
  536. CK_RV
  537. slot_create_session (slot_iterator_t id, session_iterator_t *session,
  538. bool rw)
  539. {
  540. error_t err;
  541. unsigned int idx = SLOT_ID_TO_IDX (id);
  542. struct slot *slot = hurd_table_lookup (&slots, idx);
  543. unsigned int tsid;
  544. struct session session_obj;
  545. assert (slot);
  546. if (HURD_TABLE_USED (&slot->sessions) == SESSION_MAX)
  547. return CKR_SESSION_COUNT;
  548. if (slot->login == SLOT_LOGIN_SO && !rw)
  549. return CKR_SESSION_READ_WRITE_SO_EXISTS;
  550. session_obj.dummy = DUMMY_PTR;
  551. session_obj.rw = rw;
  552. session_obj.search_result = NULL;
  553. session_obj.search_result_len = 0;
  554. err = hurd_table_enter (&slot->sessions, &session_obj, &tsid);
  555. if (err)
  556. return scute_sys_to_ck (err);
  557. *session = SESSION_BUILD_ID (id, tsid);
  558. return CKR_OK;
  559. }
  560. /* Look up session. */
  561. CK_RV
  562. slots_lookup_session (session_iterator_t sid, slot_iterator_t *id)
  563. {
  564. CK_RV err;
  565. unsigned int idx = SLOT_ID_TO_IDX (SESSION_SLOT (sid));
  566. unsigned session_idx = SESSION_ID (sid);
  567. struct slot *slot;
  568. /* Verify the slot. */
  569. err = slots_lookup (SESSION_SLOT (sid), id);
  570. if (err)
  571. return err;
  572. /* Verify the session. */
  573. slot = hurd_table_lookup (&slots, idx);
  574. if (session_idx >= HURD_TABLE_EXTENT (&slot->sessions)
  575. || !hurd_table_lookup (&slot->sessions, session_idx))
  576. return CKR_SESSION_HANDLE_INVALID;
  577. return 0;
  578. }
  579. /* Close the session. */
  580. CK_RV
  581. slot_close_session (slot_iterator_t id, session_iterator_t sid)
  582. {
  583. unsigned int idx = SLOT_ID_TO_IDX (id);
  584. struct slot *slot = hurd_table_lookup (&slots, idx);
  585. unsigned session_idx = SESSION_ID (sid);
  586. struct session *session;
  587. assert (slot);
  588. session = hurd_table_lookup (&slot->sessions, session_idx);
  589. assert (session);
  590. if (session->search_result)
  591. free (session->search_result);
  592. hurd_table_remove (&slot->sessions, session_idx);
  593. /* At last session closed, return to public sessions. */
  594. if (! HURD_TABLE_USED (&slot->sessions))
  595. slot->login = SLOT_LOGIN_PUBLIC;
  596. return CKR_OK;
  597. }
  598. /* Close all sessions. */
  599. CK_RV
  600. slot_close_all_sessions (slot_iterator_t id)
  601. {
  602. unsigned int idx = SLOT_ID_TO_IDX (id);
  603. struct slot *slot = hurd_table_lookup (&slots, idx);
  604. assert (slot);
  605. HURD_TABLE_ITERATE (&slot->sessions, sid)
  606. slot_close_session (id, sid);
  607. assert (HURD_TABLE_USED (&slot->sessions) == 0);
  608. return CKR_OK;
  609. }
  610. /* Get the RW flag from the session SID in slot ID. */
  611. bool
  612. session_get_rw (slot_iterator_t id, session_iterator_t sid)
  613. {
  614. unsigned int idx = SLOT_ID_TO_IDX (id);
  615. struct slot *slot = hurd_table_lookup (&slots, idx);
  616. unsigned session_idx = SESSION_ID (sid);
  617. struct session *session;
  618. assert (slot);
  619. session = hurd_table_lookup (&slot->sessions, session_idx);
  620. assert (session);
  621. return session->rw;
  622. }
  623. /* Get the login state from the slot ID. */
  624. slot_login_t
  625. slot_get_status (slot_iterator_t id)
  626. {
  627. unsigned int idx = SLOT_ID_TO_IDX (id);
  628. struct slot *slot = hurd_table_lookup (&slots, idx);
  629. assert (slot);
  630. return slot->status;
  631. }
  632. /* Object management. */
  633. /* Begin iterating over the list of objects. If succeeds, will be
  634. followed up by a slot_iterate_end. */
  635. CK_RV
  636. objects_iterate_begin (slot_iterator_t id,
  637. object_iterator_t *object)
  638. {
  639. unsigned int idx = SLOT_ID_TO_IDX (id);
  640. struct slot *slot = hurd_table_lookup (&slots, idx);
  641. unsigned int oidx = 0;
  642. assert (slot);
  643. while (oidx < HURD_TABLE_EXTENT (&slot->objects)
  644. && !hurd_table_lookup (&slot->objects, oidx))
  645. oidx++;
  646. *object = OBJECT_IDX_TO_ID (oidx);
  647. return CKR_OK;
  648. }
  649. /* Continue iterating over the list of objects. */
  650. CK_RV
  651. objects_iterate_next (slot_iterator_t id, object_iterator_t *object)
  652. {
  653. unsigned int idx = SLOT_ID_TO_IDX (id);
  654. struct slot *slot = hurd_table_lookup (&slots, idx);
  655. unsigned int oidx = OBJECT_ID_TO_IDX (*object);
  656. assert (slot);
  657. do
  658. oidx++;
  659. while (oidx < HURD_TABLE_EXTENT (&slot->objects)
  660. && !hurd_table_lookup (&slot->objects, oidx));
  661. *object = OBJECT_IDX_TO_ID (oidx);
  662. return CKR_OK;
  663. }
  664. /* Stop iterating over the list of objects. */
  665. CK_RV
  666. objects_iterate_end (slot_iterator_t id, object_iterator_t *object)
  667. {
  668. /* Nothing to do. */
  669. return 0;
  670. }
  671. /* Return true iff the previous slot was the last one. */
  672. bool
  673. objects_iterate_last (slot_iterator_t id, object_iterator_t *object)
  674. {
  675. unsigned int idx = SLOT_ID_TO_IDX (id);
  676. struct slot *slot = hurd_table_lookup (&slots, idx);
  677. unsigned int oidx = OBJECT_ID_TO_IDX (*object);
  678. assert (slot);
  679. return oidx >= HURD_TABLE_EXTENT (&slot->objects);
  680. }
  681. /* Return the max. number of objects in the slot. May overcount
  682. somewhat. */
  683. CK_RV
  684. slot_get_object_count (slot_iterator_t id, int *nr)
  685. {
  686. unsigned int idx = SLOT_ID_TO_IDX (id);
  687. struct slot *slot = hurd_table_lookup (&slots, idx);
  688. assert (slot);
  689. *nr = HURD_TABLE_EXTENT (&slot->objects);
  690. return CKR_OK;
  691. }
  692. /* Get the object information for object OBJECT_ID in slot ID. */
  693. CK_RV
  694. slot_get_object (slot_iterator_t id, object_iterator_t oid,
  695. CK_ATTRIBUTE_PTR *obj, CK_ULONG *obj_count)
  696. {
  697. unsigned int idx = SLOT_ID_TO_IDX (id);
  698. struct slot *slot = hurd_table_lookup (&slots, idx);
  699. unsigned int object_idx = OBJECT_ID_TO_IDX (oid);
  700. struct object *object;
  701. assert (slot);
  702. object = hurd_table_lookup (&slot->objects, object_idx);
  703. if (!object)
  704. return CKR_OBJECT_HANDLE_INVALID;
  705. assert (obj);
  706. assert (obj_count);
  707. *obj = object->attributes;
  708. *obj_count = object->attributes_count;
  709. return 0;
  710. }
  711. /* Set the result of a search for session SID in slot ID to
  712. SEARCH_RESULT and SEARCH_RESULT_LEN. */
  713. CK_RV
  714. session_set_search_result (slot_iterator_t id, session_iterator_t sid,
  715. object_iterator_t *search_result,
  716. int search_result_len)
  717. {
  718. unsigned int idx = SLOT_ID_TO_IDX (id);
  719. struct slot *slot = hurd_table_lookup (&slots, idx);
  720. unsigned session_idx = SESSION_ID (sid);
  721. struct session *session;
  722. assert (slot);
  723. session = hurd_table_lookup (&slot->sessions, session_idx);
  724. assert (session);
  725. if (session->search_result && session->search_result != search_result)
  726. free (session->search_result);
  727. session->search_result = search_result;
  728. session->search_result_len = search_result_len;
  729. return 0;
  730. }
  731. /* Get the stored search result for the session SID in slot ID. */
  732. CK_RV
  733. session_get_search_result (slot_iterator_t id, session_iterator_t sid,
  734. object_iterator_t **search_result,
  735. int *search_result_len)
  736. {
  737. unsigned int idx = SLOT_ID_TO_IDX (id);
  738. struct slot *slot = hurd_table_lookup (&slots, idx);
  739. unsigned session_idx = SESSION_ID (sid);
  740. struct session *session;
  741. assert (slot);
  742. session = hurd_table_lookup (&slot->sessions, session_idx);
  743. assert (session);
  744. assert (search_result);
  745. assert (search_result_len);
  746. *search_result = session->search_result;
  747. *search_result_len = session->search_result_len;
  748. return 0;
  749. }
  750. /* Set the signing key for session SID in slot ID to KEY. */
  751. CK_RV
  752. session_set_signing_key (slot_iterator_t id, session_iterator_t sid,
  753. object_iterator_t key)
  754. {
  755. unsigned int idx = SLOT_ID_TO_IDX (id);
  756. struct slot *slot = hurd_table_lookup (&slots, idx);
  757. unsigned session_idx = SESSION_ID (sid);
  758. struct session *session;
  759. CK_RV err;
  760. CK_ATTRIBUTE_PTR attr;
  761. CK_ULONG attr_count;
  762. CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
  763. assert (slot);
  764. session = hurd_table_lookup (&slot->sessions, session_idx);
  765. assert (session);
  766. err = slot_get_object (id, key, &attr, &attr_count);
  767. if (err)
  768. return err;
  769. while (attr_count-- > 0)
  770. if (attr->type == CKA_CLASS)
  771. break;
  772. if (attr_count == (CK_ULONG) -1)
  773. return CKR_KEY_HANDLE_INVALID;
  774. if (attr->ulValueLen != sizeof (key_class)
  775. || memcmp (attr->pValue, &key_class, sizeof (key_class)))
  776. return CKR_KEY_HANDLE_INVALID;
  777. /* It's the private RSA key object. */
  778. session->signing_key = key;
  779. return 0;
  780. }
  781. /* Set the signing key for session SID in slot ID to KEY. */
  782. CK_RV
  783. session_sign (slot_iterator_t id, session_iterator_t sid,
  784. CK_BYTE_PTR pData, CK_ULONG ulDataLen,
  785. CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
  786. {
  787. unsigned int idx = SLOT_ID_TO_IDX (id);
  788. struct slot *slot = hurd_table_lookup (&slots, idx);
  789. unsigned session_idx = SESSION_ID (sid);
  790. struct session *session;
  791. gpg_error_t err;
  792. unsigned int sig_len;
  793. assert (slot);
  794. session = hurd_table_lookup (&slot->sessions, session_idx);
  795. assert (session);
  796. /* FIXME: Who cares if they called sign init correctly. */
  797. if (pSignature == NULL_PTR)
  798. {
  799. err = scute_agent_sign (NULL, NULL, 0, NULL, &sig_len);
  800. if (err)
  801. return scute_gpg_err_to_ck (err);
  802. *pulSignatureLen = sig_len;
  803. return 0;
  804. }
  805. sig_len = *pulSignatureLen;
  806. err = scute_agent_sign (slot->info.grip3, pData, ulDataLen,
  807. pSignature, &sig_len);
  808. /* FIXME: Oh well. */
  809. if (gpg_err_code (err) == GPG_ERR_INV_ARG)
  810. return CKR_BUFFER_TOO_SMALL;
  811. return scute_gpg_err_to_ck (err);
  812. }