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