xref: /freebsd/crypto/heimdal/lib/hx509/softp11.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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 
52 struct st_attr {
53     CK_ATTRIBUTE attribute;
54     int secret;
55 };
56 
57 struct st_object {
58     CK_OBJECT_HANDLE object_handle;
59     struct st_attr *attrs;
60     int num_attributes;
61     hx509_cert cert;
62 };
63 
64 static 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 
97 static hx509_context context;
98 
99 static void
100 application_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 
110 static void
111 st_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 
122 static CK_RV
123 init_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 
135 static void
136 snprintf_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 
162 static CK_RV
163 verify_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 
182 static CK_RV
183 object_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 
199 static int
200 attributes_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 
229 static void
230 print_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 
303 static struct st_object *
304 add_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 
335 static CK_RV
336 add_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 
362 static CK_RV
363 add_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 
416 struct foo {
417     char *label;
418     char *id;
419 };
420 
421 static int
422 add_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 
599 static CK_RV
600 add_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 
643 static void
644 find_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 
660 static void
661 reset_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 
673 static void
674 close_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 
687 static const char *
688 has_session(void)
689 {
690     return soft_token.open_sessions > 0 ? "yes" : "no";
691 }
692 
693 static CK_RV
694 read_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 
804 static CK_RV
805 func_not_supported(void)
806 {
807     st_logf("function not supported\n");
808     return CKR_FUNCTION_NOT_SUPPORTED;
809 }
810 
811 static char *
812 get_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 
858 CK_RV CK_SPEC
859 C_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 
917 CK_RV
918 C_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 
937 CK_RV
938 C_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 
960 extern CK_FUNCTION_LIST funcs;
961 
962 CK_RV
963 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
964 {
965     INIT_CONTEXT();
966 
967     *ppFunctionList = &funcs;
968     return CKR_OK;
969 }
970 
971 CK_RV
972 C_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 
985 CK_RV
986 C_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 
1016 CK_RV
1017 C_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 
1069 CK_RV
1070 C_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 
1085 CK_RV
1086 C_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 
1098 CK_RV
1099 C_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 
1109 CK_RV
1110 C_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 
1141 CK_RV
1142 C_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 
1156 CK_RV
1157 C_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 
1171 CK_RV
1172 C_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 
1193 CK_RV
1194 C_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 
1225 CK_RV
1226 C_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 
1235 CK_RV
1236 C_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 
1247 CK_RV
1248 C_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 
1297 CK_RV
1298 C_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 
1347 CK_RV
1348 C_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 
1387 CK_RV
1388 C_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 
1400 static CK_RV
1401 commonInit(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 
1432 static CK_RV
1433 dup_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 
1449 CK_RV
1450 C_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 
1459 CK_RV
1460 C_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 
1490 CK_RV
1491 C_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 
1569 CK_RV
1570 C_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 
1581 CK_RV
1582 C_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 
1592 CK_RV
1593 C_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 
1623 CK_RV
1624 C_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 
1676 CK_RV
1677 C_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 
1687 CK_RV
1688 C_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 
1698 CK_RV
1699 C_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 
1710 CK_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