1/*
2 * Copyright (c) 2004 - 2008 Kungliga Tekniska H��gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#define CRYPTOKI_EXPORTS 1
35
36#include "hx_locl.h"
37#include "pkcs11.h"
38
39#define OBJECT_ID_MASK		0xfff
40#define HANDLE_OBJECT_ID(h)	((h) & OBJECT_ID_MASK)
41#define OBJECT_ID(obj)		HANDLE_OBJECT_ID((obj)->object_handle)
42
43#ifndef HAVE_RANDOM
44#define random() rand()
45#define srandom(s) srand(s)
46#endif
47
48#ifdef _WIN32
49#include <shlobj.h>
50#endif
51
52struct st_attr {
53    CK_ATTRIBUTE attribute;
54    int secret;
55};
56
57struct st_object {
58    CK_OBJECT_HANDLE object_handle;
59    struct st_attr *attrs;
60    int num_attributes;
61    hx509_cert cert;
62};
63
64static struct soft_token {
65    CK_VOID_PTR application;
66    CK_NOTIFY notify;
67    char *config_file;
68    hx509_certs certs;
69    struct {
70	struct st_object **objs;
71	int num_objs;
72    } object;
73    struct {
74	int hardware_slot;
75	int app_error_fatal;
76	int login_done;
77    } flags;
78    int open_sessions;
79    struct session_state {
80	CK_SESSION_HANDLE session_handle;
81
82	struct {
83	    CK_ATTRIBUTE *attributes;
84	    CK_ULONG num_attributes;
85	    int next_object;
86	} find;
87
88	int sign_object;
89	CK_MECHANISM_PTR sign_mechanism;
90	int verify_object;
91	CK_MECHANISM_PTR verify_mechanism;
92    } state[10];
93#define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0]))
94    FILE *logfile;
95} soft_token;
96
97static hx509_context context;
98
99static void
100application_error(const char *fmt, ...)
101{
102    va_list ap;
103    va_start(ap, fmt);
104    vprintf(fmt, ap);
105    va_end(ap);
106    if (soft_token.flags.app_error_fatal)
107	abort();
108}
109
110static void
111st_logf(const char *fmt, ...)
112{
113    va_list ap;
114    if (soft_token.logfile == NULL)
115	return;
116    va_start(ap, fmt);
117    vfprintf(soft_token.logfile, fmt, ap);
118    va_end(ap);
119    fflush(soft_token.logfile);
120}
121
122static CK_RV
123init_context(void)
124{
125    if (context == NULL) {
126	int ret = hx509_context_init(&context);
127	if (ret)
128	    return CKR_GENERAL_ERROR;
129    }
130    return CKR_OK;
131}
132
133#define INIT_CONTEXT() { CK_RV icret = init_context(); if (icret) return icret; }
134
135static void
136snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...)
137{
138    int len;
139    va_list ap;
140    va_start(ap, fmt);
141    len = vsnprintf(str, size, fmt, ap);
142    va_end(ap);
143    if (len < 0 || (size_t)len > size)
144	return;
145    while ((size_t)len < size)
146	str[len++] = fillchar;
147}
148
149#ifndef TEST_APP
150#define printf error_use_st_logf
151#endif
152
153#define VERIFY_SESSION_HANDLE(s, state)			\
154{							\
155    CK_RV xret;						\
156    xret = verify_session_handle(s, state);		\
157    if (xret != CKR_OK) {				\
158	/* return CKR_OK */;				\
159    }							\
160}
161
162static CK_RV
163verify_session_handle(CK_SESSION_HANDLE hSession,
164		      struct session_state **state)
165{
166    size_t i;
167
168    for (i = 0; i < MAX_NUM_SESSION; i++){
169	if (soft_token.state[i].session_handle == hSession)
170	    break;
171    }
172    if (i == MAX_NUM_SESSION) {
173	application_error("use of invalid handle: 0x%08lx\n",
174			  (unsigned long)hSession);
175	return CKR_SESSION_HANDLE_INVALID;
176    }
177    if (state)
178	*state = &soft_token.state[i];
179    return CKR_OK;
180}
181
182static CK_RV
183object_handle_to_object(CK_OBJECT_HANDLE handle,
184			struct st_object **object)
185{
186    int i = HANDLE_OBJECT_ID(handle);
187
188    *object = NULL;
189    if (i >= soft_token.object.num_objs)
190	return CKR_ARGUMENTS_BAD;
191    if (soft_token.object.objs[i] == NULL)
192	return CKR_ARGUMENTS_BAD;
193    if (soft_token.object.objs[i]->object_handle != handle)
194	return CKR_ARGUMENTS_BAD;
195    *object = soft_token.object.objs[i];
196    return CKR_OK;
197}
198
199static int
200attributes_match(const struct st_object *obj,
201		 const CK_ATTRIBUTE *attributes,
202		 CK_ULONG num_attributes)
203{
204    CK_ULONG i;
205    int j;
206
207    st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj));
208
209    for (i = 0; i < num_attributes; i++) {
210	int match = 0;
211	for (j = 0; j < obj->num_attributes; j++) {
212	    if (attributes[i].type == obj->attrs[j].attribute.type &&
213		attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen &&
214		memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue,
215		       attributes[i].ulValueLen) == 0) {
216		match = 1;
217		break;
218	    }
219	}
220	if (match == 0) {
221	    st_logf("type %d attribute have no match\n", attributes[i].type);
222	    return 0;
223	}
224    }
225    st_logf("attribute matches\n");
226    return 1;
227}
228
229static void
230print_attributes(const CK_ATTRIBUTE *attributes,
231		 CK_ULONG num_attributes)
232{
233    CK_ULONG i;
234
235    st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes);
236
237    for (i = 0; i < num_attributes; i++) {
238	st_logf("  type: ");
239	switch (attributes[i].type) {
240	case CKA_TOKEN: {
241	    CK_BBOOL *ck_true;
242	    if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) {
243		application_error("token attribute wrong length\n");
244		break;
245	    }
246	    ck_true = attributes[i].pValue;
247	    st_logf("token: %s", *ck_true ? "TRUE" : "FALSE");
248	    break;
249	}
250	case CKA_CLASS: {
251	    CK_OBJECT_CLASS *class;
252	    if (attributes[i].ulValueLen != sizeof(CK_ULONG)) {
253		application_error("class attribute wrong length\n");
254		break;
255	    }
256	    class = attributes[i].pValue;
257	    st_logf("class ");
258	    switch (*class) {
259	    case CKO_CERTIFICATE:
260		st_logf("certificate");
261		break;
262	    case CKO_PUBLIC_KEY:
263		st_logf("public key");
264		break;
265	    case CKO_PRIVATE_KEY:
266		st_logf("private key");
267		break;
268	    case CKO_SECRET_KEY:
269		st_logf("secret key");
270		break;
271	    case CKO_DOMAIN_PARAMETERS:
272		st_logf("domain parameters");
273		break;
274	    default:
275		st_logf("[class %lx]", (long unsigned)*class);
276		break;
277	    }
278	    break;
279	}
280	case CKA_PRIVATE:
281	    st_logf("private");
282	    break;
283	case CKA_LABEL:
284	    st_logf("label");
285	    break;
286	case CKA_APPLICATION:
287	    st_logf("application");
288	    break;
289	case CKA_VALUE:
290	    st_logf("value");
291	    break;
292	case CKA_ID:
293	    st_logf("id");
294	    break;
295	default:
296	    st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type);
297	    break;
298	}
299	st_logf("\n");
300    }
301}
302
303static struct st_object *
304add_st_object(void)
305{
306    struct st_object *o, **objs;
307    int i;
308
309    o = calloc(1, sizeof(*o));
310    if (o == NULL)
311	return NULL;
312
313    for (i = 0; i < soft_token.object.num_objs; i++) {
314	if (soft_token.object.objs == NULL) {
315	    soft_token.object.objs[i] = o;
316	    break;
317	}
318    }
319    if (i == soft_token.object.num_objs) {
320	objs = realloc(soft_token.object.objs,
321		       (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0]));
322	if (objs == NULL) {
323	    free(o);
324	    return NULL;
325	}
326	soft_token.object.objs = objs;
327	soft_token.object.objs[soft_token.object.num_objs++] = o;
328    }
329    soft_token.object.objs[i]->object_handle =
330	(random() & (~OBJECT_ID_MASK)) | i;
331
332    return o;
333}
334
335static CK_RV
336add_object_attribute(struct st_object *o,
337		     int secret,
338		     CK_ATTRIBUTE_TYPE type,
339		     CK_VOID_PTR pValue,
340		     CK_ULONG ulValueLen)
341{
342    struct st_attr *a;
343    int i;
344
345    if (pValue == NULL && ulValueLen)
346        return CKR_ARGUMENTS_BAD;
347
348    i = o->num_attributes;
349    a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0]));
350    if (a == NULL)
351	return CKR_DEVICE_MEMORY;
352    o->attrs = a;
353    o->attrs[i].secret = secret;
354    o->attrs[i].attribute.type = type;
355    o->attrs[i].attribute.pValue = malloc(ulValueLen);
356    if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0)
357	return CKR_DEVICE_MEMORY;
358    if (ulValueLen)
359        memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen);
360    o->attrs[i].attribute.ulValueLen = ulValueLen;
361    o->num_attributes++;
362
363    return CKR_OK;
364}
365
366static CK_RV
367add_pubkey_info(hx509_context hxctx, struct st_object *o,
368		CK_KEY_TYPE key_type, hx509_cert cert)
369{
370    BIGNUM *num;
371    CK_BYTE *modulus = NULL;
372    size_t modulus_len = 0;
373    CK_ULONG modulus_bits = 0;
374    CK_BYTE *exponent = NULL;
375    size_t exponent_len = 0;
376
377    if (key_type != CKK_RSA)
378	return CKR_OK;
379    if (_hx509_cert_private_key(cert) == NULL)
380	return CKR_OK;
381
382    num = _hx509_private_key_get_internal(context,
383					  _hx509_cert_private_key(cert),
384					  "rsa-modulus");
385    if (num == NULL)
386	return CKR_GENERAL_ERROR;
387    modulus_bits = BN_num_bits(num);
388
389    modulus_len = BN_num_bytes(num);
390    modulus = malloc(modulus_len);
391    BN_bn2bin(num, modulus);
392    BN_free(num);
393
394    add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
395    add_object_attribute(o, 0, CKA_MODULUS_BITS,
396			 &modulus_bits, sizeof(modulus_bits));
397
398    free(modulus);
399
400    num = _hx509_private_key_get_internal(context,
401					  _hx509_cert_private_key(cert),
402					  "rsa-exponent");
403    if (num == NULL)
404	return CKR_GENERAL_ERROR;
405
406    exponent_len = BN_num_bytes(num);
407    exponent = malloc(exponent_len);
408    BN_bn2bin(num, exponent);
409    BN_free(num);
410
411    add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
412			 exponent, exponent_len);
413
414    free(exponent);
415
416    return CKR_OK;
417}
418
419
420struct foo {
421    char *label;
422    char *id;
423};
424
425static int
426add_cert(hx509_context hxctx, void *ctx, hx509_cert cert)
427{
428    static char empty[] = "";
429    struct foo *foo = (struct foo *)ctx;
430    struct st_object *o = NULL;
431    CK_OBJECT_CLASS type;
432    CK_BBOOL bool_true = CK_TRUE;
433    CK_BBOOL bool_false = CK_FALSE;
434    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
435    CK_KEY_TYPE key_type;
436    CK_MECHANISM_TYPE mech_type;
437    CK_RV ret = CKR_GENERAL_ERROR;
438    int hret;
439    heim_octet_string cert_data, subject_data, issuer_data, serial_data;
440
441    st_logf("adding certificate\n");
442
443    serial_data.data = NULL;
444    serial_data.length = 0;
445    cert_data = subject_data = issuer_data = serial_data;
446
447    hret = hx509_cert_binary(hxctx, cert, &cert_data);
448    if (hret)
449	goto out;
450
451    {
452	    hx509_name name;
453
454	    hret = hx509_cert_get_issuer(cert, &name);
455	    if (hret)
456		goto out;
457	    hret = hx509_name_binary(name, &issuer_data);
458	    hx509_name_free(&name);
459	    if (hret)
460		goto out;
461
462	    hret = hx509_cert_get_subject(cert, &name);
463	    if (hret)
464		goto out;
465	    hret = hx509_name_binary(name, &subject_data);
466	    hx509_name_free(&name);
467	    if (hret)
468		goto out;
469    }
470
471    {
472	AlgorithmIdentifier alg;
473
474	hret = hx509_cert_get_SPKI_AlgorithmIdentifier(context, cert, &alg);
475	if (hret) {
476	    ret = CKR_DEVICE_MEMORY;
477	    goto out;
478	}
479
480	key_type = CKK_RSA; /* XXX */
481
482	free_AlgorithmIdentifier(&alg);
483    }
484
485
486    type = CKO_CERTIFICATE;
487    o = add_st_object();
488    if (o == NULL) {
489	ret = CKR_DEVICE_MEMORY;
490	goto out;
491    }
492
493    o->cert = hx509_cert_ref(cert);
494
495    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
496    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
497    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
498    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
499    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
500
501    add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
502    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
503
504    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
505    add_object_attribute(o, 0, CKA_ISSUER, issuer_data.data, issuer_data.length);
506    add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data.data, serial_data.length);
507    add_object_attribute(o, 0, CKA_VALUE, cert_data.data, cert_data.length);
508    add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));
509
510    st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));
511
512    type = CKO_PUBLIC_KEY;
513    o = add_st_object();
514    if (o == NULL) {
515	ret = CKR_DEVICE_MEMORY;
516	goto out;
517    }
518    o->cert = hx509_cert_ref(cert);
519
520    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
521    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
522    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
523    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
524    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
525
526    add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
527    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
528    add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
529    add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
530    add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
531    add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
532    mech_type = CKM_RSA_X_509;
533    add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
534
535    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
536    add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
537    add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
538    add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
539    add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
540    add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
541
542    add_pubkey_info(hxctx, o, key_type, cert);
543
544    st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));
545
546    if (hx509_cert_have_private_key(cert)) {
547	CK_FLAGS flags;
548
549	type = CKO_PRIVATE_KEY;
550	o = add_st_object();
551	if (o == NULL) {
552	    ret = CKR_DEVICE_MEMORY;
553	    goto out;
554	}
555	o->cert = hx509_cert_ref(cert);
556
557	add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
558	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
559	add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
560	add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
561	add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
562
563	add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
564	add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
565	add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
566	add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
567	add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
568	add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
569	mech_type = CKM_RSA_X_509;
570	add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
571
572	add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
573	add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
574	add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
575	flags = 0;
576	add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));
577
578	add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
579	add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
580	add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
581	add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
582	add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
583	add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));
584
585	add_pubkey_info(hxctx, o, key_type, cert);
586    }
587
588    ret = CKR_OK;
589 out:
590    if (ret != CKR_OK) {
591	st_logf("something went wrong when adding cert!\n");
592
593	/* XXX wack o */;
594    }
595    hx509_xfree(cert_data.data);
596    hx509_xfree(serial_data.data);
597    hx509_xfree(issuer_data.data);
598    hx509_xfree(subject_data.data);
599
600    return 0;
601}
602
603static CK_RV
604add_certificate(const char *cert_file,
605		const char *pin,
606		char *id,
607		char *label)
608{
609    hx509_certs certs;
610    hx509_lock lock = NULL;
611    int ret, flags = 0;
612
613    struct foo foo;
614    foo.id = id;
615    foo.label = label;
616
617    if (pin == NULL)
618	flags |= HX509_CERTS_UNPROTECT_ALL;
619
620    if (pin) {
621	char *str;
622	asprintf(&str, "PASS:%s", pin);
623
624	hx509_lock_init(context, &lock);
625	hx509_lock_command_string(lock, str);
626
627	memset(str, 0, strlen(str));
628	free(str);
629    }
630
631    ret = hx509_certs_init(context, cert_file, flags, lock, &certs);
632    if (ret) {
633	st_logf("failed to open file %s\n", cert_file);
634	return CKR_GENERAL_ERROR;
635    }
636
637    ret = hx509_certs_iter_f(context, certs, add_cert, &foo);
638    hx509_certs_free(&certs);
639    if (ret) {
640	st_logf("failed adding certs from file %s\n", cert_file);
641	return CKR_GENERAL_ERROR;
642    }
643
644    return CKR_OK;
645}
646
647static void
648find_object_final(struct session_state *state)
649{
650    if (state->find.attributes) {
651	CK_ULONG i;
652
653	for (i = 0; i < state->find.num_attributes; i++) {
654	    if (state->find.attributes[i].pValue)
655		free(state->find.attributes[i].pValue);
656	}
657	free(state->find.attributes);
658	state->find.attributes = NULL;
659	state->find.num_attributes = 0;
660	state->find.next_object = -1;
661    }
662}
663
664static void
665reset_crypto_state(struct session_state *state)
666{
667    state->sign_object = -1;
668    if (state->sign_mechanism)
669	free(state->sign_mechanism);
670    state->sign_mechanism = NULL_PTR;
671    state->verify_object = -1;
672    if (state->verify_mechanism)
673	free(state->verify_mechanism);
674    state->verify_mechanism = NULL_PTR;
675}
676
677static void
678close_session(struct session_state *state)
679{
680    if (state->find.attributes) {
681	application_error("application didn't do C_FindObjectsFinal\n");
682	find_object_final(state);
683    }
684
685    state->session_handle = CK_INVALID_HANDLE;
686    soft_token.application = NULL_PTR;
687    soft_token.notify = NULL_PTR;
688    reset_crypto_state(state);
689}
690
691static const char *
692has_session(void)
693{
694    return soft_token.open_sessions > 0 ? "yes" : "no";
695}
696
697static CK_RV
698read_conf_file(const char *fn, CK_USER_TYPE userType, const char *pin)
699{
700    char buf[1024], *type, *s, *p;
701    FILE *f;
702    CK_RV ret = CKR_OK;
703    CK_RV failed = CKR_OK;
704
705    if (fn == NULL) {
706        st_logf("Can't open configuration file.  No file specified\n");
707        return CKR_GENERAL_ERROR;
708    }
709
710    f = fopen(fn, "r");
711    if (f == NULL) {
712	st_logf("can't open configuration file %s\n", fn);
713	return CKR_GENERAL_ERROR;
714    }
715    rk_cloexec_file(f);
716
717    while(fgets(buf, sizeof(buf), f) != NULL) {
718	buf[strcspn(buf, "\n")] = '\0';
719
720	st_logf("line: %s\n", buf);
721
722	p = buf;
723	while (isspace((unsigned char)*p))
724	    p++;
725	if (*p == '#')
726	    continue;
727	while (isspace((unsigned char)*p))
728	    p++;
729
730	s = NULL;
731	type = strtok_r(p, "\t", &s);
732	if (type == NULL)
733	    continue;
734
735	if (strcasecmp("certificate", type) == 0) {
736	    char *cert, *id, *label;
737
738	    id = strtok_r(NULL, "\t", &s);
739	    if (id == NULL) {
740		st_logf("no id\n");
741		continue;
742	    }
743	    st_logf("id: %s\n", id);
744	    label = strtok_r(NULL, "\t", &s);
745	    if (label == NULL) {
746		st_logf("no label\n");
747		continue;
748	    }
749	    cert = strtok_r(NULL, "\t", &s);
750	    if (cert == NULL) {
751		st_logf("no certfiicate store\n");
752		continue;
753	    }
754
755	    st_logf("adding: %s: %s in file %s\n", id, label, cert);
756
757	    ret = add_certificate(cert, pin, id, label);
758	    if (ret)
759		failed = ret;
760	} else if (strcasecmp("debug", type) == 0) {
761	    char *name;
762
763	    name = strtok_r(NULL, "\t", &s);
764	    if (name == NULL) {
765		st_logf("no filename\n");
766		continue;
767	    }
768
769	    if (soft_token.logfile)
770		fclose(soft_token.logfile);
771
772	    if (strcasecmp(name, "stdout") == 0)
773		soft_token.logfile = stdout;
774	    else {
775		soft_token.logfile = fopen(name, "a");
776		if (soft_token.logfile)
777		    rk_cloexec_file(soft_token.logfile);
778	    }
779	    if (soft_token.logfile == NULL)
780		st_logf("failed to open file: %s\n", name);
781
782	} else if (strcasecmp("app-fatal", type) == 0) {
783	    char *name;
784
785	    name = strtok_r(NULL, "\t", &s);
786	    if (name == NULL) {
787		st_logf("argument to app-fatal\n");
788		continue;
789	    }
790
791	    if (strcmp(name, "true") == 0 || strcmp(name, "on") == 0)
792		soft_token.flags.app_error_fatal = 1;
793	    else if (strcmp(name, "false") == 0 || strcmp(name, "off") == 0)
794		soft_token.flags.app_error_fatal = 0;
795	    else
796		st_logf("unknown app-fatal: %s\n", name);
797
798	} else {
799	    st_logf("unknown type: %s\n", type);
800	}
801    }
802
803    fclose(f);
804
805    return failed;
806}
807
808static CK_RV
809func_not_supported(void)
810{
811    st_logf("function not supported\n");
812    return CKR_FUNCTION_NOT_SUPPORTED;
813}
814
815static char *
816get_config_file_for_user(void)
817{
818    char *fn = NULL;
819
820#ifndef _WIN32
821    char *home = NULL;
822
823    if (!issuid()) {
824        fn = getenv("SOFTPKCS11RC");
825        if (fn)
826            fn = strdup(fn);
827        home = getenv("HOME");
828    }
829    if (fn == NULL && home == NULL) {
830        struct passwd *pw = getpwuid(getuid());
831        if(pw != NULL)
832            home = pw->pw_dir;
833    }
834    if (fn == NULL) {
835        if (home)
836            asprintf(&fn, "%s/.soft-token.rc", home);
837        else
838            fn = strdup("/etc/soft-token.rc");
839    }
840#else  /* Windows */
841
842    char appdatafolder[MAX_PATH];
843
844    fn = getenv("SOFTPKCS11RC");
845
846    /* Retrieve the roaming AppData folder for the current user.  The
847       current user is the user account represented by the current
848       thread token. */
849
850    if (fn == NULL &&
851        SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatafolder))) {
852
853        asprintf(&fn, "%s\\.soft-token.rc", appdatafolder);
854    }
855
856#endif  /* _WIN32 */
857
858    return fn;
859}
860
861
862CK_RV CK_SPEC
863C_Initialize(CK_VOID_PTR a)
864{
865    CK_C_INITIALIZE_ARGS_PTR args = a;
866    CK_RV ret;
867    size_t i;
868
869    st_logf("Initialize\n");
870
871    INIT_CONTEXT();
872
873    OpenSSL_add_all_algorithms();
874
875    srandom(getpid() ^ (int) time(NULL));
876
877    for (i = 0; i < MAX_NUM_SESSION; i++) {
878	soft_token.state[i].session_handle = CK_INVALID_HANDLE;
879	soft_token.state[i].find.attributes = NULL;
880	soft_token.state[i].find.num_attributes = 0;
881	soft_token.state[i].find.next_object = -1;
882	reset_crypto_state(&soft_token.state[i]);
883    }
884
885    soft_token.flags.hardware_slot = 1;
886    soft_token.flags.app_error_fatal = 0;
887    soft_token.flags.login_done = 0;
888
889    soft_token.object.objs = NULL;
890    soft_token.object.num_objs = 0;
891
892    soft_token.logfile = NULL;
893#if 0
894    soft_token.logfile = stdout;
895#endif
896#if 0
897    soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
898#endif
899
900    if (a != NULL_PTR) {
901	st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
902	st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
903	st_logf("\tLockMutext\t%p\n", args->LockMutex);
904	st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
905	st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
906    }
907
908    soft_token.config_file = get_config_file_for_user();
909
910    /*
911     * This operations doesn't return CKR_OK if any of the
912     * certificates failes to be unparsed (ie password protected).
913     */
914    ret = read_conf_file(soft_token.config_file, CKU_USER, NULL);
915    if (ret == CKR_OK)
916	soft_token.flags.login_done = 1;
917
918    return CKR_OK;
919}
920
921CK_RV
922C_Finalize(CK_VOID_PTR args)
923{
924    size_t i;
925
926    INIT_CONTEXT();
927
928    st_logf("Finalize\n");
929
930    for (i = 0; i < MAX_NUM_SESSION; i++) {
931	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
932	    application_error("application finalized without "
933			      "closing session\n");
934	    close_session(&soft_token.state[i]);
935	}
936    }
937
938    return CKR_OK;
939}
940
941CK_RV
942C_GetInfo(CK_INFO_PTR args)
943{
944    INIT_CONTEXT();
945
946    st_logf("GetInfo\n");
947
948    memset(args, 17, sizeof(*args));
949    args->cryptokiVersion.major = 2;
950    args->cryptokiVersion.minor = 10;
951    snprintf_fill((char *)args->manufacturerID,
952		  sizeof(args->manufacturerID),
953		  ' ',
954		  "Heimdal hx509 SoftToken");
955    snprintf_fill((char *)args->libraryDescription,
956		  sizeof(args->libraryDescription), ' ',
957		  "Heimdal hx509 SoftToken");
958    args->libraryVersion.major = 2;
959    args->libraryVersion.minor = 0;
960
961    return CKR_OK;
962}
963
964extern CK_FUNCTION_LIST funcs;
965
966CK_RV
967C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
968{
969    INIT_CONTEXT();
970
971    *ppFunctionList = &funcs;
972    return CKR_OK;
973}
974
975CK_RV
976C_GetSlotList(CK_BBOOL tokenPresent,
977	      CK_SLOT_ID_PTR pSlotList,
978	      CK_ULONG_PTR   pulCount)
979{
980    INIT_CONTEXT();
981    st_logf("GetSlotList: %s\n",
982	    tokenPresent ? "tokenPresent" : "token not Present");
983    if (pSlotList)
984	pSlotList[0] = 1;
985    *pulCount = 1;
986    return CKR_OK;
987}
988
989CK_RV
990C_GetSlotInfo(CK_SLOT_ID slotID,
991	      CK_SLOT_INFO_PTR pInfo)
992{
993    INIT_CONTEXT();
994    st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
995
996    memset(pInfo, 18, sizeof(*pInfo));
997
998    if (slotID != 1)
999	return CKR_ARGUMENTS_BAD;
1000
1001    snprintf_fill((char *)pInfo->slotDescription,
1002		  sizeof(pInfo->slotDescription),
1003		  ' ',
1004		  "Heimdal hx509 SoftToken (slot)");
1005    snprintf_fill((char *)pInfo->manufacturerID,
1006		  sizeof(pInfo->manufacturerID),
1007		  ' ',
1008		  "Heimdal hx509 SoftToken (slot)");
1009    pInfo->flags = CKF_TOKEN_PRESENT;
1010    if (soft_token.flags.hardware_slot)
1011	pInfo->flags |= CKF_HW_SLOT;
1012    pInfo->hardwareVersion.major = 1;
1013    pInfo->hardwareVersion.minor = 0;
1014    pInfo->firmwareVersion.major = 1;
1015    pInfo->firmwareVersion.minor = 0;
1016
1017    return CKR_OK;
1018}
1019
1020CK_RV
1021C_GetTokenInfo(CK_SLOT_ID slotID,
1022	       CK_TOKEN_INFO_PTR pInfo)
1023{
1024    INIT_CONTEXT();
1025    st_logf("GetTokenInfo: %s\n", has_session());
1026
1027    memset(pInfo, 19, sizeof(*pInfo));
1028
1029    snprintf_fill((char *)pInfo->label,
1030		  sizeof(pInfo->label),
1031		  ' ',
1032		  "Heimdal hx509 SoftToken (token)");
1033    snprintf_fill((char *)pInfo->manufacturerID,
1034		  sizeof(pInfo->manufacturerID),
1035		  ' ',
1036		  "Heimdal hx509 SoftToken (token)");
1037    snprintf_fill((char *)pInfo->model,
1038		  sizeof(pInfo->model),
1039		  ' ',
1040		  "Heimdal hx509 SoftToken (token)");
1041    snprintf_fill((char *)pInfo->serialNumber,
1042		  sizeof(pInfo->serialNumber),
1043		  ' ',
1044		  "4711");
1045    pInfo->flags =
1046	CKF_TOKEN_INITIALIZED |
1047	CKF_USER_PIN_INITIALIZED;
1048
1049    if (soft_token.flags.login_done == 0)
1050	pInfo->flags |= CKF_LOGIN_REQUIRED;
1051
1052    /* CFK_RNG |
1053       CKF_RESTORE_KEY_NOT_NEEDED |
1054    */
1055    pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
1056    pInfo->ulSessionCount = soft_token.open_sessions;
1057    pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
1058    pInfo->ulRwSessionCount = soft_token.open_sessions;
1059    pInfo->ulMaxPinLen = 1024;
1060    pInfo->ulMinPinLen = 0;
1061    pInfo->ulTotalPublicMemory = 4711;
1062    pInfo->ulFreePublicMemory = 4712;
1063    pInfo->ulTotalPrivateMemory = 4713;
1064    pInfo->ulFreePrivateMemory = 4714;
1065    pInfo->hardwareVersion.major = 2;
1066    pInfo->hardwareVersion.minor = 0;
1067    pInfo->firmwareVersion.major = 2;
1068    pInfo->firmwareVersion.minor = 0;
1069
1070    return CKR_OK;
1071}
1072
1073CK_RV
1074C_GetMechanismList(CK_SLOT_ID slotID,
1075		   CK_MECHANISM_TYPE_PTR pMechanismList,
1076		   CK_ULONG_PTR pulCount)
1077{
1078    INIT_CONTEXT();
1079    st_logf("GetMechanismList\n");
1080
1081    *pulCount = 1;
1082    if (pMechanismList == NULL_PTR)
1083	return CKR_OK;
1084    pMechanismList[1] = CKM_RSA_PKCS;
1085
1086    return CKR_OK;
1087}
1088
1089CK_RV
1090C_GetMechanismInfo(CK_SLOT_ID slotID,
1091		   CK_MECHANISM_TYPE type,
1092		   CK_MECHANISM_INFO_PTR pInfo)
1093{
1094    INIT_CONTEXT();
1095    st_logf("GetMechanismInfo: slot %d type: %d\n",
1096	    (int)slotID, (int)type);
1097    memset(pInfo, 0, sizeof(*pInfo));
1098
1099    return CKR_OK;
1100}
1101
1102CK_RV
1103C_InitToken(CK_SLOT_ID slotID,
1104	    CK_UTF8CHAR_PTR pPin,
1105	    CK_ULONG ulPinLen,
1106	    CK_UTF8CHAR_PTR pLabel)
1107{
1108    INIT_CONTEXT();
1109    st_logf("InitToken: slot %d\n", (int)slotID);
1110    return CKR_FUNCTION_NOT_SUPPORTED;
1111}
1112
1113CK_RV
1114C_OpenSession(CK_SLOT_ID slotID,
1115	      CK_FLAGS flags,
1116	      CK_VOID_PTR pApplication,
1117	      CK_NOTIFY Notify,
1118	      CK_SESSION_HANDLE_PTR phSession)
1119{
1120    size_t i;
1121    INIT_CONTEXT();
1122    st_logf("OpenSession: slot: %d\n", (int)slotID);
1123
1124    if (soft_token.open_sessions == MAX_NUM_SESSION)
1125	return CKR_SESSION_COUNT;
1126
1127    soft_token.application = pApplication;
1128    soft_token.notify = Notify;
1129
1130    for (i = 0; i < MAX_NUM_SESSION; i++)
1131	if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
1132	    break;
1133    if (i == MAX_NUM_SESSION)
1134	abort();
1135
1136    soft_token.open_sessions++;
1137
1138    soft_token.state[i].session_handle =
1139	(CK_SESSION_HANDLE)(random() & 0xfffff);
1140    *phSession = soft_token.state[i].session_handle;
1141
1142    return CKR_OK;
1143}
1144
1145CK_RV
1146C_CloseSession(CK_SESSION_HANDLE hSession)
1147{
1148    struct session_state *state;
1149    INIT_CONTEXT();
1150    st_logf("CloseSession\n");
1151
1152    if (verify_session_handle(hSession, &state) != CKR_OK)
1153	application_error("closed session not open");
1154    else
1155	close_session(state);
1156
1157    return CKR_OK;
1158}
1159
1160CK_RV
1161C_CloseAllSessions(CK_SLOT_ID slotID)
1162{
1163    size_t i;
1164    INIT_CONTEXT();
1165
1166    st_logf("CloseAllSessions\n");
1167
1168    for (i = 0; i < MAX_NUM_SESSION; i++)
1169	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
1170	    close_session(&soft_token.state[i]);
1171
1172    return CKR_OK;
1173}
1174
1175CK_RV
1176C_GetSessionInfo(CK_SESSION_HANDLE hSession,
1177		 CK_SESSION_INFO_PTR pInfo)
1178{
1179    st_logf("GetSessionInfo\n");
1180    INIT_CONTEXT();
1181
1182    VERIFY_SESSION_HANDLE(hSession, NULL);
1183
1184    memset(pInfo, 20, sizeof(*pInfo));
1185
1186    pInfo->slotID = 1;
1187    if (soft_token.flags.login_done)
1188	pInfo->state = CKS_RO_USER_FUNCTIONS;
1189    else
1190	pInfo->state = CKS_RO_PUBLIC_SESSION;
1191    pInfo->flags = CKF_SERIAL_SESSION;
1192    pInfo->ulDeviceError = 0;
1193
1194    return CKR_OK;
1195}
1196
1197CK_RV
1198C_Login(CK_SESSION_HANDLE hSession,
1199	CK_USER_TYPE userType,
1200	CK_UTF8CHAR_PTR pPin,
1201	CK_ULONG ulPinLen)
1202{
1203    char *pin = NULL;
1204    CK_RV ret;
1205    INIT_CONTEXT();
1206
1207    st_logf("Login\n");
1208
1209    VERIFY_SESSION_HANDLE(hSession, NULL);
1210
1211    if (pPin != NULL_PTR) {
1212	asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
1213	st_logf("type: %d password: %s\n", (int)userType, pin);
1214    }
1215
1216    /*
1217     * Login
1218     */
1219
1220    ret = read_conf_file(soft_token.config_file, userType, pin);
1221    if (ret == CKR_OK)
1222	soft_token.flags.login_done = 1;
1223
1224    free(pin);
1225
1226    return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
1227}
1228
1229CK_RV
1230C_Logout(CK_SESSION_HANDLE hSession)
1231{
1232    st_logf("Logout\n");
1233    INIT_CONTEXT();
1234
1235    VERIFY_SESSION_HANDLE(hSession, NULL);
1236    return CKR_FUNCTION_NOT_SUPPORTED;
1237}
1238
1239CK_RV
1240C_GetObjectSize(CK_SESSION_HANDLE hSession,
1241		CK_OBJECT_HANDLE hObject,
1242		CK_ULONG_PTR pulSize)
1243{
1244    st_logf("GetObjectSize\n");
1245    INIT_CONTEXT();
1246
1247    VERIFY_SESSION_HANDLE(hSession, NULL);
1248    return CKR_FUNCTION_NOT_SUPPORTED;
1249}
1250
1251CK_RV
1252C_GetAttributeValue(CK_SESSION_HANDLE hSession,
1253		    CK_OBJECT_HANDLE hObject,
1254		    CK_ATTRIBUTE_PTR pTemplate,
1255		    CK_ULONG ulCount)
1256{
1257    struct session_state *state;
1258    struct st_object *obj;
1259    CK_ULONG i;
1260    CK_RV ret;
1261    int j;
1262
1263    INIT_CONTEXT();
1264
1265    st_logf("GetAttributeValue: %lx\n",
1266	    (unsigned long)HANDLE_OBJECT_ID(hObject));
1267    VERIFY_SESSION_HANDLE(hSession, &state);
1268
1269    if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
1270	st_logf("object not found: %lx\n",
1271		(unsigned long)HANDLE_OBJECT_ID(hObject));
1272	return ret;
1273    }
1274
1275    for (i = 0; i < ulCount; i++) {
1276	st_logf("	getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
1277	for (j = 0; j < obj->num_attributes; j++) {
1278	    if (obj->attrs[j].secret) {
1279		pTemplate[i].ulValueLen = (CK_ULONG)-1;
1280		break;
1281	    }
1282	    if (pTemplate[i].type == obj->attrs[j].attribute.type) {
1283		if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
1284		    if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
1285			memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
1286			       obj->attrs[j].attribute.ulValueLen);
1287		}
1288		pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
1289		break;
1290	    }
1291	}
1292	if (j == obj->num_attributes) {
1293	    st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
1294	    pTemplate[i].ulValueLen = (CK_ULONG)-1;
1295	}
1296
1297    }
1298    return CKR_OK;
1299}
1300
1301CK_RV
1302C_FindObjectsInit(CK_SESSION_HANDLE hSession,
1303		  CK_ATTRIBUTE_PTR pTemplate,
1304		  CK_ULONG ulCount)
1305{
1306    struct session_state *state;
1307
1308    st_logf("FindObjectsInit\n");
1309
1310    INIT_CONTEXT();
1311
1312    VERIFY_SESSION_HANDLE(hSession, &state);
1313
1314    if (state->find.next_object != -1) {
1315	application_error("application didn't do C_FindObjectsFinal\n");
1316	find_object_final(state);
1317    }
1318    if (ulCount) {
1319	CK_ULONG i;
1320
1321	print_attributes(pTemplate, ulCount);
1322
1323	state->find.attributes =
1324	    calloc(1, ulCount * sizeof(state->find.attributes[0]));
1325	if (state->find.attributes == NULL)
1326	    return CKR_DEVICE_MEMORY;
1327	for (i = 0; i < ulCount; i++) {
1328	    state->find.attributes[i].pValue =
1329		malloc(pTemplate[i].ulValueLen);
1330	    if (state->find.attributes[i].pValue == NULL) {
1331		find_object_final(state);
1332		return CKR_DEVICE_MEMORY;
1333	    }
1334	    memcpy(state->find.attributes[i].pValue,
1335		   pTemplate[i].pValue, pTemplate[i].ulValueLen);
1336	    state->find.attributes[i].type = pTemplate[i].type;
1337	    state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
1338	}
1339	state->find.num_attributes = ulCount;
1340	state->find.next_object = 0;
1341    } else {
1342	st_logf("find all objects\n");
1343	state->find.attributes = NULL;
1344	state->find.num_attributes = 0;
1345	state->find.next_object = 0;
1346    }
1347
1348    return CKR_OK;
1349}
1350
1351CK_RV
1352C_FindObjects(CK_SESSION_HANDLE hSession,
1353	      CK_OBJECT_HANDLE_PTR phObject,
1354	      CK_ULONG ulMaxObjectCount,
1355	      CK_ULONG_PTR pulObjectCount)
1356{
1357    struct session_state *state;
1358    int i;
1359
1360    INIT_CONTEXT();
1361
1362    st_logf("FindObjects\n");
1363
1364    VERIFY_SESSION_HANDLE(hSession, &state);
1365
1366    if (state->find.next_object == -1) {
1367	application_error("application didn't do C_FindObjectsInit\n");
1368	return CKR_ARGUMENTS_BAD;
1369    }
1370    if (ulMaxObjectCount == 0) {
1371	application_error("application asked for 0 objects\n");
1372	return CKR_ARGUMENTS_BAD;
1373    }
1374    *pulObjectCount = 0;
1375    for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
1376	st_logf("FindObjects: %d\n", i);
1377	state->find.next_object = i + 1;
1378	if (attributes_match(soft_token.object.objs[i],
1379			     state->find.attributes,
1380			     state->find.num_attributes)) {
1381	    *phObject++ = soft_token.object.objs[i]->object_handle;
1382	    ulMaxObjectCount--;
1383	    (*pulObjectCount)++;
1384	    if (ulMaxObjectCount == 0)
1385		break;
1386	}
1387    }
1388    return CKR_OK;
1389}
1390
1391CK_RV
1392C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1393{
1394    struct session_state *state;
1395
1396    INIT_CONTEXT();
1397
1398    st_logf("FindObjectsFinal\n");
1399    VERIFY_SESSION_HANDLE(hSession, &state);
1400    find_object_final(state);
1401    return CKR_OK;
1402}
1403
1404static CK_RV
1405commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
1406	   const CK_MECHANISM_TYPE *mechs, int mechs_len,
1407	   const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
1408	   struct st_object **o)
1409{
1410    CK_RV ret;
1411    int i;
1412
1413    *o = NULL;
1414    if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
1415	return ret;
1416
1417    ret = attributes_match(*o, attr_match, attr_match_len);
1418    if (!ret) {
1419	application_error("called commonInit on key that doesn't "
1420			  "support required attr");
1421	return CKR_ARGUMENTS_BAD;
1422    }
1423
1424    for (i = 0; i < mechs_len; i++)
1425	if (mechs[i] == pMechanism->mechanism)
1426	    break;
1427    if (i == mechs_len) {
1428	application_error("called mech (%08lx) not supported\n",
1429			  pMechanism->mechanism);
1430	return CKR_ARGUMENTS_BAD;
1431    }
1432    return CKR_OK;
1433}
1434
1435
1436static CK_RV
1437dup_mechanism(CK_MECHANISM_PTR *dp, const CK_MECHANISM_PTR pMechanism)
1438{
1439    CK_MECHANISM_PTR p;
1440
1441    p = malloc(sizeof(*p));
1442    if (p == NULL)
1443	return CKR_DEVICE_MEMORY;
1444
1445    if (*dp)
1446	free(*dp);
1447    *dp = p;
1448    memcpy(p, pMechanism, sizeof(*p));
1449
1450    return CKR_OK;
1451}
1452
1453CK_RV
1454C_DigestInit(CK_SESSION_HANDLE hSession,
1455	     CK_MECHANISM_PTR pMechanism)
1456{
1457    st_logf("DigestInit\n");
1458    INIT_CONTEXT();
1459    VERIFY_SESSION_HANDLE(hSession, NULL);
1460    return CKR_FUNCTION_NOT_SUPPORTED;
1461}
1462
1463CK_RV
1464C_SignInit(CK_SESSION_HANDLE hSession,
1465	   CK_MECHANISM_PTR pMechanism,
1466	   CK_OBJECT_HANDLE hKey)
1467{
1468    struct session_state *state;
1469    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1470    CK_BBOOL bool_true = CK_TRUE;
1471    CK_ATTRIBUTE attr[] = {
1472	{ CKA_SIGN, &bool_true, sizeof(bool_true) }
1473    };
1474    struct st_object *o;
1475    CK_RV ret;
1476
1477    INIT_CONTEXT();
1478    st_logf("SignInit\n");
1479    VERIFY_SESSION_HANDLE(hSession, &state);
1480
1481    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1482		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1483		     pMechanism, hKey, &o);
1484    if (ret)
1485	return ret;
1486
1487    ret = dup_mechanism(&state->sign_mechanism, pMechanism);
1488    if (ret == CKR_OK)
1489	state->sign_object = OBJECT_ID(o);
1490
1491    return CKR_OK;
1492}
1493
1494CK_RV
1495C_Sign(CK_SESSION_HANDLE hSession,
1496       CK_BYTE_PTR pData,
1497       CK_ULONG ulDataLen,
1498       CK_BYTE_PTR pSignature,
1499       CK_ULONG_PTR pulSignatureLen)
1500{
1501    struct session_state *state;
1502    struct st_object *o;
1503    CK_RV ret;
1504    int hret;
1505    const AlgorithmIdentifier *alg;
1506    heim_octet_string sig, data;
1507
1508    INIT_CONTEXT();
1509    st_logf("Sign\n");
1510    VERIFY_SESSION_HANDLE(hSession, &state);
1511
1512    sig.data = NULL;
1513    sig.length = 0;
1514
1515    if (state->sign_object == -1)
1516	return CKR_ARGUMENTS_BAD;
1517
1518    if (pulSignatureLen == NULL) {
1519	st_logf("signature len NULL\n");
1520	ret = CKR_ARGUMENTS_BAD;
1521	goto out;
1522    }
1523
1524    if (pData == NULL_PTR) {
1525	st_logf("data NULL\n");
1526	ret = CKR_ARGUMENTS_BAD;
1527	goto out;
1528    }
1529
1530    o = soft_token.object.objs[state->sign_object];
1531
1532    if (hx509_cert_have_private_key(o->cert) == 0) {
1533	st_logf("private key NULL\n");
1534	return CKR_ARGUMENTS_BAD;
1535    }
1536
1537    switch(state->sign_mechanism->mechanism) {
1538    case CKM_RSA_PKCS:
1539	alg = hx509_signature_rsa_pkcs1_x509();
1540	break;
1541    default:
1542	ret = CKR_FUNCTION_NOT_SUPPORTED;
1543	goto out;
1544    }
1545
1546    data.data = pData;
1547    data.length = ulDataLen;
1548
1549    hret = _hx509_create_signature(context,
1550				   _hx509_cert_private_key(o->cert),
1551				   alg,
1552				   &data,
1553				   NULL,
1554				   &sig);
1555    if (hret) {
1556	ret = CKR_DEVICE_ERROR;
1557	goto out;
1558    }
1559    *pulSignatureLen = sig.length;
1560
1561    if (pSignature != NULL_PTR)
1562	memcpy(pSignature, sig.data, sig.length);
1563
1564    ret = CKR_OK;
1565 out:
1566    if (sig.data) {
1567	memset(sig.data, 0, sig.length);
1568	der_free_octet_string(&sig);
1569    }
1570    return ret;
1571}
1572
1573CK_RV
1574C_SignUpdate(CK_SESSION_HANDLE hSession,
1575	     CK_BYTE_PTR pPart,
1576	     CK_ULONG ulPartLen)
1577{
1578    INIT_CONTEXT();
1579    st_logf("SignUpdate\n");
1580    VERIFY_SESSION_HANDLE(hSession, NULL);
1581    return CKR_FUNCTION_NOT_SUPPORTED;
1582}
1583
1584
1585CK_RV
1586C_SignFinal(CK_SESSION_HANDLE hSession,
1587	    CK_BYTE_PTR pSignature,
1588	    CK_ULONG_PTR pulSignatureLen)
1589{
1590    INIT_CONTEXT();
1591    st_logf("SignUpdate\n");
1592    VERIFY_SESSION_HANDLE(hSession, NULL);
1593    return CKR_FUNCTION_NOT_SUPPORTED;
1594}
1595
1596CK_RV
1597C_VerifyInit(CK_SESSION_HANDLE hSession,
1598	     CK_MECHANISM_PTR pMechanism,
1599	     CK_OBJECT_HANDLE hKey)
1600{
1601    struct session_state *state;
1602    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1603    CK_BBOOL bool_true = CK_TRUE;
1604    CK_ATTRIBUTE attr[] = {
1605	{ CKA_VERIFY, &bool_true, sizeof(bool_true) }
1606    };
1607    struct st_object *o;
1608    CK_RV ret;
1609
1610    INIT_CONTEXT();
1611    st_logf("VerifyInit\n");
1612    VERIFY_SESSION_HANDLE(hSession, &state);
1613
1614    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1615		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1616		     pMechanism, hKey, &o);
1617    if (ret)
1618	return ret;
1619
1620    ret = dup_mechanism(&state->verify_mechanism, pMechanism);
1621    if (ret == CKR_OK)
1622	state->verify_object = OBJECT_ID(o);
1623
1624    return ret;
1625}
1626
1627CK_RV
1628C_Verify(CK_SESSION_HANDLE hSession,
1629	 CK_BYTE_PTR pData,
1630	 CK_ULONG ulDataLen,
1631	 CK_BYTE_PTR pSignature,
1632	 CK_ULONG ulSignatureLen)
1633{
1634    struct session_state *state;
1635    struct st_object *o;
1636    const AlgorithmIdentifier *alg;
1637    CK_RV ret;
1638    int hret;
1639    heim_octet_string data, sig;
1640
1641    INIT_CONTEXT();
1642    st_logf("Verify\n");
1643    VERIFY_SESSION_HANDLE(hSession, &state);
1644
1645    if (state->verify_object == -1)
1646	return CKR_ARGUMENTS_BAD;
1647
1648    o = soft_token.object.objs[state->verify_object];
1649
1650    switch(state->verify_mechanism->mechanism) {
1651    case CKM_RSA_PKCS:
1652	alg = hx509_signature_rsa_pkcs1_x509();
1653	break;
1654    default:
1655	ret = CKR_FUNCTION_NOT_SUPPORTED;
1656	goto out;
1657    }
1658
1659    sig.data = pData;
1660    sig.length = ulDataLen;
1661    data.data = pSignature;
1662    data.length = ulSignatureLen;
1663
1664    hret = _hx509_verify_signature(context,
1665				   o->cert,
1666				   alg,
1667				   &data,
1668				   &sig);
1669    if (hret) {
1670	ret = CKR_GENERAL_ERROR;
1671	goto out;
1672    }
1673    ret = CKR_OK;
1674
1675 out:
1676    return ret;
1677}
1678
1679
1680CK_RV
1681C_VerifyUpdate(CK_SESSION_HANDLE hSession,
1682	       CK_BYTE_PTR pPart,
1683	       CK_ULONG ulPartLen)
1684{
1685    INIT_CONTEXT();
1686    st_logf("VerifyUpdate\n");
1687    VERIFY_SESSION_HANDLE(hSession, NULL);
1688    return CKR_FUNCTION_NOT_SUPPORTED;
1689}
1690
1691CK_RV
1692C_VerifyFinal(CK_SESSION_HANDLE hSession,
1693	      CK_BYTE_PTR pSignature,
1694	      CK_ULONG ulSignatureLen)
1695{
1696    INIT_CONTEXT();
1697    st_logf("VerifyFinal\n");
1698    VERIFY_SESSION_HANDLE(hSession, NULL);
1699    return CKR_FUNCTION_NOT_SUPPORTED;
1700}
1701
1702CK_RV
1703C_GenerateRandom(CK_SESSION_HANDLE hSession,
1704		 CK_BYTE_PTR RandomData,
1705		 CK_ULONG ulRandomLen)
1706{
1707    INIT_CONTEXT();
1708    st_logf("GenerateRandom\n");
1709    VERIFY_SESSION_HANDLE(hSession, NULL);
1710    return CKR_FUNCTION_NOT_SUPPORTED;
1711}
1712
1713
1714CK_FUNCTION_LIST funcs = {
1715    { 2, 11 },
1716    C_Initialize,
1717    C_Finalize,
1718    C_GetInfo,
1719    C_GetFunctionList,
1720    C_GetSlotList,
1721    C_GetSlotInfo,
1722    C_GetTokenInfo,
1723    C_GetMechanismList,
1724    C_GetMechanismInfo,
1725    C_InitToken,
1726    (void *)func_not_supported, /* C_InitPIN */
1727    (void *)func_not_supported, /* C_SetPIN */
1728    C_OpenSession,
1729    C_CloseSession,
1730    C_CloseAllSessions,
1731    C_GetSessionInfo,
1732    (void *)func_not_supported, /* C_GetOperationState */
1733    (void *)func_not_supported, /* C_SetOperationState */
1734    C_Login,
1735    C_Logout,
1736    (void *)func_not_supported, /* C_CreateObject */
1737    (void *)func_not_supported, /* C_CopyObject */
1738    (void *)func_not_supported, /* C_DestroyObject */
1739    (void *)func_not_supported, /* C_GetObjectSize */
1740    C_GetAttributeValue,
1741    (void *)func_not_supported, /* C_SetAttributeValue */
1742    C_FindObjectsInit,
1743    C_FindObjects,
1744    C_FindObjectsFinal,
1745    (void *)func_not_supported, /* C_EncryptInit, */
1746    (void *)func_not_supported, /* C_Encrypt, */
1747    (void *)func_not_supported, /* C_EncryptUpdate, */
1748    (void *)func_not_supported, /* C_EncryptFinal, */
1749    (void *)func_not_supported, /* C_DecryptInit, */
1750    (void *)func_not_supported, /* C_Decrypt, */
1751    (void *)func_not_supported, /* C_DecryptUpdate, */
1752    (void *)func_not_supported, /* C_DecryptFinal, */
1753    C_DigestInit,
1754    (void *)func_not_supported, /* C_Digest */
1755    (void *)func_not_supported, /* C_DigestUpdate */
1756    (void *)func_not_supported, /* C_DigestKey */
1757    (void *)func_not_supported, /* C_DigestFinal */
1758    C_SignInit,
1759    C_Sign,
1760    C_SignUpdate,
1761    C_SignFinal,
1762    (void *)func_not_supported, /* C_SignRecoverInit */
1763    (void *)func_not_supported, /* C_SignRecover */
1764    C_VerifyInit,
1765    C_Verify,
1766    C_VerifyUpdate,
1767    C_VerifyFinal,
1768    (void *)func_not_supported, /* C_VerifyRecoverInit */
1769    (void *)func_not_supported, /* C_VerifyRecover */
1770    (void *)func_not_supported, /* C_DigestEncryptUpdate */
1771    (void *)func_not_supported, /* C_DecryptDigestUpdate */
1772    (void *)func_not_supported, /* C_SignEncryptUpdate */
1773    (void *)func_not_supported, /* C_DecryptVerifyUpdate */
1774    (void *)func_not_supported, /* C_GenerateKey */
1775    (void *)func_not_supported, /* C_GenerateKeyPair */
1776    (void *)func_not_supported, /* C_WrapKey */
1777    (void *)func_not_supported, /* C_UnwrapKey */
1778    (void *)func_not_supported, /* C_DeriveKey */
1779    (void *)func_not_supported, /* C_SeedRandom */
1780    C_GenerateRandom,
1781    (void *)func_not_supported, /* C_GetFunctionStatus */
1782    (void *)func_not_supported, /* C_CancelFunction */
1783    (void *)func_not_supported  /* C_WaitForSlotEvent */
1784};
1785