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