Path: blob/main/crypto/heimdal/lib/hx509/ks_p11.c
110669 views
/*1* Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "hx_locl.h"34#ifdef HAVE_DLFCN_H35#include <dlfcn.h>36#endif3738#ifdef HAVE_DLOPEN3940#include "pkcs11.h"4142struct p11_slot {43int flags;44#define P11_SESSION 145#define P11_SESSION_IN_USE 246#define P11_LOGIN_REQ 447#define P11_LOGIN_DONE 848#define P11_TOKEN_PRESENT 1649CK_SESSION_HANDLE session;50CK_SLOT_ID id;51CK_BBOOL token;52char *name;53hx509_certs certs;54char *pin;55struct {56CK_MECHANISM_TYPE_PTR list;57CK_ULONG num;58CK_MECHANISM_INFO_PTR *infos;59} mechs;60};6162struct p11_module {63void *dl_handle;64CK_FUNCTION_LIST_PTR funcs;65CK_ULONG num_slots;66unsigned int ref;67struct p11_slot *slot;68};6970#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args7172static int p11_get_session(hx509_context,73struct p11_module *,74struct p11_slot *,75hx509_lock,76CK_SESSION_HANDLE *);77static int p11_put_session(struct p11_module *,78struct p11_slot *,79CK_SESSION_HANDLE);80static void p11_release_module(struct p11_module *);8182static int p11_list_keys(hx509_context,83struct p11_module *,84struct p11_slot *,85CK_SESSION_HANDLE,86hx509_lock,87hx509_certs *);8889/*90*91*/9293struct p11_rsa {94struct p11_module *p;95struct p11_slot *slot;96CK_OBJECT_HANDLE private_key;97CK_OBJECT_HANDLE public_key;98};99100static int101p11_rsa_public_encrypt(int flen,102const unsigned char *from,103unsigned char *to,104RSA *rsa,105int padding)106{107return -1;108}109110static int111p11_rsa_public_decrypt(int flen,112const unsigned char *from,113unsigned char *to,114RSA *rsa,115int padding)116{117return -1;118}119120121static int122p11_rsa_private_encrypt(int flen,123const unsigned char *from,124unsigned char *to,125RSA *rsa,126int padding)127{128struct p11_rsa *p11rsa = RSA_get_app_data(rsa);129CK_OBJECT_HANDLE key = p11rsa->private_key;130CK_SESSION_HANDLE session;131CK_MECHANISM mechanism;132CK_ULONG ck_sigsize;133int ret;134135if (padding != RSA_PKCS1_PADDING)136return -1;137138memset(&mechanism, 0, sizeof(mechanism));139mechanism.mechanism = CKM_RSA_PKCS;140141ck_sigsize = RSA_size(rsa);142143ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);144if (ret)145return -1;146147ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));148if (ret != CKR_OK) {149p11_put_session(p11rsa->p, p11rsa->slot, session);150return -1;151}152153ret = P11FUNC(p11rsa->p, Sign,154(session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));155p11_put_session(p11rsa->p, p11rsa->slot, session);156if (ret != CKR_OK)157return -1;158159return ck_sigsize;160}161162static int163p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,164RSA * rsa, int padding)165{166struct p11_rsa *p11rsa = RSA_get_app_data(rsa);167CK_OBJECT_HANDLE key = p11rsa->private_key;168CK_SESSION_HANDLE session;169CK_MECHANISM mechanism;170CK_ULONG ck_sigsize;171int ret;172173if (padding != RSA_PKCS1_PADDING)174return -1;175176memset(&mechanism, 0, sizeof(mechanism));177mechanism.mechanism = CKM_RSA_PKCS;178179ck_sigsize = RSA_size(rsa);180181ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);182if (ret)183return -1;184185ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));186if (ret != CKR_OK) {187p11_put_session(p11rsa->p, p11rsa->slot, session);188return -1;189}190191ret = P11FUNC(p11rsa->p, Decrypt,192(session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));193p11_put_session(p11rsa->p, p11rsa->slot, session);194if (ret != CKR_OK)195return -1;196197return ck_sigsize;198}199200static int201p11_rsa_init(RSA *rsa)202{203return 1;204}205206static int207p11_rsa_finish(RSA *rsa)208{209struct p11_rsa *p11rsa = RSA_get_app_data(rsa);210p11_release_module(p11rsa->p);211free(p11rsa);212return 1;213}214215static const RSA_METHOD *216get_p11_rsa_pkcs1_method(void)217{218static const RSA_METHOD *p11_rsa_pkcs1_method;219RSA_METHOD *new_method;220221if (p11_rsa_pkcs1_method != NULL)222return p11_rsa_pkcs1_method;223224new_method = RSA_meth_new("hx509 PKCS11 PKCS#1 RSA", 0);225if (new_method == NULL)226return NULL;227228if (RSA_meth_set_pub_enc(new_method, p11_rsa_public_encrypt) != 1)229goto out;230231if (RSA_meth_set_pub_dec(new_method, p11_rsa_public_decrypt) != 1)232goto out;233234if (RSA_meth_set_priv_enc(new_method, p11_rsa_private_encrypt) != 1)235goto out;236237if (RSA_meth_set_priv_dec(new_method, p11_rsa_private_decrypt) != 1)238goto out;239240if (RSA_meth_set_init(new_method, p11_rsa_init) != 1)241goto out;242243if (RSA_meth_set_finish(new_method, p11_rsa_finish) != 1)244goto out;245246/*247* This might overwrite a previously-created method if multiple248* threads invoke this concurrently which will leak memory.249*/250p11_rsa_pkcs1_method = new_method;251return p11_rsa_pkcs1_method;252out:253RSA_meth_free(new_method);254return NULL;255}256257/*258*259*/260261static int262p11_mech_info(hx509_context context,263struct p11_module *p,264struct p11_slot *slot,265int num)266{267CK_ULONG i;268int ret;269270ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));271if (ret) {272hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,273"Failed to get mech list count for slot %d",274num);275return HX509_PKCS11_NO_MECH;276}277if (i == 0) {278hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,279"no mech supported for slot %d", num);280return HX509_PKCS11_NO_MECH;281}282slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));283if (slot->mechs.list == NULL) {284hx509_set_error_string(context, 0, ENOMEM,285"out of memory");286return ENOMEM;287}288slot->mechs.num = i;289ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));290if (ret) {291hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,292"Failed to get mech list for slot %d",293num);294return HX509_PKCS11_NO_MECH;295}296assert(i == slot->mechs.num);297298slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));299if (slot->mechs.list == NULL) {300hx509_set_error_string(context, 0, ENOMEM,301"out of memory");302return ENOMEM;303}304305for (i = 0; i < slot->mechs.num; i++) {306slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));307if (slot->mechs.infos[i] == NULL) {308hx509_set_error_string(context, 0, ENOMEM,309"out of memory");310return ENOMEM;311}312ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],313slot->mechs.infos[i]));314if (ret) {315hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,316"Failed to get mech info for slot %d",317num);318return HX509_PKCS11_NO_MECH;319}320}321322return 0;323}324325static int326p11_init_slot(hx509_context context,327struct p11_module *p,328hx509_lock lock,329CK_SLOT_ID id,330int num,331struct p11_slot *slot)332{333CK_SESSION_HANDLE session;334CK_SLOT_INFO slot_info;335CK_TOKEN_INFO token_info;336size_t i;337int ret;338339slot->certs = NULL;340slot->id = id;341342ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));343if (ret) {344hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,345"Failed to init PKCS11 slot %d",346num);347return HX509_PKCS11_TOKEN_CONFUSED;348}349350for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {351char c = slot_info.slotDescription[i];352if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')353continue;354i++;355break;356}357358asprintf(&slot->name, "%.*s",359(int)i, slot_info.slotDescription);360361if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)362return 0;363364ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));365if (ret) {366hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,367"Failed to init PKCS11 slot %d "368"with error 0x08x",369num, ret);370return HX509_PKCS11_NO_TOKEN;371}372slot->flags |= P11_TOKEN_PRESENT;373374if (token_info.flags & CKF_LOGIN_REQUIRED)375slot->flags |= P11_LOGIN_REQ;376377ret = p11_get_session(context, p, slot, lock, &session);378if (ret)379return ret;380381ret = p11_mech_info(context, p, slot, num);382if (ret)383goto out;384385ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);386out:387p11_put_session(p, slot, session);388389return ret;390}391392static int393p11_get_session(hx509_context context,394struct p11_module *p,395struct p11_slot *slot,396hx509_lock lock,397CK_SESSION_HANDLE *psession)398{399CK_RV ret;400401if (slot->flags & P11_SESSION_IN_USE)402_hx509_abort("slot already in session");403404if (slot->flags & P11_SESSION) {405slot->flags |= P11_SESSION_IN_USE;406*psession = slot->session;407return 0;408}409410ret = P11FUNC(p, OpenSession, (slot->id,411CKF_SERIAL_SESSION,412NULL,413NULL,414&slot->session));415if (ret != CKR_OK) {416if (context)417hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,418"Failed to OpenSession for slot id %d "419"with error: 0x%08x",420(int)slot->id, ret);421return HX509_PKCS11_OPEN_SESSION;422}423424slot->flags |= P11_SESSION;425426/*427* If we have have to login, and haven't tried before and have a428* prompter or known to work pin code.429*430* This code is very conversative and only uses the prompter in431* the hx509_lock, the reason is that it's bad to try many432* passwords on a pkcs11 token, it might lock up and have to be433* unlocked by a administrator.434*435* XXX try harder to not use pin several times on the same card.436*/437438if ( (slot->flags & P11_LOGIN_REQ)439&& (slot->flags & P11_LOGIN_DONE) == 0440&& (lock || slot->pin))441{442hx509_prompt prompt;443char pin[20];444char *str;445446if (slot->pin == NULL) {447448memset(&prompt, 0, sizeof(prompt));449450asprintf(&str, "PIN code for %s: ", slot->name);451prompt.prompt = str;452prompt.type = HX509_PROMPT_TYPE_PASSWORD;453prompt.reply.data = pin;454prompt.reply.length = sizeof(pin);455456ret = hx509_lock_prompt(lock, &prompt);457if (ret) {458free(str);459if (context)460hx509_set_error_string(context, 0, ret,461"Failed to get pin code for slot "462"id %d with error: %d",463(int)slot->id, ret);464return ret;465}466free(str);467} else {468strlcpy(pin, slot->pin, sizeof(pin));469}470471ret = P11FUNC(p, Login, (slot->session, CKU_USER,472(unsigned char*)pin, strlen(pin)));473if (ret != CKR_OK) {474if (context)475hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,476"Failed to login on slot id %d "477"with error: 0x%08x",478(int)slot->id, ret);479return HX509_PKCS11_LOGIN;480} else481slot->flags |= P11_LOGIN_DONE;482483if (slot->pin == NULL) {484slot->pin = strdup(pin);485if (slot->pin == NULL) {486if (context)487hx509_set_error_string(context, 0, ENOMEM,488"out of memory");489return ENOMEM;490}491}492} else493slot->flags |= P11_LOGIN_DONE;494495slot->flags |= P11_SESSION_IN_USE;496497*psession = slot->session;498499return 0;500}501502static int503p11_put_session(struct p11_module *p,504struct p11_slot *slot,505CK_SESSION_HANDLE session)506{507if ((slot->flags & P11_SESSION_IN_USE) == 0)508_hx509_abort("slot not in session");509slot->flags &= ~P11_SESSION_IN_USE;510511return 0;512}513514static int515iterate_entries(hx509_context context,516struct p11_module *p, struct p11_slot *slot,517CK_SESSION_HANDLE session,518CK_ATTRIBUTE *search_data, int num_search_data,519CK_ATTRIBUTE *query, int num_query,520int (*func)(hx509_context,521struct p11_module *, struct p11_slot *,522CK_SESSION_HANDLE session,523CK_OBJECT_HANDLE object,524void *, CK_ATTRIBUTE *, int), void *ptr)525{526CK_OBJECT_HANDLE object;527CK_ULONG object_count;528int ret, ret2, i;529530ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));531if (ret != CKR_OK) {532return -1;533}534while (1) {535ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));536if (ret != CKR_OK) {537return -1;538}539if (object_count == 0)540break;541542for (i = 0; i < num_query; i++)543query[i].pValue = NULL;544545ret = P11FUNC(p, GetAttributeValue,546(session, object, query, num_query));547if (ret != CKR_OK) {548return -1;549}550for (i = 0; i < num_query; i++) {551query[i].pValue = malloc(query[i].ulValueLen);552if (query[i].pValue == NULL) {553ret = ENOMEM;554goto out;555}556}557ret = P11FUNC(p, GetAttributeValue,558(session, object, query, num_query));559if (ret != CKR_OK) {560ret = -1;561goto out;562}563564ret = (*func)(context, p, slot, session, object, ptr, query, num_query);565if (ret)566goto out;567568for (i = 0; i < num_query; i++) {569if (query[i].pValue)570free(query[i].pValue);571query[i].pValue = NULL;572}573}574out:575576for (i = 0; i < num_query; i++) {577if (query[i].pValue)578free(query[i].pValue);579query[i].pValue = NULL;580}581582ret2 = P11FUNC(p, FindObjectsFinal, (session));583if (ret2 != CKR_OK) {584return ret2;585}586587return ret;588}589590static BIGNUM *591getattr_bn(struct p11_module *p,592struct p11_slot *slot,593CK_SESSION_HANDLE session,594CK_OBJECT_HANDLE object,595unsigned int type)596{597CK_ATTRIBUTE query;598BIGNUM *bn;599int ret;600601query.type = type;602query.pValue = NULL;603query.ulValueLen = 0;604605ret = P11FUNC(p, GetAttributeValue,606(session, object, &query, 1));607if (ret != CKR_OK)608return NULL;609610query.pValue = malloc(query.ulValueLen);611612ret = P11FUNC(p, GetAttributeValue,613(session, object, &query, 1));614if (ret != CKR_OK) {615free(query.pValue);616return NULL;617}618bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);619free(query.pValue);620621return bn;622}623624static int625collect_private_key(hx509_context context,626struct p11_module *p, struct p11_slot *slot,627CK_SESSION_HANDLE session,628CK_OBJECT_HANDLE object,629void *ptr, CK_ATTRIBUTE *query, int num_query)630{631struct hx509_collector *collector = ptr;632hx509_private_key key;633heim_octet_string localKeyId;634int ret;635const RSA_METHOD *meth;636BIGNUM *n, *e;637RSA *rsa;638struct p11_rsa *p11rsa;639640localKeyId.data = query[0].pValue;641localKeyId.length = query[0].ulValueLen;642643ret = hx509_private_key_init(&key, NULL, NULL);644if (ret)645return ret;646647rsa = RSA_new();648if (rsa == NULL)649_hx509_abort("out of memory");650651/*652* The exponent and modulus should always be present according to653* the pkcs11 specification, but some smartcards leaves it out,654* let ignore any failure to fetch it.655*/656n = getattr_bn(p, slot, session, object, CKA_MODULUS);657e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);658if (RSA_set0_key(rsa, n, e, NULL) != 1) {659BN_free(n);660BN_free(e);661RSA_free(rsa);662hx509_private_key_free(&key);663return EINVAL;664}665666p11rsa = calloc(1, sizeof(*p11rsa));667if (p11rsa == NULL)668_hx509_abort("out of memory");669670p11rsa->p = p;671p11rsa->slot = slot;672p11rsa->private_key = object;673674if (p->ref == 0)675_hx509_abort("pkcs11 ref == 0 on alloc");676p->ref++;677if (p->ref == UINT_MAX)678_hx509_abort("pkcs11 ref == UINT_MAX on alloc");679680meth = get_p11_rsa_pkcs1_method();681if (meth == NULL)682_hx509_abort("failed to create RSA method");683RSA_set_method(rsa, meth);684ret = RSA_set_app_data(rsa, p11rsa);685if (ret != 1)686_hx509_abort("RSA_set_app_data");687688hx509_private_key_assign_rsa(key, rsa);689690ret = _hx509_collector_private_key_add(context,691collector,692hx509_signature_rsa(),693key,694NULL,695&localKeyId);696697if (ret) {698hx509_private_key_free(&key);699return ret;700}701return 0;702}703704static void705p11_cert_release(hx509_cert cert, void *ctx)706{707struct p11_module *p = ctx;708p11_release_module(p);709}710711712static int713collect_cert(hx509_context context,714struct p11_module *p, struct p11_slot *slot,715CK_SESSION_HANDLE session,716CK_OBJECT_HANDLE object,717void *ptr, CK_ATTRIBUTE *query, int num_query)718{719struct hx509_collector *collector = ptr;720hx509_cert cert;721int ret;722723if ((CK_LONG)query[0].ulValueLen == -1 ||724(CK_LONG)query[1].ulValueLen == -1)725{726return 0;727}728729ret = hx509_cert_init_data(context, query[1].pValue,730query[1].ulValueLen, &cert);731if (ret)732return ret;733734if (p->ref == 0)735_hx509_abort("pkcs11 ref == 0 on alloc");736p->ref++;737if (p->ref == UINT_MAX)738_hx509_abort("pkcs11 ref to high");739740_hx509_cert_set_release(cert, p11_cert_release, p);741742{743heim_octet_string data;744745data.data = query[0].pValue;746data.length = query[0].ulValueLen;747748_hx509_set_cert_attribute(context,749cert,750&asn1_oid_id_pkcs_9_at_localKeyId,751&data);752}753754if ((CK_LONG)query[2].ulValueLen != -1) {755char *str;756757asprintf(&str, "%.*s",758(int)query[2].ulValueLen, (char *)query[2].pValue);759if (str) {760hx509_cert_set_friendly_name(cert, str);761free(str);762}763}764765ret = _hx509_collector_certs_add(context, collector, cert);766hx509_cert_free(cert);767768return ret;769}770771772static int773p11_list_keys(hx509_context context,774struct p11_module *p,775struct p11_slot *slot,776CK_SESSION_HANDLE session,777hx509_lock lock,778hx509_certs *certs)779{780struct hx509_collector *collector;781CK_OBJECT_CLASS key_class;782CK_ATTRIBUTE search_data[] = {783{CKA_CLASS, NULL, 0},784};785CK_ATTRIBUTE query_data[3] = {786{CKA_ID, NULL, 0},787{CKA_VALUE, NULL, 0},788{CKA_LABEL, NULL, 0}789};790int ret;791792search_data[0].pValue = &key_class;793search_data[0].ulValueLen = sizeof(key_class);794795if (lock == NULL)796lock = _hx509_empty_lock;797798ret = _hx509_collector_alloc(context, lock, &collector);799if (ret)800return ret;801802key_class = CKO_PRIVATE_KEY;803ret = iterate_entries(context, p, slot, session,804search_data, 1,805query_data, 1,806collect_private_key, collector);807if (ret)808goto out;809810key_class = CKO_CERTIFICATE;811ret = iterate_entries(context, p, slot, session,812search_data, 1,813query_data, 3,814collect_cert, collector);815if (ret)816goto out;817818ret = _hx509_collector_collect_certs(context, collector, &slot->certs);819820out:821_hx509_collector_free(collector);822823return ret;824}825826827static int828p11_init(hx509_context context,829hx509_certs certs, void **data, int flags,830const char *residue, hx509_lock lock)831{832CK_C_GetFunctionList getFuncs;833struct p11_module *p;834char *list, *str;835int ret;836837*data = NULL;838839list = strdup(residue);840if (list == NULL)841return ENOMEM;842843p = calloc(1, sizeof(*p));844if (p == NULL) {845free(list);846return ENOMEM;847}848849p->ref = 1;850851str = strchr(list, ',');852if (str)853*str++ = '\0';854while (str) {855char *strnext;856strnext = strchr(str, ',');857if (strnext)858*strnext++ = '\0';859#if 0860if (strncasecmp(str, "slot=", 5) == 0)861p->selected_slot = atoi(str + 5);862#endif863str = strnext;864}865866p->dl_handle = dlopen(list, RTLD_NOW);867free(list);868if (p->dl_handle == NULL) {869ret = HX509_PKCS11_LOAD;870hx509_set_error_string(context, 0, ret,871"Failed to open %s: %s", list, dlerror());872goto out;873}874875getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");876if (getFuncs == NULL) {877ret = HX509_PKCS11_LOAD;878hx509_set_error_string(context, 0, ret,879"C_GetFunctionList missing in %s: %s",880list, dlerror());881goto out;882}883884ret = (*getFuncs)(&p->funcs);885if (ret) {886ret = HX509_PKCS11_LOAD;887hx509_set_error_string(context, 0, ret,888"C_GetFunctionList failed in %s", list);889goto out;890}891892ret = P11FUNC(p, Initialize, (NULL_PTR));893if (ret != CKR_OK) {894ret = HX509_PKCS11_TOKEN_CONFUSED;895hx509_set_error_string(context, 0, ret,896"Failed initialize the PKCS11 module");897goto out;898}899900ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));901if (ret) {902ret = HX509_PKCS11_TOKEN_CONFUSED;903hx509_set_error_string(context, 0, ret,904"Failed to get number of PKCS11 slots");905goto out;906}907908if (p->num_slots == 0) {909ret = HX509_PKCS11_NO_SLOT;910hx509_set_error_string(context, 0, ret,911"Selected PKCS11 module have no slots");912goto out;913}914915916{917CK_SLOT_ID_PTR slot_ids;918int num_tokens = 0;919size_t i;920921slot_ids = malloc(p->num_slots * sizeof(*slot_ids));922if (slot_ids == NULL) {923hx509_clear_error_string(context);924ret = ENOMEM;925goto out;926}927928ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));929if (ret) {930free(slot_ids);931hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,932"Failed getting slot-list from "933"PKCS11 module");934ret = HX509_PKCS11_TOKEN_CONFUSED;935goto out;936}937938p->slot = calloc(p->num_slots, sizeof(p->slot[0]));939if (p->slot == NULL) {940free(slot_ids);941hx509_set_error_string(context, 0, ENOMEM,942"Failed to get memory for slot-list");943ret = ENOMEM;944goto out;945}946947for (i = 0; i < p->num_slots; i++) {948ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);949if (ret)950break;951if (p->slot[i].flags & P11_TOKEN_PRESENT)952num_tokens++;953}954free(slot_ids);955if (ret)956goto out;957if (num_tokens == 0) {958ret = HX509_PKCS11_NO_TOKEN;959goto out;960}961}962963*data = p;964965return 0;966out:967p11_release_module(p);968return ret;969}970971static void972p11_release_module(struct p11_module *p)973{974size_t i;975976if (p->ref == 0)977_hx509_abort("pkcs11 ref to low");978if (--p->ref > 0)979return;980981for (i = 0; i < p->num_slots; i++) {982if (p->slot[i].flags & P11_SESSION_IN_USE)983_hx509_abort("pkcs11 module release while session in use");984if (p->slot[i].flags & P11_SESSION) {985P11FUNC(p, CloseSession, (p->slot[i].session));986}987988if (p->slot[i].name)989free(p->slot[i].name);990if (p->slot[i].pin) {991memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));992free(p->slot[i].pin);993}994if (p->slot[i].mechs.num) {995free(p->slot[i].mechs.list);996997if (p->slot[i].mechs.infos) {998size_t j;9991000for (j = 0 ; j < p->slot[i].mechs.num ; j++)1001free(p->slot[i].mechs.infos[j]);1002free(p->slot[i].mechs.infos);1003}1004}1005}1006free(p->slot);10071008if (p->funcs)1009P11FUNC(p, Finalize, (NULL));10101011if (p->dl_handle)1012dlclose(p->dl_handle);10131014memset(p, 0, sizeof(*p));1015free(p);1016}10171018static int1019p11_free(hx509_certs certs, void *data)1020{1021struct p11_module *p = data;1022size_t i;10231024for (i = 0; i < p->num_slots; i++) {1025if (p->slot[i].certs)1026hx509_certs_free(&p->slot[i].certs);1027}1028p11_release_module(p);1029return 0;1030}10311032struct p11_cursor {1033hx509_certs certs;1034void *cursor;1035};10361037static int1038p11_iter_start(hx509_context context,1039hx509_certs certs, void *data, void **cursor)1040{1041struct p11_module *p = data;1042struct p11_cursor *c;1043int ret;1044size_t i;10451046c = malloc(sizeof(*c));1047if (c == NULL) {1048hx509_clear_error_string(context);1049return ENOMEM;1050}1051ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);1052if (ret) {1053free(c);1054return ret;1055}10561057for (i = 0 ; i < p->num_slots; i++) {1058if (p->slot[i].certs == NULL)1059continue;1060ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);1061if (ret) {1062hx509_certs_free(&c->certs);1063free(c);1064return ret;1065}1066}10671068ret = hx509_certs_start_seq(context, c->certs, &c->cursor);1069if (ret) {1070hx509_certs_free(&c->certs);1071free(c);1072return 0;1073}1074*cursor = c;10751076return 0;1077}10781079static int1080p11_iter(hx509_context context,1081hx509_certs certs, void *data, void *cursor, hx509_cert *cert)1082{1083struct p11_cursor *c = cursor;1084return hx509_certs_next_cert(context, c->certs, c->cursor, cert);1085}10861087static int1088p11_iter_end(hx509_context context,1089hx509_certs certs, void *data, void *cursor)1090{1091struct p11_cursor *c = cursor;1092int ret;1093ret = hx509_certs_end_seq(context, c->certs, c->cursor);1094hx509_certs_free(&c->certs);1095free(c);1096return ret;1097}10981099#define MECHFLAG(x) { "unknown-flag-" #x, x }1100static struct units mechflags[] = {1101MECHFLAG(0x80000000),1102MECHFLAG(0x40000000),1103MECHFLAG(0x20000000),1104MECHFLAG(0x10000000),1105MECHFLAG(0x08000000),1106MECHFLAG(0x04000000),1107{"ec-compress", 0x2000000 },1108{"ec-uncompress", 0x1000000 },1109{"ec-namedcurve", 0x0800000 },1110{"ec-ecparameters", 0x0400000 },1111{"ec-f-2m", 0x0200000 },1112{"ec-f-p", 0x0100000 },1113{"derive", 0x0080000 },1114{"unwrap", 0x0040000 },1115{"wrap", 0x0020000 },1116{"genereate-key-pair", 0x0010000 },1117{"generate", 0x0008000 },1118{"verify-recover", 0x0004000 },1119{"verify", 0x0002000 },1120{"sign-recover", 0x0001000 },1121{"sign", 0x0000800 },1122{"digest", 0x0000400 },1123{"decrypt", 0x0000200 },1124{"encrypt", 0x0000100 },1125MECHFLAG(0x00080),1126MECHFLAG(0x00040),1127MECHFLAG(0x00020),1128MECHFLAG(0x00010),1129MECHFLAG(0x00008),1130MECHFLAG(0x00004),1131MECHFLAG(0x00002),1132{"hw", 0x0000001 },1133{ NULL, 0x0000000 }1134};1135#undef MECHFLAG11361137static int1138p11_printinfo(hx509_context context,1139hx509_certs certs,1140void *data,1141int (*func)(void *, const char *),1142void *ctx)1143{1144struct p11_module *p = data;1145size_t i, j;11461147_hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",1148p->num_slots, p->num_slots > 1 ? "s" : "");11491150for (i = 0; i < p->num_slots; i++) {1151struct p11_slot *s = &p->slot[i];11521153_hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",1154i, (int)s->id, s->name, s->flags);11551156_hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",1157(unsigned long)s->mechs.num);1158for (j = 0; j < s->mechs.num; j++) {1159const char *mechname = "unknown";1160char flags[256], unknownname[40];1161#define MECHNAME(s,n) case s: mechname = n; break1162switch(s->mechs.list[j]) {1163MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");1164MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");1165MECHNAME(CKM_RSA_X_509, "rsa-x-509");1166MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");1167MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");1168MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");1169MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");1170MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");1171MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");1172MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");1173MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");1174MECHNAME(CKM_SHA512, "sha512");1175MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");1176MECHNAME(CKM_SHA384, "sha384");1177MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");1178MECHNAME(CKM_SHA256, "sha256");1179MECHNAME(CKM_SHA_1, "sha1");1180MECHNAME(CKM_MD5, "md5");1181MECHNAME(CKM_RIPEMD160, "ripemd-160");1182MECHNAME(CKM_DES_ECB, "des-ecb");1183MECHNAME(CKM_DES_CBC, "des-cbc");1184MECHNAME(CKM_AES_ECB, "aes-ecb");1185MECHNAME(CKM_AES_CBC, "aes-cbc");1186MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");1187default:1188snprintf(unknownname, sizeof(unknownname),1189"unknown-mech-%lu",1190(unsigned long)s->mechs.list[j]);1191mechname = unknownname;1192break;1193}1194#undef MECHNAME1195unparse_flags(s->mechs.infos[j]->flags, mechflags,1196flags, sizeof(flags));11971198_hx509_pi_printf(func, ctx, " %s: %s", mechname, flags);1199}1200}12011202return 0;1203}12041205static struct hx509_keyset_ops keyset_pkcs11 = {1206"PKCS11",12070,1208p11_init,1209NULL,1210p11_free,1211NULL,1212NULL,1213p11_iter_start,1214p11_iter,1215p11_iter_end,1216p11_printinfo1217};12181219#endif /* HAVE_DLOPEN */12201221void1222_hx509_ks_pkcs11_register(hx509_context context)1223{1224#ifdef HAVE_DLOPEN1225_hx509_ks_register(context, &keyset_pkcs11);1226#endif1227}122812291230