Home | History | Annotate | Line # | Download | only in hx509
      1 /*	$NetBSD: softp11.c,v 1.5 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2004 - 2008 Kungliga Tekniska Hgskolan
      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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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 *
    701 has_session(void)
    702 {
    703     return soft_token.open_sessions > 0 ? "yes" : "no";
    704 }
    705 
    706 static CK_RV
    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
    818 func_not_supported(void)
    819 {
    820     st_logf("function not supported\n");
    821     return CKR_FUNCTION_NOT_SUPPORTED;
    822 }
    823 
    824 static char *
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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