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