Home | History | Annotate | Line # | Download | only in hx509
ks_p11.c revision 1.1.1.2.10.1
      1 /*	$NetBSD: ks_p11.c,v 1.1.1.2.10.1 2017/04/21 16:50:48 bouyer 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 #include "hx_locl.h"
     37 #ifdef HAVE_DLFCN_H
     38 #include <dlfcn.h>
     39 #endif
     40 
     41 #ifdef HAVE_DLOPEN
     42 
     43 #include "ref/pkcs11.h"
     44 
     45 struct p11_slot {
     46     int flags;
     47 #define P11_SESSION		1
     48 #define P11_SESSION_IN_USE	2
     49 #define P11_LOGIN_REQ		4
     50 #define P11_LOGIN_DONE		8
     51 #define P11_TOKEN_PRESENT	16
     52     CK_SESSION_HANDLE session;
     53     CK_SLOT_ID id;
     54     CK_BBOOL token;
     55     char *name;
     56     hx509_certs certs;
     57     char *pin;
     58     struct {
     59 	CK_MECHANISM_TYPE_PTR list;
     60 	CK_ULONG num;
     61 	CK_MECHANISM_INFO_PTR *infos;
     62     } mechs;
     63 };
     64 
     65 struct p11_module {
     66     void *dl_handle;
     67     CK_FUNCTION_LIST_PTR funcs;
     68     CK_ULONG num_slots;
     69     unsigned int ref;
     70     unsigned int selected_slot;
     71     struct p11_slot *slot;
     72 };
     73 
     74 #define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
     75 
     76 static int p11_get_session(hx509_context,
     77 			   struct p11_module *,
     78 			   struct p11_slot *,
     79 			   hx509_lock,
     80 			   CK_SESSION_HANDLE *);
     81 static int p11_put_session(struct p11_module *,
     82 			   struct p11_slot *,
     83 			   CK_SESSION_HANDLE);
     84 static void p11_release_module(struct p11_module *);
     85 
     86 static int p11_list_keys(hx509_context,
     87 			 struct p11_module *,
     88 			 struct p11_slot *,
     89 			 CK_SESSION_HANDLE,
     90 			 hx509_lock,
     91 			 hx509_certs *);
     92 
     93 /*
     94  *
     95  */
     96 
     97 struct p11_rsa {
     98     struct p11_module *p;
     99     struct p11_slot *slot;
    100     CK_OBJECT_HANDLE private_key;
    101     CK_OBJECT_HANDLE public_key;
    102 };
    103 
    104 static int
    105 p11_rsa_public_encrypt(int flen,
    106 		       const unsigned char *from,
    107 		       unsigned char *to,
    108 		       RSA *rsa,
    109 		       int padding)
    110 {
    111     return -1;
    112 }
    113 
    114 static int
    115 p11_rsa_public_decrypt(int flen,
    116 		       const unsigned char *from,
    117 		       unsigned char *to,
    118 		       RSA *rsa,
    119 		       int padding)
    120 {
    121     return -1;
    122 }
    123 
    124 
    125 static int
    126 p11_rsa_private_encrypt(int flen,
    127 			const unsigned char *from,
    128 			unsigned char *to,
    129 			RSA *rsa,
    130 			int padding)
    131 {
    132     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
    133     CK_OBJECT_HANDLE key = p11rsa->private_key;
    134     CK_SESSION_HANDLE session;
    135     CK_MECHANISM mechanism;
    136     CK_ULONG ck_sigsize;
    137     int ret;
    138 
    139     if (padding != RSA_PKCS1_PADDING)
    140 	return -1;
    141 
    142     memset(&mechanism, 0, sizeof(mechanism));
    143     mechanism.mechanism = CKM_RSA_PKCS;
    144 
    145     ck_sigsize = RSA_size(rsa);
    146 
    147     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
    148     if (ret)
    149 	return -1;
    150 
    151     ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
    152     if (ret != CKR_OK) {
    153 	p11_put_session(p11rsa->p, p11rsa->slot, session);
    154 	return -1;
    155     }
    156 
    157     ret = P11FUNC(p11rsa->p, Sign,
    158 		  (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
    159     p11_put_session(p11rsa->p, p11rsa->slot, session);
    160     if (ret != CKR_OK)
    161 	return -1;
    162 
    163     return ck_sigsize;
    164 }
    165 
    166 static int
    167 p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
    168 			RSA * rsa, int padding)
    169 {
    170     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
    171     CK_OBJECT_HANDLE key = p11rsa->private_key;
    172     CK_SESSION_HANDLE session;
    173     CK_MECHANISM mechanism;
    174     CK_ULONG ck_sigsize;
    175     int ret;
    176 
    177     if (padding != RSA_PKCS1_PADDING)
    178 	return -1;
    179 
    180     memset(&mechanism, 0, sizeof(mechanism));
    181     mechanism.mechanism = CKM_RSA_PKCS;
    182 
    183     ck_sigsize = RSA_size(rsa);
    184 
    185     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
    186     if (ret)
    187 	return -1;
    188 
    189     ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
    190     if (ret != CKR_OK) {
    191 	p11_put_session(p11rsa->p, p11rsa->slot, session);
    192 	return -1;
    193     }
    194 
    195     ret = P11FUNC(p11rsa->p, Decrypt,
    196 		  (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
    197     p11_put_session(p11rsa->p, p11rsa->slot, session);
    198     if (ret != CKR_OK)
    199 	return -1;
    200 
    201     return ck_sigsize;
    202 }
    203 
    204 static int
    205 p11_rsa_init(RSA *rsa)
    206 {
    207     return 1;
    208 }
    209 
    210 static int
    211 p11_rsa_finish(RSA *rsa)
    212 {
    213     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
    214     p11_release_module(p11rsa->p);
    215     free(p11rsa);
    216     return 1;
    217 }
    218 
    219 static const RSA_METHOD p11_rsa_pkcs1_method = {
    220     "hx509 PKCS11 PKCS#1 RSA",
    221     p11_rsa_public_encrypt,
    222     p11_rsa_public_decrypt,
    223     p11_rsa_private_encrypt,
    224     p11_rsa_private_decrypt,
    225     NULL,
    226     NULL,
    227     p11_rsa_init,
    228     p11_rsa_finish,
    229     0,
    230     NULL,
    231     NULL,
    232     NULL,
    233     NULL
    234 };
    235 
    236 /*
    237  *
    238  */
    239 
    240 static int
    241 p11_mech_info(hx509_context context,
    242 	      struct p11_module *p,
    243 	      struct p11_slot *slot,
    244 	      int num)
    245 {
    246     CK_ULONG i;
    247     int ret;
    248 
    249     ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
    250     if (ret) {
    251 	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
    252 			       "Failed to get mech list count for slot %d",
    253 			       num);
    254 	return HX509_PKCS11_NO_MECH;
    255     }
    256     if (i == 0) {
    257 	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
    258 			       "no mech supported for slot %d", num);
    259 	return HX509_PKCS11_NO_MECH;
    260     }
    261     slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
    262     if (slot->mechs.list == NULL) {
    263 	hx509_set_error_string(context, 0, ENOMEM,
    264 			       "out of memory");
    265 	return ENOMEM;
    266     }
    267     slot->mechs.num = i;
    268     ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
    269     if (ret) {
    270 	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
    271 			       "Failed to get mech list for slot %d",
    272 			       num);
    273 	return HX509_PKCS11_NO_MECH;
    274     }
    275     assert(i == slot->mechs.num);
    276 
    277     slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
    278     if (slot->mechs.list == NULL) {
    279 	hx509_set_error_string(context, 0, ENOMEM,
    280 			       "out of memory");
    281 	return ENOMEM;
    282     }
    283 
    284     for (i = 0; i < slot->mechs.num; i++) {
    285 	slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
    286 	if (slot->mechs.infos[i] == NULL) {
    287 	    hx509_set_error_string(context, 0, ENOMEM,
    288 				   "out of memory");
    289 	    return ENOMEM;
    290 	}
    291 	ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
    292 					    slot->mechs.infos[i]));
    293 	if (ret) {
    294 	    hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
    295 				   "Failed to get mech info for slot %d",
    296 				   num);
    297 	    return HX509_PKCS11_NO_MECH;
    298 	}
    299     }
    300 
    301     return 0;
    302 }
    303 
    304 static int
    305 p11_init_slot(hx509_context context,
    306 	      struct p11_module *p,
    307 	      hx509_lock lock,
    308 	      CK_SLOT_ID id,
    309 	      int num,
    310 	      struct p11_slot *slot)
    311 {
    312     CK_SESSION_HANDLE session;
    313     CK_SLOT_INFO slot_info;
    314     CK_TOKEN_INFO token_info;
    315     size_t i;
    316     int ret;
    317 
    318     slot->certs = NULL;
    319     slot->id = id;
    320 
    321     ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
    322     if (ret) {
    323 	hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
    324 			       "Failed to init PKCS11 slot %d",
    325 			       num);
    326 	return HX509_PKCS11_TOKEN_CONFUSED;
    327     }
    328 
    329     for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
    330 	char c = slot_info.slotDescription[i];
    331 	if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
    332 	    continue;
    333 	i++;
    334 	break;
    335     }
    336 
    337     ret = asprintf(&slot->name, "%.*s", (int)i,
    338 		   slot_info.slotDescription);
    339     if (ret == -1)
    340 	return ENOMEM;
    341 
    342     if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
    343 	return 0;
    344 
    345     ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
    346     if (ret) {
    347 	hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
    348 			       "Failed to init PKCS11 slot %d "
    349 			       "with error 0x%08x",
    350 			       num, ret);
    351 	return HX509_PKCS11_NO_TOKEN;
    352     }
    353     slot->flags |= P11_TOKEN_PRESENT;
    354 
    355     if (token_info.flags & CKF_LOGIN_REQUIRED)
    356 	slot->flags |= P11_LOGIN_REQ;
    357 
    358     ret = p11_get_session(context, p, slot, lock, &session);
    359     if (ret)
    360 	return ret;
    361 
    362     ret = p11_mech_info(context, p, slot, num);
    363     if (ret)
    364 	goto out;
    365 
    366     ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
    367  out:
    368     p11_put_session(p, slot, session);
    369 
    370     return ret;
    371 }
    372 
    373 static int
    374 p11_get_session(hx509_context context,
    375 		struct p11_module *p,
    376 		struct p11_slot *slot,
    377 		hx509_lock lock,
    378 		CK_SESSION_HANDLE *psession)
    379 {
    380     CK_RV ret;
    381 
    382     if (slot->flags & P11_SESSION_IN_USE)
    383 	_hx509_abort("slot already in session");
    384 
    385     if (slot->flags & P11_SESSION) {
    386 	slot->flags |= P11_SESSION_IN_USE;
    387 	*psession = slot->session;
    388 	return 0;
    389     }
    390 
    391     ret = P11FUNC(p, OpenSession, (slot->id,
    392 				   CKF_SERIAL_SESSION,
    393 				   NULL,
    394 				   NULL,
    395 				   &slot->session));
    396     if (ret != CKR_OK) {
    397 	if (context)
    398 	    hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
    399 				   "Failed to OpenSession for slot id %d "
    400 				   "with error: 0x%08x",
    401 				   (int)slot->id, ret);
    402 	return HX509_PKCS11_OPEN_SESSION;
    403     }
    404 
    405     slot->flags |= P11_SESSION;
    406 
    407     /*
    408      * If we have have to login, and haven't tried before and have a
    409      * prompter or known to work pin code.
    410      *
    411      * This code is very conversative and only uses the prompter in
    412      * the hx509_lock, the reason is that it's bad to try many
    413      * passwords on a pkcs11 token, it might lock up and have to be
    414      * unlocked by a administrator.
    415      *
    416      * XXX try harder to not use pin several times on the same card.
    417      */
    418 
    419     if (   (slot->flags & P11_LOGIN_REQ)
    420 	&& (slot->flags & P11_LOGIN_DONE) == 0
    421 	&& (lock || slot->pin))
    422     {
    423 	hx509_prompt prompt;
    424 	char pin[20];
    425 	char *str;
    426 
    427 	if (slot->pin == NULL) {
    428 
    429 	    memset(&prompt, 0, sizeof(prompt));
    430 
    431 	    ret = asprintf(&str, "PIN code for %s: ", slot->name);
    432 	    if (ret == -1 || str == NULL) {
    433 		if (context)
    434 		    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    435 		return ENOMEM;
    436 	    }
    437 	    prompt.prompt = str;
    438 	    prompt.type = HX509_PROMPT_TYPE_PASSWORD;
    439 	    prompt.reply.data = pin;
    440 	    prompt.reply.length = sizeof(pin);
    441 
    442 	    ret = hx509_lock_prompt(lock, &prompt);
    443 	    if (ret) {
    444 		free(str);
    445 		if (context)
    446 		    hx509_set_error_string(context, 0, ret,
    447 					   "Failed to get pin code for slot "
    448 					   "id %d with error: %d",
    449 					   (int)slot->id, ret);
    450 		return ret;
    451 	    }
    452 	    free(str);
    453 	} else {
    454 	    strlcpy(pin, slot->pin, sizeof(pin));
    455 	}
    456 
    457 	ret = P11FUNC(p, Login, (slot->session, CKU_USER,
    458 				 (unsigned char*)pin, strlen(pin)));
    459 	if (ret != CKR_OK) {
    460 	    if (context)
    461 		hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
    462 				       "Failed to login on slot id %d "
    463 				       "with error: 0x%08x",
    464 				       (int)slot->id, ret);
    465 	    switch(ret) {
    466 	        case CKR_PIN_LOCKED:
    467 	            return HX509_PKCS11_PIN_LOCKED;
    468 	        case CKR_PIN_EXPIRED:
    469 	            return HX509_PKCS11_PIN_EXPIRED;
    470 	        case CKR_PIN_INCORRECT:
    471 	            return HX509_PKCS11_PIN_INCORRECT;
    472 	        case CKR_USER_PIN_NOT_INITIALIZED:
    473 	            return HX509_PKCS11_PIN_NOT_INITIALIZED;
    474 	        default:
    475 	            return HX509_PKCS11_LOGIN;
    476 	    }
    477 	} else
    478 	    slot->flags |= P11_LOGIN_DONE;
    479 
    480 	if (slot->pin == NULL) {
    481 	    slot->pin = strdup(pin);
    482 	    if (slot->pin == NULL) {
    483 		if (context)
    484 		    hx509_set_error_string(context, 0, ENOMEM,
    485 					   "out of memory");
    486 		return ENOMEM;
    487 	    }
    488 	}
    489     } else
    490 	slot->flags |= P11_LOGIN_DONE;
    491 
    492     slot->flags |= P11_SESSION_IN_USE;
    493 
    494     *psession = slot->session;
    495 
    496     return 0;
    497 }
    498 
    499 static int
    500 p11_put_session(struct p11_module *p,
    501 		struct p11_slot *slot,
    502 		CK_SESSION_HANDLE session)
    503 {
    504     if ((slot->flags & P11_SESSION_IN_USE) == 0)
    505 	_hx509_abort("slot not in session");
    506     slot->flags &= ~P11_SESSION_IN_USE;
    507 
    508     return 0;
    509 }
    510 
    511 static int
    512 iterate_entries(hx509_context context,
    513 		struct p11_module *p, struct p11_slot *slot,
    514 		CK_SESSION_HANDLE session,
    515 		CK_ATTRIBUTE *search_data, int num_search_data,
    516 		CK_ATTRIBUTE *query, int num_query,
    517 		int (*func)(hx509_context,
    518 			    struct p11_module *, struct p11_slot *,
    519 			    CK_SESSION_HANDLE session,
    520 			    CK_OBJECT_HANDLE object,
    521 			    void *, CK_ATTRIBUTE *, int), void *ptr)
    522 {
    523     CK_OBJECT_HANDLE object;
    524     CK_ULONG object_count;
    525     int ret, ret2, i;
    526 
    527     ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
    528     if (ret != CKR_OK) {
    529 	return -1;
    530     }
    531     while (1) {
    532 	ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
    533 	if (ret != CKR_OK) {
    534 	    return -1;
    535 	}
    536 	if (object_count == 0)
    537 	    break;
    538 
    539 	for (i = 0; i < num_query; i++)
    540 	    query[i].pValue = NULL;
    541 
    542 	ret = P11FUNC(p, GetAttributeValue,
    543 		      (session, object, query, num_query));
    544 	if (ret != CKR_OK) {
    545 	    return -1;
    546 	}
    547 	for (i = 0; i < num_query; i++) {
    548 	    query[i].pValue = malloc(query[i].ulValueLen);
    549 	    if (query[i].pValue == NULL) {
    550 		ret = ENOMEM;
    551 		goto out;
    552 	    }
    553 	}
    554 	ret = P11FUNC(p, GetAttributeValue,
    555 		      (session, object, query, num_query));
    556 	if (ret != CKR_OK) {
    557 	    ret = -1;
    558 	    goto out;
    559 	}
    560 
    561 	ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
    562 	if (ret)
    563 	    goto out;
    564 
    565 	for (i = 0; i < num_query; i++) {
    566 	    if (query[i].pValue)
    567 		free(query[i].pValue);
    568 	    query[i].pValue = NULL;
    569 	}
    570     }
    571  out:
    572 
    573     for (i = 0; i < num_query; i++) {
    574 	if (query[i].pValue)
    575 	    free(query[i].pValue);
    576 	query[i].pValue = NULL;
    577     }
    578 
    579     ret2 = P11FUNC(p, FindObjectsFinal, (session));
    580     if (ret2 != CKR_OK) {
    581 	return ret2;
    582     }
    583 
    584     return ret;
    585 }
    586 
    587 static BIGNUM *
    588 getattr_bn(struct p11_module *p,
    589 	   struct p11_slot *slot,
    590 	   CK_SESSION_HANDLE session,
    591 	   CK_OBJECT_HANDLE object,
    592 	   unsigned int type)
    593 {
    594     CK_ATTRIBUTE query;
    595     BIGNUM *bn;
    596     int ret;
    597 
    598     query.type = type;
    599     query.pValue = NULL;
    600     query.ulValueLen = 0;
    601 
    602     ret = P11FUNC(p, GetAttributeValue,
    603 		  (session, object, &query, 1));
    604     if (ret != CKR_OK)
    605 	return NULL;
    606 
    607     query.pValue = malloc(query.ulValueLen);
    608 
    609     ret = P11FUNC(p, GetAttributeValue,
    610 		  (session, object, &query, 1));
    611     if (ret != CKR_OK) {
    612 	free(query.pValue);
    613 	return NULL;
    614     }
    615     bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
    616     free(query.pValue);
    617 
    618     return bn;
    619 }
    620 
    621 static int
    622 collect_private_key(hx509_context context,
    623 		    struct p11_module *p, struct p11_slot *slot,
    624 		    CK_SESSION_HANDLE session,
    625 		    CK_OBJECT_HANDLE object,
    626 		    void *ptr, CK_ATTRIBUTE *query, int num_query)
    627 {
    628     struct hx509_collector *collector = ptr;
    629     hx509_private_key key;
    630     heim_octet_string localKeyId;
    631     int ret;
    632     RSA *rsa;
    633     struct p11_rsa *p11rsa;
    634 
    635     localKeyId.data = query[0].pValue;
    636     localKeyId.length = query[0].ulValueLen;
    637 
    638     ret = hx509_private_key_init(&key, NULL, NULL);
    639     if (ret)
    640 	return ret;
    641 
    642     rsa = RSA_new();
    643     if (rsa == NULL)
    644 	_hx509_abort("out of memory");
    645 
    646     /*
    647      * The exponent and modulus should always be present according to
    648      * the pkcs11 specification, but some smartcards leaves it out,
    649      * let ignore any failure to fetch it.
    650      */
    651     rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
    652     rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
    653 
    654     p11rsa = calloc(1, sizeof(*p11rsa));
    655     if (p11rsa == NULL)
    656 	_hx509_abort("out of memory");
    657 
    658     p11rsa->p = p;
    659     p11rsa->slot = slot;
    660     p11rsa->private_key = object;
    661 
    662     if (p->ref == 0)
    663 	_hx509_abort("pkcs11 ref == 0 on alloc");
    664     p->ref++;
    665     if (p->ref == UINT_MAX)
    666 	_hx509_abort("pkcs11 ref == UINT_MAX on alloc");
    667 
    668     RSA_set_method(rsa, &p11_rsa_pkcs1_method);
    669     ret = RSA_set_app_data(rsa, p11rsa);
    670     if (ret != 1)
    671 	_hx509_abort("RSA_set_app_data");
    672 
    673     hx509_private_key_assign_rsa(key, rsa);
    674 
    675     ret = _hx509_collector_private_key_add(context,
    676 					   collector,
    677 					   hx509_signature_rsa(),
    678 					   key,
    679 					   NULL,
    680 					   &localKeyId);
    681 
    682     if (ret) {
    683 	hx509_private_key_free(&key);
    684 	return ret;
    685     }
    686     return 0;
    687 }
    688 
    689 static void
    690 p11_cert_release(hx509_cert cert, void *ctx)
    691 {
    692     struct p11_module *p = ctx;
    693     p11_release_module(p);
    694 }
    695 
    696 
    697 static int
    698 collect_cert(hx509_context context,
    699 	     struct p11_module *p, struct p11_slot *slot,
    700 	     CK_SESSION_HANDLE session,
    701 	     CK_OBJECT_HANDLE object,
    702 	     void *ptr, CK_ATTRIBUTE *query, int num_query)
    703 {
    704     struct hx509_collector *collector = ptr;
    705     heim_error_t error = NULL;
    706     hx509_cert cert;
    707     int ret;
    708 
    709     if ((CK_LONG)query[0].ulValueLen == -1 ||
    710 	(CK_LONG)query[1].ulValueLen == -1)
    711     {
    712 	return 0;
    713     }
    714 
    715     cert = hx509_cert_init_data(context, query[1].pValue,
    716 			       query[1].ulValueLen, &error);
    717     if (cert == NULL) {
    718 	ret = heim_error_get_code(error);
    719 	heim_release(error);
    720 	return ret;
    721     }
    722 
    723     if (p->ref == 0)
    724 	_hx509_abort("pkcs11 ref == 0 on alloc");
    725     p->ref++;
    726     if (p->ref == UINT_MAX)
    727 	_hx509_abort("pkcs11 ref to high");
    728 
    729     _hx509_cert_set_release(cert, p11_cert_release, p);
    730 
    731     {
    732 	heim_octet_string data;
    733 
    734 	data.data = query[0].pValue;
    735 	data.length = query[0].ulValueLen;
    736 
    737 	_hx509_set_cert_attribute(context,
    738 				  cert,
    739 				  &asn1_oid_id_pkcs_9_at_localKeyId,
    740 				  &data);
    741     }
    742 
    743     if ((CK_LONG)query[2].ulValueLen != -1) {
    744 	char *str;
    745 
    746 	ret = asprintf(&str, "%.*s",
    747 		       (int)query[2].ulValueLen, (char *)query[2].pValue);
    748 	if (ret != -1 && str) {
    749 	    hx509_cert_set_friendly_name(cert, str);
    750 	    free(str);
    751 	}
    752     }
    753 
    754     ret = _hx509_collector_certs_add(context, collector, cert);
    755     hx509_cert_free(cert);
    756 
    757     return ret;
    758 }
    759 
    760 
    761 static int
    762 p11_list_keys(hx509_context context,
    763 	      struct p11_module *p,
    764 	      struct p11_slot *slot,
    765 	      CK_SESSION_HANDLE session,
    766 	      hx509_lock lock,
    767 	      hx509_certs *certs)
    768 {
    769     struct hx509_collector *collector;
    770     CK_OBJECT_CLASS key_class;
    771     CK_ATTRIBUTE search_data[] = {
    772 	{CKA_CLASS, NULL, 0},
    773     };
    774     CK_ATTRIBUTE query_data[3] = {
    775 	{CKA_ID, NULL, 0},
    776 	{CKA_VALUE, NULL, 0},
    777 	{CKA_LABEL, NULL, 0}
    778     };
    779     int ret;
    780 
    781     search_data[0].pValue = &key_class;
    782     search_data[0].ulValueLen = sizeof(key_class);
    783 
    784     if (lock == NULL)
    785 	lock = _hx509_empty_lock;
    786 
    787     ret = _hx509_collector_alloc(context, lock, &collector);
    788     if (ret)
    789 	return ret;
    790 
    791     key_class = CKO_PRIVATE_KEY;
    792     ret = iterate_entries(context, p, slot, session,
    793 			  search_data, 1,
    794 			  query_data, 1,
    795 			  collect_private_key, collector);
    796     if (ret)
    797 	goto out;
    798 
    799     key_class = CKO_CERTIFICATE;
    800     ret = iterate_entries(context, p, slot, session,
    801 			  search_data, 1,
    802 			  query_data, 3,
    803 			  collect_cert, collector);
    804     if (ret)
    805 	goto out;
    806 
    807     ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
    808 
    809 out:
    810     _hx509_collector_free(collector);
    811 
    812     return ret;
    813 }
    814 
    815 
    816 static int
    817 p11_init(hx509_context context,
    818 	 hx509_certs certs, void **data, int flags,
    819 	 const char *residue, hx509_lock lock)
    820 {
    821     CK_C_GetFunctionList getFuncs;
    822     struct p11_module *p;
    823     char *list, *str;
    824     int ret;
    825 
    826     *data = NULL;
    827 
    828     list = strdup(residue);
    829     if (list == NULL)
    830 	return ENOMEM;
    831 
    832     p = calloc(1, sizeof(*p));
    833     if (p == NULL) {
    834 	free(list);
    835 	return ENOMEM;
    836     }
    837 
    838     p->ref = 1;
    839     p->selected_slot = 0;
    840 
    841     str = strchr(list, ',');
    842     if (str)
    843 	*str++ = '\0';
    844     while (str) {
    845 	char *strnext;
    846 	strnext = strchr(str, ',');
    847 	if (strnext)
    848 	    *strnext++ = '\0';
    849 	if (strncasecmp(str, "slot=", 5) == 0)
    850 	    p->selected_slot = atoi(str + 5);
    851 	str = strnext;
    852     }
    853 
    854     p->dl_handle = dlopen(list, RTLD_NOW);
    855     if (p->dl_handle == NULL) {
    856 	ret = HX509_PKCS11_LOAD;
    857 	hx509_set_error_string(context, 0, ret,
    858 			       "Failed to open %s: %s", list, dlerror());
    859 	goto out;
    860     }
    861 
    862     getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");
    863     if (getFuncs == NULL) {
    864 	ret = HX509_PKCS11_LOAD;
    865 	hx509_set_error_string(context, 0, ret,
    866 			       "C_GetFunctionList missing in %s: %s",
    867 			       list, dlerror());
    868 	goto out;
    869     }
    870 
    871     ret = (*getFuncs)(&p->funcs);
    872     if (ret) {
    873 	ret = HX509_PKCS11_LOAD;
    874 	hx509_set_error_string(context, 0, ret,
    875 			       "C_GetFunctionList failed in %s", list);
    876 	goto out;
    877     }
    878 
    879     ret = P11FUNC(p, Initialize, (NULL_PTR));
    880     if (ret != CKR_OK) {
    881 	ret = HX509_PKCS11_TOKEN_CONFUSED;
    882 	hx509_set_error_string(context, 0, ret,
    883 			       "Failed initialize the PKCS11 module");
    884 	goto out;
    885     }
    886 
    887     ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
    888     if (ret) {
    889 	ret = HX509_PKCS11_TOKEN_CONFUSED;
    890 	hx509_set_error_string(context, 0, ret,
    891 			       "Failed to get number of PKCS11 slots");
    892 	goto out;
    893     }
    894 
    895    if (p->num_slots == 0) {
    896 	ret = HX509_PKCS11_NO_SLOT;
    897 	hx509_set_error_string(context, 0, ret,
    898 			       "Selected PKCS11 module have no slots");
    899 	goto out;
    900    }
    901 
    902 
    903     {
    904 	CK_SLOT_ID_PTR slot_ids;
    905 	int num_tokens = 0;
    906 	size_t i;
    907 
    908 	slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
    909 	if (slot_ids == NULL) {
    910 	    hx509_clear_error_string(context);
    911 	    ret = ENOMEM;
    912 	    goto out;
    913 	}
    914 
    915 	ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
    916 	if (ret) {
    917 	    free(slot_ids);
    918 	    hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
    919 				   "Failed getting slot-list from "
    920 				   "PKCS11 module");
    921 	    ret = HX509_PKCS11_TOKEN_CONFUSED;
    922 	    goto out;
    923 	}
    924 
    925 	p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
    926 	if (p->slot == NULL) {
    927 	    free(slot_ids);
    928 	    hx509_set_error_string(context, 0, ENOMEM,
    929 				   "Failed to get memory for slot-list");
    930 	    ret = ENOMEM;
    931 	    goto out;
    932 	}
    933 
    934 	for (i = 0; i < p->num_slots; i++) {
    935 	    if ((p->selected_slot != 0) && (slot_ids[i] != (p->selected_slot - 1)))
    936 		continue;
    937 	    ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
    938 	    if (!ret) {
    939 	        if (p->slot[i].flags & P11_TOKEN_PRESENT)
    940 	            num_tokens++;
    941 	    }
    942 	}
    943 	free(slot_ids);
    944 	if (ret)
    945 	    goto out;
    946 	if (num_tokens == 0) {
    947 	    ret = HX509_PKCS11_NO_TOKEN;
    948 	    goto out;
    949 	}
    950     }
    951 
    952     free(list);
    953 
    954     *data = p;
    955 
    956     return 0;
    957  out:
    958     if (list)
    959 	free(list);
    960     p11_release_module(p);
    961     return ret;
    962 }
    963 
    964 static void
    965 p11_release_module(struct p11_module *p)
    966 {
    967     size_t i;
    968 
    969     if (p->ref == 0)
    970 	_hx509_abort("pkcs11 ref to low");
    971     if (--p->ref > 0)
    972 	return;
    973 
    974     for (i = 0; i < p->num_slots; i++) {
    975 	if (p->slot[i].flags & P11_SESSION_IN_USE)
    976 	    _hx509_abort("pkcs11 module release while session in use");
    977 	if (p->slot[i].flags & P11_SESSION) {
    978 	    P11FUNC(p, CloseSession, (p->slot[i].session));
    979 	}
    980 
    981 	if (p->slot[i].name)
    982 	    free(p->slot[i].name);
    983 	if (p->slot[i].pin) {
    984 	    memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
    985 	    free(p->slot[i].pin);
    986 	}
    987 	if (p->slot[i].mechs.num) {
    988 	    free(p->slot[i].mechs.list);
    989 
    990 	    if (p->slot[i].mechs.infos) {
    991 		size_t j;
    992 
    993 		for (j = 0 ; j < p->slot[i].mechs.num ; j++)
    994 		    free(p->slot[i].mechs.infos[j]);
    995 		free(p->slot[i].mechs.infos);
    996 	    }
    997 	}
    998     }
    999     free(p->slot);
   1000 
   1001     if (p->funcs)
   1002 	P11FUNC(p, Finalize, (NULL));
   1003 
   1004     if (p->dl_handle)
   1005 	dlclose(p->dl_handle);
   1006 
   1007     memset(p, 0, sizeof(*p));
   1008     free(p);
   1009 }
   1010 
   1011 static int
   1012 p11_free(hx509_certs certs, void *data)
   1013 {
   1014     struct p11_module *p = data;
   1015     size_t i;
   1016 
   1017     for (i = 0; i < p->num_slots; i++) {
   1018 	if (p->slot[i].certs)
   1019 	    hx509_certs_free(&p->slot[i].certs);
   1020     }
   1021     p11_release_module(p);
   1022     return 0;
   1023 }
   1024 
   1025 struct p11_cursor {
   1026     hx509_certs certs;
   1027     void *cursor;
   1028 };
   1029 
   1030 static int
   1031 p11_iter_start(hx509_context context,
   1032 	       hx509_certs certs, void *data, void **cursor)
   1033 {
   1034     struct p11_module *p = data;
   1035     struct p11_cursor *c;
   1036     int ret;
   1037     size_t i;
   1038 
   1039     c = malloc(sizeof(*c));
   1040     if (c == NULL) {
   1041 	hx509_clear_error_string(context);
   1042 	return ENOMEM;
   1043     }
   1044     ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
   1045     if (ret) {
   1046 	free(c);
   1047 	return ret;
   1048     }
   1049 
   1050     for (i = 0 ; i < p->num_slots; i++) {
   1051 	if (p->slot[i].certs == NULL)
   1052 	    continue;
   1053 	ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
   1054 	if (ret) {
   1055 	    hx509_certs_free(&c->certs);
   1056 	    free(c);
   1057 	    return ret;
   1058 	}
   1059     }
   1060 
   1061     ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
   1062     if (ret) {
   1063 	hx509_certs_free(&c->certs);
   1064 	free(c);
   1065 	return 0;
   1066     }
   1067     *cursor = c;
   1068 
   1069     return 0;
   1070 }
   1071 
   1072 static int
   1073 p11_iter(hx509_context context,
   1074 	 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
   1075 {
   1076     struct p11_cursor *c = cursor;
   1077     return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
   1078 }
   1079 
   1080 static int
   1081 p11_iter_end(hx509_context context,
   1082 	     hx509_certs certs, void *data, void *cursor)
   1083 {
   1084     struct p11_cursor *c = cursor;
   1085     int ret;
   1086     ret = hx509_certs_end_seq(context, c->certs, c->cursor);
   1087     hx509_certs_free(&c->certs);
   1088     free(c);
   1089     return ret;
   1090 }
   1091 
   1092 #define MECHFLAG(x) { "unknown-flag-" #x, x }
   1093 static struct units mechflags[] = {
   1094 	MECHFLAG(0x80000000),
   1095 	MECHFLAG(0x40000000),
   1096 	MECHFLAG(0x20000000),
   1097 	MECHFLAG(0x10000000),
   1098 	MECHFLAG(0x08000000),
   1099 	MECHFLAG(0x04000000),
   1100 	{"ec-compress",		0x2000000 },
   1101 	{"ec-uncompress",	0x1000000 },
   1102 	{"ec-namedcurve",	0x0800000 },
   1103 	{"ec-ecparameters",	0x0400000 },
   1104 	{"ec-f-2m",		0x0200000 },
   1105 	{"ec-f-p",		0x0100000 },
   1106 	{"derive",		0x0080000 },
   1107 	{"unwrap",		0x0040000 },
   1108 	{"wrap",		0x0020000 },
   1109 	{"genereate-key-pair",	0x0010000 },
   1110 	{"generate",		0x0008000 },
   1111 	{"verify-recover",	0x0004000 },
   1112 	{"verify",		0x0002000 },
   1113 	{"sign-recover",	0x0001000 },
   1114 	{"sign",		0x0000800 },
   1115 	{"digest",		0x0000400 },
   1116 	{"decrypt",		0x0000200 },
   1117 	{"encrypt",		0x0000100 },
   1118 	MECHFLAG(0x00080),
   1119 	MECHFLAG(0x00040),
   1120 	MECHFLAG(0x00020),
   1121 	MECHFLAG(0x00010),
   1122 	MECHFLAG(0x00008),
   1123 	MECHFLAG(0x00004),
   1124 	MECHFLAG(0x00002),
   1125 	{"hw",			0x0000001 },
   1126 	{ NULL,			0x0000000 }
   1127 };
   1128 #undef MECHFLAG
   1129 
   1130 static int
   1131 p11_printinfo(hx509_context context,
   1132 	      hx509_certs certs,
   1133 	      void *data,
   1134 	      int (*func)(void *, const char *),
   1135 	      void *ctx)
   1136 {
   1137     struct p11_module *p = data;
   1138     size_t i, j;
   1139 
   1140     _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
   1141 		     p->num_slots, p->num_slots > 1 ? "s" : "");
   1142 
   1143     for (i = 0; i < p->num_slots; i++) {
   1144 	struct p11_slot *s = &p->slot[i];
   1145 
   1146 	_hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
   1147 			 i, (int)s->id, s->name, s->flags);
   1148 
   1149 	_hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
   1150 			 (unsigned long)s->mechs.num);
   1151 	for (j = 0; j < s->mechs.num; j++) {
   1152 	    const char *mechname = "unknown";
   1153 	    char flags[256], unknownname[40];
   1154 #define MECHNAME(s,n) case s: mechname = n; break
   1155 	    switch(s->mechs.list[j]) {
   1156 		MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
   1157 		MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
   1158 		MECHNAME(CKM_RSA_X_509, "rsa-x-509");
   1159 		MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
   1160 		MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
   1161 		MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
   1162 		MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
   1163 		MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
   1164 		MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
   1165 		MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
   1166 		MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
   1167 		MECHNAME(CKM_SHA512, "sha512");
   1168 		MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
   1169 		MECHNAME(CKM_SHA384, "sha384");
   1170 		MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
   1171 		MECHNAME(CKM_SHA256, "sha256");
   1172 		MECHNAME(CKM_SHA_1, "sha1");
   1173 		MECHNAME(CKM_MD5, "md5");
   1174 		MECHNAME(CKM_RIPEMD160, "ripemd-160");
   1175 		MECHNAME(CKM_DES_ECB, "des-ecb");
   1176 		MECHNAME(CKM_DES_CBC, "des-cbc");
   1177 		MECHNAME(CKM_AES_ECB, "aes-ecb");
   1178 		MECHNAME(CKM_AES_CBC, "aes-cbc");
   1179 		MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
   1180 	    default:
   1181 		snprintf(unknownname, sizeof(unknownname),
   1182 			 "unknown-mech-%lu",
   1183 			 (unsigned long)s->mechs.list[j]);
   1184 		mechname = unknownname;
   1185 		break;
   1186 	    }
   1187 #undef MECHNAME
   1188 	    unparse_flags(s->mechs.infos[j]->flags, mechflags,
   1189 			  flags, sizeof(flags));
   1190 
   1191 	    _hx509_pi_printf(func, ctx, "  %s: %s", mechname, flags);
   1192 	}
   1193     }
   1194 
   1195     return 0;
   1196 }
   1197 
   1198 static struct hx509_keyset_ops keyset_pkcs11 = {
   1199     "PKCS11",
   1200     0,
   1201     p11_init,
   1202     NULL,
   1203     p11_free,
   1204     NULL,
   1205     NULL,
   1206     p11_iter_start,
   1207     p11_iter,
   1208     p11_iter_end,
   1209     p11_printinfo,
   1210     NULL,
   1211     NULL
   1212 };
   1213 
   1214 #endif /* HAVE_DLOPEN */
   1215 
   1216 void
   1217 _hx509_ks_pkcs11_register(hx509_context context)
   1218 {
   1219 #ifdef HAVE_DLOPEN
   1220     _hx509_ks_register(context, &keyset_pkcs11);
   1221 #endif
   1222 }
   1223