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    i = o->num_attributes;
346    a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0]));
347    if (a == NULL)
348	return CKR_DEVICE_MEMORY;
349    o->attrs = a;
350    o->attrs[i].secret = secret;
351    o->attrs[i].attribute.type = type;
352    o->attrs[i].attribute.pValue = malloc(ulValueLen);
353    if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0)
354	return CKR_DEVICE_MEMORY;
355    memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen);
356    o->attrs[i].attribute.ulValueLen = ulValueLen;
357    o->num_attributes++;
358
359    return CKR_OK;
360}
361
362static CK_RV
363add_pubkey_info(hx509_context hxctx, struct st_object *o,
364		CK_KEY_TYPE key_type, hx509_cert cert)
365{
366    BIGNUM *num;
367    CK_BYTE *modulus = NULL;
368    size_t modulus_len = 0;
369    CK_ULONG modulus_bits = 0;
370    CK_BYTE *exponent = NULL;
371    size_t exponent_len = 0;
372
373    if (key_type != CKK_RSA)
374	return CKR_OK;
375    if (_hx509_cert_private_key(cert) == NULL)
376	return CKR_OK;
377
378    num = _hx509_private_key_get_internal(context,
379					  _hx509_cert_private_key(cert),
380					  "rsa-modulus");
381    if (num == NULL)
382	return CKR_GENERAL_ERROR;
383    modulus_bits = BN_num_bits(num);
384
385    modulus_len = BN_num_bytes(num);
386    modulus = malloc(modulus_len);
387    BN_bn2bin(num, modulus);
388    BN_free(num);
389
390    add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
391    add_object_attribute(o, 0, CKA_MODULUS_BITS,
392			 &modulus_bits, sizeof(modulus_bits));
393
394    free(modulus);
395
396    num = _hx509_private_key_get_internal(context,
397					  _hx509_cert_private_key(cert),
398					  "rsa-exponent");
399    if (num == NULL)
400	return CKR_GENERAL_ERROR;
401
402    exponent_len = BN_num_bytes(num);
403    exponent = malloc(exponent_len);
404    BN_bn2bin(num, exponent);
405    BN_free(num);
406
407    add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
408			 exponent, exponent_len);
409
410    free(exponent);
411
412    return CKR_OK;
413}
414
415
416struct foo {
417    char *label;
418    char *id;
419};
420
421static int
422add_cert(hx509_context hxctx, void *ctx, hx509_cert cert)
423{
424    static char empty[] = "";
425    struct foo *foo = (struct foo *)ctx;
426    struct st_object *o = NULL;
427    CK_OBJECT_CLASS type;
428    CK_BBOOL bool_true = CK_TRUE;
429    CK_BBOOL bool_false = CK_FALSE;
430    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
431    CK_KEY_TYPE key_type;
432    CK_MECHANISM_TYPE mech_type;
433    CK_RV ret = CKR_GENERAL_ERROR;
434    int hret;
435    heim_octet_string cert_data, subject_data, issuer_data, serial_data;
436
437    st_logf("adding certificate\n");
438
439    serial_data.data = NULL;
440    serial_data.length = 0;
441    cert_data = subject_data = issuer_data = serial_data;
442
443    hret = hx509_cert_binary(hxctx, cert, &cert_data);
444    if (hret)
445	goto out;
446
447    {
448	    hx509_name name;
449
450	    hret = hx509_cert_get_issuer(cert, &name);
451	    if (hret)
452		goto out;
453	    hret = hx509_name_binary(name, &issuer_data);
454	    hx509_name_free(&name);
455	    if (hret)
456		goto out;
457
458	    hret = hx509_cert_get_subject(cert, &name);
459	    if (hret)
460		goto out;
461	    hret = hx509_name_binary(name, &subject_data);
462	    hx509_name_free(&name);
463	    if (hret)
464		goto out;
465    }
466
467    {
468	AlgorithmIdentifier alg;
469
470	hret = hx509_cert_get_SPKI_AlgorithmIdentifier(context, cert, &alg);
471	if (hret) {
472	    ret = CKR_DEVICE_MEMORY;
473	    goto out;
474	}
475
476	key_type = CKK_RSA; /* XXX */
477
478	free_AlgorithmIdentifier(&alg);
479    }
480
481
482    type = CKO_CERTIFICATE;
483    o = add_st_object();
484    if (o == NULL) {
485	ret = CKR_DEVICE_MEMORY;
486	goto out;
487    }
488
489    o->cert = hx509_cert_ref(cert);
490
491    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
492    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
493    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
494    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
495    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
496
497    add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
498    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
499
500    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
501    add_object_attribute(o, 0, CKA_ISSUER, issuer_data.data, issuer_data.length);
502    add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data.data, serial_data.length);
503    add_object_attribute(o, 0, CKA_VALUE, cert_data.data, cert_data.length);
504    add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));
505
506    st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));
507
508    type = CKO_PUBLIC_KEY;
509    o = add_st_object();
510    if (o == NULL) {
511	ret = CKR_DEVICE_MEMORY;
512	goto out;
513    }
514    o->cert = hx509_cert_ref(cert);
515
516    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
517    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
518    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
519    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
520    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
521
522    add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
523    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
524    add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
525    add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
526    add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
527    add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
528    mech_type = CKM_RSA_X_509;
529    add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
530
531    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
532    add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
533    add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
534    add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
535    add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
536    add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
537
538    add_pubkey_info(hxctx, o, key_type, cert);
539
540    st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));
541
542    if (hx509_cert_have_private_key(cert)) {
543	CK_FLAGS flags;
544
545	type = CKO_PRIVATE_KEY;
546	o = add_st_object();
547	if (o == NULL) {
548	    ret = CKR_DEVICE_MEMORY;
549	    goto out;
550	}
551	o->cert = hx509_cert_ref(cert);
552
553	add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
554	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
555	add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
556	add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
557	add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
558
559	add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
560	add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
561	add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
562	add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
563	add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
564	add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
565	mech_type = CKM_RSA_X_509;
566	add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
567
568	add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
569	add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
570	add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
571	flags = 0;
572	add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));
573
574	add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
575	add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
576	add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
577	add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
578	add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
579	add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));
580
581	add_pubkey_info(hxctx, o, key_type, cert);
582    }
583
584    ret = CKR_OK;
585 out:
586    if (ret != CKR_OK) {
587	st_logf("something went wrong when adding cert!\n");
588
589	/* XXX wack o */;
590    }
591    hx509_xfree(cert_data.data);
592    hx509_xfree(serial_data.data);
593    hx509_xfree(issuer_data.data);
594    hx509_xfree(subject_data.data);
595
596    return 0;
597}
598
599static CK_RV
600add_certificate(const char *cert_file,
601		const char *pin,
602		char *id,
603		char *label)
604{
605    hx509_certs certs;
606    hx509_lock lock = NULL;
607    int ret, flags = 0;
608
609    struct foo foo;
610    foo.id = id;
611    foo.label = label;
612
613    if (pin == NULL)
614	flags |= HX509_CERTS_UNPROTECT_ALL;
615
616    if (pin) {
617	char *str;
618	asprintf(&str, "PASS:%s", pin);
619
620	hx509_lock_init(context, &lock);
621	hx509_lock_command_string(lock, str);
622
623	memset(str, 0, strlen(str));
624	free(str);
625    }
626
627    ret = hx509_certs_init(context, cert_file, flags, lock, &certs);
628    if (ret) {
629	st_logf("failed to open file %s\n", cert_file);
630	return CKR_GENERAL_ERROR;
631    }
632
633    ret = hx509_certs_iter_f(context, certs, add_cert, &foo);
634    hx509_certs_free(&certs);
635    if (ret) {
636	st_logf("failed adding certs from file %s\n", cert_file);
637	return CKR_GENERAL_ERROR;
638    }
639
640    return CKR_OK;
641}
642
643static void
644find_object_final(struct session_state *state)
645{
646    if (state->find.attributes) {
647	CK_ULONG i;
648
649	for (i = 0; i < state->find.num_attributes; i++) {
650	    if (state->find.attributes[i].pValue)
651		free(state->find.attributes[i].pValue);
652	}
653	free(state->find.attributes);
654	state->find.attributes = NULL;
655	state->find.num_attributes = 0;
656	state->find.next_object = -1;
657    }
658}
659
660static void
661reset_crypto_state(struct session_state *state)
662{
663    state->sign_object = -1;
664    if (state->sign_mechanism)
665	free(state->sign_mechanism);
666    state->sign_mechanism = NULL_PTR;
667    state->verify_object = -1;
668    if (state->verify_mechanism)
669	free(state->verify_mechanism);
670    state->verify_mechanism = NULL_PTR;
671}
672
673static void
674close_session(struct session_state *state)
675{
676    if (state->find.attributes) {
677	application_error("application didn't do C_FindObjectsFinal\n");
678	find_object_final(state);
679    }
680
681    state->session_handle = CK_INVALID_HANDLE;
682    soft_token.application = NULL_PTR;
683    soft_token.notify = NULL_PTR;
684    reset_crypto_state(state);
685}
686
687static const char *
688has_session(void)
689{
690    return soft_token.open_sessions > 0 ? "yes" : "no";
691}
692
693static CK_RV
694read_conf_file(const char *fn, CK_USER_TYPE userType, const char *pin)
695{
696    char buf[1024], *type, *s, *p;
697    FILE *f;
698    CK_RV ret = CKR_OK;
699    CK_RV failed = CKR_OK;
700
701    if (fn == NULL) {
702        st_logf("Can't open configuration file.  No file specified\n");
703        return CKR_GENERAL_ERROR;
704    }
705
706    f = fopen(fn, "r");
707    if (f == NULL) {
708	st_logf("can't open configuration file %s\n", fn);
709	return CKR_GENERAL_ERROR;
710    }
711    rk_cloexec_file(f);
712
713    while(fgets(buf, sizeof(buf), f) != NULL) {
714	buf[strcspn(buf, "\n")] = '\0';
715
716	st_logf("line: %s\n", buf);
717
718	p = buf;
719	while (isspace((unsigned char)*p))
720	    p++;
721	if (*p == '#')
722	    continue;
723	while (isspace((unsigned char)*p))
724	    p++;
725
726	s = NULL;
727	type = strtok_r(p, "\t", &s);
728	if (type == NULL)
729	    continue;
730
731	if (strcasecmp("certificate", type) == 0) {
732	    char *cert, *id, *label;
733
734	    id = strtok_r(NULL, "\t", &s);
735	    if (id == NULL) {
736		st_logf("no id\n");
737		continue;
738	    }
739	    st_logf("id: %s\n", id);
740	    label = strtok_r(NULL, "\t", &s);
741	    if (label == NULL) {
742		st_logf("no label\n");
743		continue;
744	    }
745	    cert = strtok_r(NULL, "\t", &s);
746	    if (cert == NULL) {
747		st_logf("no certfiicate store\n");
748		continue;
749	    }
750
751	    st_logf("adding: %s: %s in file %s\n", id, label, cert);
752
753	    ret = add_certificate(cert, pin, id, label);
754	    if (ret)
755		failed = ret;
756	} else if (strcasecmp("debug", type) == 0) {
757	    char *name;
758
759	    name = strtok_r(NULL, "\t", &s);
760	    if (name == NULL) {
761		st_logf("no filename\n");
762		continue;
763	    }
764
765	    if (soft_token.logfile)
766		fclose(soft_token.logfile);
767
768	    if (strcasecmp(name, "stdout") == 0)
769		soft_token.logfile = stdout;
770	    else {
771		soft_token.logfile = fopen(name, "a");
772		if (soft_token.logfile)
773		    rk_cloexec_file(soft_token.logfile);
774	    }
775	    if (soft_token.logfile == NULL)
776		st_logf("failed to open file: %s\n", name);
777
778	} else if (strcasecmp("app-fatal", type) == 0) {
779	    char *name;
780
781	    name = strtok_r(NULL, "\t", &s);
782	    if (name == NULL) {
783		st_logf("argument to app-fatal\n");
784		continue;
785	    }
786
787	    if (strcmp(name, "true") == 0 || strcmp(name, "on") == 0)
788		soft_token.flags.app_error_fatal = 1;
789	    else if (strcmp(name, "false") == 0 || strcmp(name, "off") == 0)
790		soft_token.flags.app_error_fatal = 0;
791	    else
792		st_logf("unknown app-fatal: %s\n", name);
793
794	} else {
795	    st_logf("unknown type: %s\n", type);
796	}
797    }
798
799    fclose(f);
800
801    return failed;
802}
803
804static CK_RV
805func_not_supported(void)
806{
807    st_logf("function not supported\n");
808    return CKR_FUNCTION_NOT_SUPPORTED;
809}
810
811static char *
812get_config_file_for_user(void)
813{
814    char *fn = NULL;
815
816#ifndef _WIN32
817    char *home = NULL;
818
819    if (!issuid()) {
820        fn = getenv("SOFTPKCS11RC");
821        if (fn)
822            fn = strdup(fn);
823        home = getenv("HOME");
824    }
825    if (fn == NULL && home == NULL) {
826        struct passwd *pw = getpwuid(getuid());
827        if(pw != NULL)
828            home = pw->pw_dir;
829    }
830    if (fn == NULL) {
831        if (home)
832            asprintf(&fn, "%s/.soft-token.rc", home);
833        else
834            fn = strdup("/etc/soft-token.rc");
835    }
836#else  /* Windows */
837
838    char appdatafolder[MAX_PATH];
839
840    fn = getenv("SOFTPKCS11RC");
841
842    /* Retrieve the roaming AppData folder for the current user.  The
843       current user is the user account represented by the current
844       thread token. */
845
846    if (fn == NULL &&
847        SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatafolder))) {
848
849        asprintf(&fn, "%s\\.soft-token.rc", appdatafolder);
850    }
851
852#endif  /* _WIN32 */
853
854    return fn;
855}
856
857
858CK_RV CK_SPEC
859C_Initialize(CK_VOID_PTR a)
860{
861    CK_C_INITIALIZE_ARGS_PTR args = a;
862    CK_RV ret;
863    size_t i;
864
865    st_logf("Initialize\n");
866
867    INIT_CONTEXT();
868
869    OpenSSL_add_all_algorithms();
870
871    srandom(getpid() ^ (int) time(NULL));
872
873    for (i = 0; i < MAX_NUM_SESSION; i++) {
874	soft_token.state[i].session_handle = CK_INVALID_HANDLE;
875	soft_token.state[i].find.attributes = NULL;
876	soft_token.state[i].find.num_attributes = 0;
877	soft_token.state[i].find.next_object = -1;
878	reset_crypto_state(&soft_token.state[i]);
879    }
880
881    soft_token.flags.hardware_slot = 1;
882    soft_token.flags.app_error_fatal = 0;
883    soft_token.flags.login_done = 0;
884
885    soft_token.object.objs = NULL;
886    soft_token.object.num_objs = 0;
887
888    soft_token.logfile = NULL;
889#if 0
890    soft_token.logfile = stdout;
891#endif
892#if 0
893    soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
894#endif
895
896    if (a != NULL_PTR) {
897	st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
898	st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
899	st_logf("\tLockMutext\t%p\n", args->LockMutex);
900	st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
901	st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
902    }
903
904    soft_token.config_file = get_config_file_for_user();
905
906    /*
907     * This operations doesn't return CKR_OK if any of the
908     * certificates failes to be unparsed (ie password protected).
909     */
910    ret = read_conf_file(soft_token.config_file, CKU_USER, NULL);
911    if (ret == CKR_OK)
912	soft_token.flags.login_done = 1;
913
914    return CKR_OK;
915}
916
917CK_RV
918C_Finalize(CK_VOID_PTR args)
919{
920    size_t i;
921
922    INIT_CONTEXT();
923
924    st_logf("Finalize\n");
925
926    for (i = 0; i < MAX_NUM_SESSION; i++) {
927	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
928	    application_error("application finalized without "
929			      "closing session\n");
930	    close_session(&soft_token.state[i]);
931	}
932    }
933
934    return CKR_OK;
935}
936
937CK_RV
938C_GetInfo(CK_INFO_PTR args)
939{
940    INIT_CONTEXT();
941
942    st_logf("GetInfo\n");
943
944    memset(args, 17, sizeof(*args));
945    args->cryptokiVersion.major = 2;
946    args->cryptokiVersion.minor = 10;
947    snprintf_fill((char *)args->manufacturerID,
948		  sizeof(args->manufacturerID),
949		  ' ',
950		  "Heimdal hx509 SoftToken");
951    snprintf_fill((char *)args->libraryDescription,
952		  sizeof(args->libraryDescription), ' ',
953		  "Heimdal hx509 SoftToken");
954    args->libraryVersion.major = 2;
955    args->libraryVersion.minor = 0;
956
957    return CKR_OK;
958}
959
960extern CK_FUNCTION_LIST funcs;
961
962CK_RV
963C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
964{
965    INIT_CONTEXT();
966
967    *ppFunctionList = &funcs;
968    return CKR_OK;
969}
970
971CK_RV
972C_GetSlotList(CK_BBOOL tokenPresent,
973	      CK_SLOT_ID_PTR pSlotList,
974	      CK_ULONG_PTR   pulCount)
975{
976    INIT_CONTEXT();
977    st_logf("GetSlotList: %s\n",
978	    tokenPresent ? "tokenPresent" : "token not Present");
979    if (pSlotList)
980	pSlotList[0] = 1;
981    *pulCount = 1;
982    return CKR_OK;
983}
984
985CK_RV
986C_GetSlotInfo(CK_SLOT_ID slotID,
987	      CK_SLOT_INFO_PTR pInfo)
988{
989    INIT_CONTEXT();
990    st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
991
992    memset(pInfo, 18, sizeof(*pInfo));
993
994    if (slotID != 1)
995	return CKR_ARGUMENTS_BAD;
996
997    snprintf_fill((char *)pInfo->slotDescription,
998		  sizeof(pInfo->slotDescription),
999		  ' ',
1000		  "Heimdal hx509 SoftToken (slot)");
1001    snprintf_fill((char *)pInfo->manufacturerID,
1002		  sizeof(pInfo->manufacturerID),
1003		  ' ',
1004		  "Heimdal hx509 SoftToken (slot)");
1005    pInfo->flags = CKF_TOKEN_PRESENT;
1006    if (soft_token.flags.hardware_slot)
1007	pInfo->flags |= CKF_HW_SLOT;
1008    pInfo->hardwareVersion.major = 1;
1009    pInfo->hardwareVersion.minor = 0;
1010    pInfo->firmwareVersion.major = 1;
1011    pInfo->firmwareVersion.minor = 0;
1012
1013    return CKR_OK;
1014}
1015
1016CK_RV
1017C_GetTokenInfo(CK_SLOT_ID slotID,
1018	       CK_TOKEN_INFO_PTR pInfo)
1019{
1020    INIT_CONTEXT();
1021    st_logf("GetTokenInfo: %s\n", has_session());
1022
1023    memset(pInfo, 19, sizeof(*pInfo));
1024
1025    snprintf_fill((char *)pInfo->label,
1026		  sizeof(pInfo->label),
1027		  ' ',
1028		  "Heimdal hx509 SoftToken (token)");
1029    snprintf_fill((char *)pInfo->manufacturerID,
1030		  sizeof(pInfo->manufacturerID),
1031		  ' ',
1032		  "Heimdal hx509 SoftToken (token)");
1033    snprintf_fill((char *)pInfo->model,
1034		  sizeof(pInfo->model),
1035		  ' ',
1036		  "Heimdal hx509 SoftToken (token)");
1037    snprintf_fill((char *)pInfo->serialNumber,
1038		  sizeof(pInfo->serialNumber),
1039		  ' ',
1040		  "4711");
1041    pInfo->flags =
1042	CKF_TOKEN_INITIALIZED |
1043	CKF_USER_PIN_INITIALIZED;
1044
1045    if (soft_token.flags.login_done == 0)
1046	pInfo->flags |= CKF_LOGIN_REQUIRED;
1047
1048    /* CFK_RNG |
1049       CKF_RESTORE_KEY_NOT_NEEDED |
1050    */
1051    pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
1052    pInfo->ulSessionCount = soft_token.open_sessions;
1053    pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
1054    pInfo->ulRwSessionCount = soft_token.open_sessions;
1055    pInfo->ulMaxPinLen = 1024;
1056    pInfo->ulMinPinLen = 0;
1057    pInfo->ulTotalPublicMemory = 4711;
1058    pInfo->ulFreePublicMemory = 4712;
1059    pInfo->ulTotalPrivateMemory = 4713;
1060    pInfo->ulFreePrivateMemory = 4714;
1061    pInfo->hardwareVersion.major = 2;
1062    pInfo->hardwareVersion.minor = 0;
1063    pInfo->firmwareVersion.major = 2;
1064    pInfo->firmwareVersion.minor = 0;
1065
1066    return CKR_OK;
1067}
1068
1069CK_RV
1070C_GetMechanismList(CK_SLOT_ID slotID,
1071		   CK_MECHANISM_TYPE_PTR pMechanismList,
1072		   CK_ULONG_PTR pulCount)
1073{
1074    INIT_CONTEXT();
1075    st_logf("GetMechanismList\n");
1076
1077    *pulCount = 1;
1078    if (pMechanismList == NULL_PTR)
1079	return CKR_OK;
1080    pMechanismList[1] = CKM_RSA_PKCS;
1081
1082    return CKR_OK;
1083}
1084
1085CK_RV
1086C_GetMechanismInfo(CK_SLOT_ID slotID,
1087		   CK_MECHANISM_TYPE type,
1088		   CK_MECHANISM_INFO_PTR pInfo)
1089{
1090    INIT_CONTEXT();
1091    st_logf("GetMechanismInfo: slot %d type: %d\n",
1092	    (int)slotID, (int)type);
1093    memset(pInfo, 0, sizeof(*pInfo));
1094
1095    return CKR_OK;
1096}
1097
1098CK_RV
1099C_InitToken(CK_SLOT_ID slotID,
1100	    CK_UTF8CHAR_PTR pPin,
1101	    CK_ULONG ulPinLen,
1102	    CK_UTF8CHAR_PTR pLabel)
1103{
1104    INIT_CONTEXT();
1105    st_logf("InitToken: slot %d\n", (int)slotID);
1106    return CKR_FUNCTION_NOT_SUPPORTED;
1107}
1108
1109CK_RV
1110C_OpenSession(CK_SLOT_ID slotID,
1111	      CK_FLAGS flags,
1112	      CK_VOID_PTR pApplication,
1113	      CK_NOTIFY Notify,
1114	      CK_SESSION_HANDLE_PTR phSession)
1115{
1116    size_t i;
1117    INIT_CONTEXT();
1118    st_logf("OpenSession: slot: %d\n", (int)slotID);
1119
1120    if (soft_token.open_sessions == MAX_NUM_SESSION)
1121	return CKR_SESSION_COUNT;
1122
1123    soft_token.application = pApplication;
1124    soft_token.notify = Notify;
1125
1126    for (i = 0; i < MAX_NUM_SESSION; i++)
1127	if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
1128	    break;
1129    if (i == MAX_NUM_SESSION)
1130	abort();
1131
1132    soft_token.open_sessions++;
1133
1134    soft_token.state[i].session_handle =
1135	(CK_SESSION_HANDLE)(random() & 0xfffff);
1136    *phSession = soft_token.state[i].session_handle;
1137
1138    return CKR_OK;
1139}
1140
1141CK_RV
1142C_CloseSession(CK_SESSION_HANDLE hSession)
1143{
1144    struct session_state *state;
1145    INIT_CONTEXT();
1146    st_logf("CloseSession\n");
1147
1148    if (verify_session_handle(hSession, &state) != CKR_OK)
1149	application_error("closed session not open");
1150    else
1151	close_session(state);
1152
1153    return CKR_OK;
1154}
1155
1156CK_RV
1157C_CloseAllSessions(CK_SLOT_ID slotID)
1158{
1159    size_t i;
1160    INIT_CONTEXT();
1161
1162    st_logf("CloseAllSessions\n");
1163
1164    for (i = 0; i < MAX_NUM_SESSION; i++)
1165	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
1166	    close_session(&soft_token.state[i]);
1167
1168    return CKR_OK;
1169}
1170
1171CK_RV
1172C_GetSessionInfo(CK_SESSION_HANDLE hSession,
1173		 CK_SESSION_INFO_PTR pInfo)
1174{
1175    st_logf("GetSessionInfo\n");
1176    INIT_CONTEXT();
1177
1178    VERIFY_SESSION_HANDLE(hSession, NULL);
1179
1180    memset(pInfo, 20, sizeof(*pInfo));
1181
1182    pInfo->slotID = 1;
1183    if (soft_token.flags.login_done)
1184	pInfo->state = CKS_RO_USER_FUNCTIONS;
1185    else
1186	pInfo->state = CKS_RO_PUBLIC_SESSION;
1187    pInfo->flags = CKF_SERIAL_SESSION;
1188    pInfo->ulDeviceError = 0;
1189
1190    return CKR_OK;
1191}
1192
1193CK_RV
1194C_Login(CK_SESSION_HANDLE hSession,
1195	CK_USER_TYPE userType,
1196	CK_UTF8CHAR_PTR pPin,
1197	CK_ULONG ulPinLen)
1198{
1199    char *pin = NULL;
1200    CK_RV ret;
1201    INIT_CONTEXT();
1202
1203    st_logf("Login\n");
1204
1205    VERIFY_SESSION_HANDLE(hSession, NULL);
1206
1207    if (pPin != NULL_PTR) {
1208	asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
1209	st_logf("type: %d password: %s\n", (int)userType, pin);
1210    }
1211
1212    /*
1213     * Login
1214     */
1215
1216    ret = read_conf_file(soft_token.config_file, userType, pin);
1217    if (ret == CKR_OK)
1218	soft_token.flags.login_done = 1;
1219
1220    free(pin);
1221
1222    return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
1223}
1224
1225CK_RV
1226C_Logout(CK_SESSION_HANDLE hSession)
1227{
1228    st_logf("Logout\n");
1229    INIT_CONTEXT();
1230
1231    VERIFY_SESSION_HANDLE(hSession, NULL);
1232    return CKR_FUNCTION_NOT_SUPPORTED;
1233}
1234
1235CK_RV
1236C_GetObjectSize(CK_SESSION_HANDLE hSession,
1237		CK_OBJECT_HANDLE hObject,
1238		CK_ULONG_PTR pulSize)
1239{
1240    st_logf("GetObjectSize\n");
1241    INIT_CONTEXT();
1242
1243    VERIFY_SESSION_HANDLE(hSession, NULL);
1244    return CKR_FUNCTION_NOT_SUPPORTED;
1245}
1246
1247CK_RV
1248C_GetAttributeValue(CK_SESSION_HANDLE hSession,
1249		    CK_OBJECT_HANDLE hObject,
1250		    CK_ATTRIBUTE_PTR pTemplate,
1251		    CK_ULONG ulCount)
1252{
1253    struct session_state *state;
1254    struct st_object *obj;
1255    CK_ULONG i;
1256    CK_RV ret;
1257    int j;
1258
1259    INIT_CONTEXT();
1260
1261    st_logf("GetAttributeValue: %lx\n",
1262	    (unsigned long)HANDLE_OBJECT_ID(hObject));
1263    VERIFY_SESSION_HANDLE(hSession, &state);
1264
1265    if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
1266	st_logf("object not found: %lx\n",
1267		(unsigned long)HANDLE_OBJECT_ID(hObject));
1268	return ret;
1269    }
1270
1271    for (i = 0; i < ulCount; i++) {
1272	st_logf("	getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
1273	for (j = 0; j < obj->num_attributes; j++) {
1274	    if (obj->attrs[j].secret) {
1275		pTemplate[i].ulValueLen = (CK_ULONG)-1;
1276		break;
1277	    }
1278	    if (pTemplate[i].type == obj->attrs[j].attribute.type) {
1279		if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
1280		    if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
1281			memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
1282			       obj->attrs[j].attribute.ulValueLen);
1283		}
1284		pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
1285		break;
1286	    }
1287	}
1288	if (j == obj->num_attributes) {
1289	    st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
1290	    pTemplate[i].ulValueLen = (CK_ULONG)-1;
1291	}
1292
1293    }
1294    return CKR_OK;
1295}
1296
1297CK_RV
1298C_FindObjectsInit(CK_SESSION_HANDLE hSession,
1299		  CK_ATTRIBUTE_PTR pTemplate,
1300		  CK_ULONG ulCount)
1301{
1302    struct session_state *state;
1303
1304    st_logf("FindObjectsInit\n");
1305
1306    INIT_CONTEXT();
1307
1308    VERIFY_SESSION_HANDLE(hSession, &state);
1309
1310    if (state->find.next_object != -1) {
1311	application_error("application didn't do C_FindObjectsFinal\n");
1312	find_object_final(state);
1313    }
1314    if (ulCount) {
1315	CK_ULONG i;
1316
1317	print_attributes(pTemplate, ulCount);
1318
1319	state->find.attributes =
1320	    calloc(1, ulCount * sizeof(state->find.attributes[0]));
1321	if (state->find.attributes == NULL)
1322	    return CKR_DEVICE_MEMORY;
1323	for (i = 0; i < ulCount; i++) {
1324	    state->find.attributes[i].pValue =
1325		malloc(pTemplate[i].ulValueLen);
1326	    if (state->find.attributes[i].pValue == NULL) {
1327		find_object_final(state);
1328		return CKR_DEVICE_MEMORY;
1329	    }
1330	    memcpy(state->find.attributes[i].pValue,
1331		   pTemplate[i].pValue, pTemplate[i].ulValueLen);
1332	    state->find.attributes[i].type = pTemplate[i].type;
1333	    state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
1334	}
1335	state->find.num_attributes = ulCount;
1336	state->find.next_object = 0;
1337    } else {
1338	st_logf("find all objects\n");
1339	state->find.attributes = NULL;
1340	state->find.num_attributes = 0;
1341	state->find.next_object = 0;
1342    }
1343
1344    return CKR_OK;
1345}
1346
1347CK_RV
1348C_FindObjects(CK_SESSION_HANDLE hSession,
1349	      CK_OBJECT_HANDLE_PTR phObject,
1350	      CK_ULONG ulMaxObjectCount,
1351	      CK_ULONG_PTR pulObjectCount)
1352{
1353    struct session_state *state;
1354    int i;
1355
1356    INIT_CONTEXT();
1357
1358    st_logf("FindObjects\n");
1359
1360    VERIFY_SESSION_HANDLE(hSession, &state);
1361
1362    if (state->find.next_object == -1) {
1363	application_error("application didn't do C_FindObjectsInit\n");
1364	return CKR_ARGUMENTS_BAD;
1365    }
1366    if (ulMaxObjectCount == 0) {
1367	application_error("application asked for 0 objects\n");
1368	return CKR_ARGUMENTS_BAD;
1369    }
1370    *pulObjectCount = 0;
1371    for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
1372	st_logf("FindObjects: %d\n", i);
1373	state->find.next_object = i + 1;
1374	if (attributes_match(soft_token.object.objs[i],
1375			     state->find.attributes,
1376			     state->find.num_attributes)) {
1377	    *phObject++ = soft_token.object.objs[i]->object_handle;
1378	    ulMaxObjectCount--;
1379	    (*pulObjectCount)++;
1380	    if (ulMaxObjectCount == 0)
1381		break;
1382	}
1383    }
1384    return CKR_OK;
1385}
1386
1387CK_RV
1388C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1389{
1390    struct session_state *state;
1391
1392    INIT_CONTEXT();
1393
1394    st_logf("FindObjectsFinal\n");
1395    VERIFY_SESSION_HANDLE(hSession, &state);
1396    find_object_final(state);
1397    return CKR_OK;
1398}
1399
1400static CK_RV
1401commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
1402	   const CK_MECHANISM_TYPE *mechs, int mechs_len,
1403	   const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
1404	   struct st_object **o)
1405{
1406    CK_RV ret;
1407    int i;
1408
1409    *o = NULL;
1410    if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
1411	return ret;
1412
1413    ret = attributes_match(*o, attr_match, attr_match_len);
1414    if (!ret) {
1415	application_error("called commonInit on key that doesn't "
1416			  "support required attr");
1417	return CKR_ARGUMENTS_BAD;
1418    }
1419
1420    for (i = 0; i < mechs_len; i++)
1421	if (mechs[i] == pMechanism->mechanism)
1422	    break;
1423    if (i == mechs_len) {
1424	application_error("called mech (%08lx) not supported\n",
1425			  pMechanism->mechanism);
1426	return CKR_ARGUMENTS_BAD;
1427    }
1428    return CKR_OK;
1429}
1430
1431
1432static CK_RV
1433dup_mechanism(CK_MECHANISM_PTR *dp, const CK_MECHANISM_PTR pMechanism)
1434{
1435    CK_MECHANISM_PTR p;
1436
1437    p = malloc(sizeof(*p));
1438    if (p == NULL)
1439	return CKR_DEVICE_MEMORY;
1440
1441    if (*dp)
1442	free(*dp);
1443    *dp = p;
1444    memcpy(p, pMechanism, sizeof(*p));
1445
1446    return CKR_OK;
1447}
1448
1449CK_RV
1450C_DigestInit(CK_SESSION_HANDLE hSession,
1451	     CK_MECHANISM_PTR pMechanism)
1452{
1453    st_logf("DigestInit\n");
1454    INIT_CONTEXT();
1455    VERIFY_SESSION_HANDLE(hSession, NULL);
1456    return CKR_FUNCTION_NOT_SUPPORTED;
1457}
1458
1459CK_RV
1460C_SignInit(CK_SESSION_HANDLE hSession,
1461	   CK_MECHANISM_PTR pMechanism,
1462	   CK_OBJECT_HANDLE hKey)
1463{
1464    struct session_state *state;
1465    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1466    CK_BBOOL bool_true = CK_TRUE;
1467    CK_ATTRIBUTE attr[] = {
1468	{ CKA_SIGN, &bool_true, sizeof(bool_true) }
1469    };
1470    struct st_object *o;
1471    CK_RV ret;
1472
1473    INIT_CONTEXT();
1474    st_logf("SignInit\n");
1475    VERIFY_SESSION_HANDLE(hSession, &state);
1476
1477    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1478		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1479		     pMechanism, hKey, &o);
1480    if (ret)
1481	return ret;
1482
1483    ret = dup_mechanism(&state->sign_mechanism, pMechanism);
1484    if (ret == CKR_OK)
1485	state->sign_object = OBJECT_ID(o);
1486
1487    return CKR_OK;
1488}
1489
1490CK_RV
1491C_Sign(CK_SESSION_HANDLE hSession,
1492       CK_BYTE_PTR pData,
1493       CK_ULONG ulDataLen,
1494       CK_BYTE_PTR pSignature,
1495       CK_ULONG_PTR pulSignatureLen)
1496{
1497    struct session_state *state;
1498    struct st_object *o;
1499    CK_RV ret;
1500    int hret;
1501    const AlgorithmIdentifier *alg;
1502    heim_octet_string sig, data;
1503
1504    INIT_CONTEXT();
1505    st_logf("Sign\n");
1506    VERIFY_SESSION_HANDLE(hSession, &state);
1507
1508    sig.data = NULL;
1509    sig.length = 0;
1510
1511    if (state->sign_object == -1)
1512	return CKR_ARGUMENTS_BAD;
1513
1514    if (pulSignatureLen == NULL) {
1515	st_logf("signature len NULL\n");
1516	ret = CKR_ARGUMENTS_BAD;
1517	goto out;
1518    }
1519
1520    if (pData == NULL_PTR) {
1521	st_logf("data NULL\n");
1522	ret = CKR_ARGUMENTS_BAD;
1523	goto out;
1524    }
1525
1526    o = soft_token.object.objs[state->sign_object];
1527
1528    if (hx509_cert_have_private_key(o->cert) == 0) {
1529	st_logf("private key NULL\n");
1530	return CKR_ARGUMENTS_BAD;
1531    }
1532
1533    switch(state->sign_mechanism->mechanism) {
1534    case CKM_RSA_PKCS:
1535	alg = hx509_signature_rsa_pkcs1_x509();
1536	break;
1537    default:
1538	ret = CKR_FUNCTION_NOT_SUPPORTED;
1539	goto out;
1540    }
1541
1542    data.data = pData;
1543    data.length = ulDataLen;
1544
1545    hret = _hx509_create_signature(context,
1546				   _hx509_cert_private_key(o->cert),
1547				   alg,
1548				   &data,
1549				   NULL,
1550				   &sig);
1551    if (hret) {
1552	ret = CKR_DEVICE_ERROR;
1553	goto out;
1554    }
1555    *pulSignatureLen = sig.length;
1556
1557    if (pSignature != NULL_PTR)
1558	memcpy(pSignature, sig.data, sig.length);
1559
1560    ret = CKR_OK;
1561 out:
1562    if (sig.data) {
1563	memset(sig.data, 0, sig.length);
1564	der_free_octet_string(&sig);
1565    }
1566    return ret;
1567}
1568
1569CK_RV
1570C_SignUpdate(CK_SESSION_HANDLE hSession,
1571	     CK_BYTE_PTR pPart,
1572	     CK_ULONG ulPartLen)
1573{
1574    INIT_CONTEXT();
1575    st_logf("SignUpdate\n");
1576    VERIFY_SESSION_HANDLE(hSession, NULL);
1577    return CKR_FUNCTION_NOT_SUPPORTED;
1578}
1579
1580
1581CK_RV
1582C_SignFinal(CK_SESSION_HANDLE hSession,
1583	    CK_BYTE_PTR pSignature,
1584	    CK_ULONG_PTR pulSignatureLen)
1585{
1586    INIT_CONTEXT();
1587    st_logf("SignUpdate\n");
1588    VERIFY_SESSION_HANDLE(hSession, NULL);
1589    return CKR_FUNCTION_NOT_SUPPORTED;
1590}
1591
1592CK_RV
1593C_VerifyInit(CK_SESSION_HANDLE hSession,
1594	     CK_MECHANISM_PTR pMechanism,
1595	     CK_OBJECT_HANDLE hKey)
1596{
1597    struct session_state *state;
1598    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1599    CK_BBOOL bool_true = CK_TRUE;
1600    CK_ATTRIBUTE attr[] = {
1601	{ CKA_VERIFY, &bool_true, sizeof(bool_true) }
1602    };
1603    struct st_object *o;
1604    CK_RV ret;
1605
1606    INIT_CONTEXT();
1607    st_logf("VerifyInit\n");
1608    VERIFY_SESSION_HANDLE(hSession, &state);
1609
1610    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1611		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1612		     pMechanism, hKey, &o);
1613    if (ret)
1614	return ret;
1615
1616    ret = dup_mechanism(&state->verify_mechanism, pMechanism);
1617    if (ret == CKR_OK)
1618	state->verify_object = OBJECT_ID(o);
1619
1620    return ret;
1621}
1622
1623CK_RV
1624C_Verify(CK_SESSION_HANDLE hSession,
1625	 CK_BYTE_PTR pData,
1626	 CK_ULONG ulDataLen,
1627	 CK_BYTE_PTR pSignature,
1628	 CK_ULONG ulSignatureLen)
1629{
1630    struct session_state *state;
1631    struct st_object *o;
1632    const AlgorithmIdentifier *alg;
1633    CK_RV ret;
1634    int hret;
1635    heim_octet_string data, sig;
1636
1637    INIT_CONTEXT();
1638    st_logf("Verify\n");
1639    VERIFY_SESSION_HANDLE(hSession, &state);
1640
1641    if (state->verify_object == -1)
1642	return CKR_ARGUMENTS_BAD;
1643
1644    o = soft_token.object.objs[state->verify_object];
1645
1646    switch(state->verify_mechanism->mechanism) {
1647    case CKM_RSA_PKCS:
1648	alg = hx509_signature_rsa_pkcs1_x509();
1649	break;
1650    default:
1651	ret = CKR_FUNCTION_NOT_SUPPORTED;
1652	goto out;
1653    }
1654
1655    sig.data = pData;
1656    sig.length = ulDataLen;
1657    data.data = pSignature;
1658    data.length = ulSignatureLen;
1659
1660    hret = _hx509_verify_signature(context,
1661				   o->cert,
1662				   alg,
1663				   &data,
1664				   &sig);
1665    if (hret) {
1666	ret = CKR_GENERAL_ERROR;
1667	goto out;
1668    }
1669    ret = CKR_OK;
1670
1671 out:
1672    return ret;
1673}
1674
1675
1676CK_RV
1677C_VerifyUpdate(CK_SESSION_HANDLE hSession,
1678	       CK_BYTE_PTR pPart,
1679	       CK_ULONG ulPartLen)
1680{
1681    INIT_CONTEXT();
1682    st_logf("VerifyUpdate\n");
1683    VERIFY_SESSION_HANDLE(hSession, NULL);
1684    return CKR_FUNCTION_NOT_SUPPORTED;
1685}
1686
1687CK_RV
1688C_VerifyFinal(CK_SESSION_HANDLE hSession,
1689	      CK_BYTE_PTR pSignature,
1690	      CK_ULONG ulSignatureLen)
1691{
1692    INIT_CONTEXT();
1693    st_logf("VerifyFinal\n");
1694    VERIFY_SESSION_HANDLE(hSession, NULL);
1695    return CKR_FUNCTION_NOT_SUPPORTED;
1696}
1697
1698CK_RV
1699C_GenerateRandom(CK_SESSION_HANDLE hSession,
1700		 CK_BYTE_PTR RandomData,
1701		 CK_ULONG ulRandomLen)
1702{
1703    INIT_CONTEXT();
1704    st_logf("GenerateRandom\n");
1705    VERIFY_SESSION_HANDLE(hSession, NULL);
1706    return CKR_FUNCTION_NOT_SUPPORTED;
1707}
1708
1709
1710CK_FUNCTION_LIST funcs = {
1711    { 2, 11 },
1712    C_Initialize,
1713    C_Finalize,
1714    C_GetInfo,
1715    C_GetFunctionList,
1716    C_GetSlotList,
1717    C_GetSlotInfo,
1718    C_GetTokenInfo,
1719    C_GetMechanismList,
1720    C_GetMechanismInfo,
1721    C_InitToken,
1722    (void *)func_not_supported, /* C_InitPIN */
1723    (void *)func_not_supported, /* C_SetPIN */
1724    C_OpenSession,
1725    C_CloseSession,
1726    C_CloseAllSessions,
1727    C_GetSessionInfo,
1728    (void *)func_not_supported, /* C_GetOperationState */
1729    (void *)func_not_supported, /* C_SetOperationState */
1730    C_Login,
1731    C_Logout,
1732    (void *)func_not_supported, /* C_CreateObject */
1733    (void *)func_not_supported, /* C_CopyObject */
1734    (void *)func_not_supported, /* C_DestroyObject */
1735    (void *)func_not_supported, /* C_GetObjectSize */
1736    C_GetAttributeValue,
1737    (void *)func_not_supported, /* C_SetAttributeValue */
1738    C_FindObjectsInit,
1739    C_FindObjects,
1740    C_FindObjectsFinal,
1741    (void *)func_not_supported, /* C_EncryptInit, */
1742    (void *)func_not_supported, /* C_Encrypt, */
1743    (void *)func_not_supported, /* C_EncryptUpdate, */
1744    (void *)func_not_supported, /* C_EncryptFinal, */
1745    (void *)func_not_supported, /* C_DecryptInit, */
1746    (void *)func_not_supported, /* C_Decrypt, */
1747    (void *)func_not_supported, /* C_DecryptUpdate, */
1748    (void *)func_not_supported, /* C_DecryptFinal, */
1749    C_DigestInit,
1750    (void *)func_not_supported, /* C_Digest */
1751    (void *)func_not_supported, /* C_DigestUpdate */
1752    (void *)func_not_supported, /* C_DigestKey */
1753    (void *)func_not_supported, /* C_DigestFinal */
1754    C_SignInit,
1755    C_Sign,
1756    C_SignUpdate,
1757    C_SignFinal,
1758    (void *)func_not_supported, /* C_SignRecoverInit */
1759    (void *)func_not_supported, /* C_SignRecover */
1760    C_VerifyInit,
1761    C_Verify,
1762    C_VerifyUpdate,
1763    C_VerifyFinal,
1764    (void *)func_not_supported, /* C_VerifyRecoverInit */
1765    (void *)func_not_supported, /* C_VerifyRecover */
1766    (void *)func_not_supported, /* C_DigestEncryptUpdate */
1767    (void *)func_not_supported, /* C_DecryptDigestUpdate */
1768    (void *)func_not_supported, /* C_SignEncryptUpdate */
1769    (void *)func_not_supported, /* C_DecryptVerifyUpdate */
1770    (void *)func_not_supported, /* C_GenerateKey */
1771    (void *)func_not_supported, /* C_GenerateKeyPair */
1772    (void *)func_not_supported, /* C_WrapKey */
1773    (void *)func_not_supported, /* C_UnwrapKey */
1774    (void *)func_not_supported, /* C_DeriveKey */
1775    (void *)func_not_supported, /* C_SeedRandom */
1776    C_GenerateRandom,
1777    (void *)func_not_supported, /* C_GetFunctionStatus */
1778    (void *)func_not_supported, /* C_CancelFunction */
1779    (void *)func_not_supported  /* C_WaitForSlotEvent */
1780};
1781