📄 ks_p11.c
字号:
/* * Copyright (c) 2004 - 2006 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "hx_locl.h"RCSID("$Id: ks_p11.c 22071 2007-11-14 20:04:50Z lha $");#ifdef HAVE_DLFCN_H#include <dlfcn.h>#endif#ifdef HAVE_DLOPEN#include "pkcs11.h"struct p11_slot { int flags;#define P11_SESSION 1#define P11_SESSION_IN_USE 2#define P11_LOGIN_REQ 4#define P11_LOGIN_DONE 8#define P11_TOKEN_PRESENT 16 CK_SESSION_HANDLE session; CK_SLOT_ID id; CK_BBOOL token; char *name; hx509_certs certs; char *pin; struct { CK_MECHANISM_TYPE_PTR list; CK_ULONG num; CK_MECHANISM_INFO_PTR *infos; } mechs;};struct p11_module { void *dl_handle; CK_FUNCTION_LIST_PTR funcs; CK_ULONG num_slots; unsigned int refcount; struct p11_slot *slot;};#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)argsstatic int p11_get_session(hx509_context, struct p11_module *, struct p11_slot *, hx509_lock, CK_SESSION_HANDLE *);static int p11_put_session(struct p11_module *, struct p11_slot *, CK_SESSION_HANDLE);static void p11_release_module(struct p11_module *);static int p11_list_keys(hx509_context, struct p11_module *, struct p11_slot *, CK_SESSION_HANDLE, hx509_lock, hx509_certs *);/* * */struct p11_rsa { struct p11_module *p; struct p11_slot *slot; CK_OBJECT_HANDLE private_key; CK_OBJECT_HANDLE public_key;};static intp11_rsa_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding){ return -1;}static intp11_rsa_public_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding){ return -1;}static intp11_rsa_private_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding){ struct p11_rsa *p11rsa = RSA_get_app_data(rsa); CK_OBJECT_HANDLE key = p11rsa->private_key; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ULONG ck_sigsize; int ret; if (padding != RSA_PKCS1_PADDING) return -1; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = CKM_RSA_PKCS; ck_sigsize = RSA_size(rsa); ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); if (ret) return -1; ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key)); if (ret != CKR_OK) { p11_put_session(p11rsa->p, p11rsa->slot, session); return -1; } ret = P11FUNC(p11rsa->p, Sign, (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); p11_put_session(p11rsa->p, p11rsa->slot, session); if (ret != CKR_OK) return -1; return ck_sigsize;}static intp11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding){ struct p11_rsa *p11rsa = RSA_get_app_data(rsa); CK_OBJECT_HANDLE key = p11rsa->private_key; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ULONG ck_sigsize; int ret; if (padding != RSA_PKCS1_PADDING) return -1; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = CKM_RSA_PKCS; ck_sigsize = RSA_size(rsa); ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); if (ret) return -1; ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key)); if (ret != CKR_OK) { p11_put_session(p11rsa->p, p11rsa->slot, session); return -1; } ret = P11FUNC(p11rsa->p, Decrypt, (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); p11_put_session(p11rsa->p, p11rsa->slot, session); if (ret != CKR_OK) return -1; return ck_sigsize;}static int p11_rsa_init(RSA *rsa){ return 1;}static intp11_rsa_finish(RSA *rsa){ struct p11_rsa *p11rsa = RSA_get_app_data(rsa); p11_release_module(p11rsa->p); free(p11rsa); return 1;}static const RSA_METHOD p11_rsa_pkcs1_method = { "hx509 PKCS11 PKCS#1 RSA", p11_rsa_public_encrypt, p11_rsa_public_decrypt, p11_rsa_private_encrypt, p11_rsa_private_decrypt, NULL, NULL, p11_rsa_init, p11_rsa_finish, 0, NULL, NULL, NULL};/* * */static intp11_mech_info(hx509_context context, struct p11_module *p, struct p11_slot *slot, int num){ CK_ULONG i; int ret; ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); if (ret) { hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, "Failed to get mech list count for slot %d", num); return HX509_PKCS11_NO_MECH; } if (i == 0) { hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, "no mech supported for slot %d", num); return HX509_PKCS11_NO_MECH; } slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); if (slot->mechs.list == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } slot->mechs.num = i; ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); if (ret) { hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, "Failed to get mech list for slot %d", num); return HX509_PKCS11_NO_MECH; } assert(i == slot->mechs.num); slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); if (slot->mechs.list == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } for (i = 0; i < slot->mechs.num; i++) { slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); if (slot->mechs.infos[i] == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], slot->mechs.infos[i])); if (ret) { hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, "Failed to get mech info for slot %d", num); return HX509_PKCS11_NO_MECH; } } return 0;}static intp11_init_slot(hx509_context context, struct p11_module *p, hx509_lock lock, CK_SLOT_ID id, int num, struct p11_slot *slot){ CK_SESSION_HANDLE session; CK_SLOT_INFO slot_info; CK_TOKEN_INFO token_info; int ret, i; slot->certs = NULL; slot->id = id; ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); if (ret) { hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, "Failed to init PKCS11 slot %d", num); return HX509_PKCS11_TOKEN_CONFUSED; } for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { char c = slot_info.slotDescription[i]; if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') continue; i++; break; } asprintf(&slot->name, "%.*s", i, slot_info.slotDescription); if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) return 0; ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); if (ret) { hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, "Failed to init PKCS11 slot %d " "with error 0x08x", num, ret); return HX509_PKCS11_NO_TOKEN; } slot->flags |= P11_TOKEN_PRESENT; if (token_info.flags & CKF_LOGIN_REQUIRED) slot->flags |= P11_LOGIN_REQ; ret = p11_get_session(context, p, slot, lock, &session); if (ret) return ret; ret = p11_mech_info(context, p, slot, num); if (ret) goto out; ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); out: p11_put_session(p, slot, session); return ret;}static intp11_get_session(hx509_context context, struct p11_module *p, struct p11_slot *slot, hx509_lock lock, CK_SESSION_HANDLE *psession){ CK_RV ret; if (slot->flags & P11_SESSION_IN_USE) _hx509_abort("slot already in session"); if (slot->flags & P11_SESSION) { slot->flags |= P11_SESSION_IN_USE; *psession = slot->session; return 0; } ret = P11FUNC(p, OpenSession, (slot->id, CKF_SERIAL_SESSION, NULL, NULL, &slot->session)); if (ret != CKR_OK) { if (context) hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, "Failed to OpenSession for slot id %d " "with error: 0x%08x", (int)slot->id, ret); return HX509_PKCS11_OPEN_SESSION; } slot->flags |= P11_SESSION; /* * If we have have to login, and haven't tried before and have a * prompter or known to work pin code. * * This code is very conversative and only uses the prompter in * the hx509_lock, the reason is that it's bad to try many * passwords on a pkcs11 token, it might lock up and have to be * unlocked by a administrator. * * XXX try harder to not use pin several times on the same card. */ if ( (slot->flags & P11_LOGIN_REQ) && (slot->flags & P11_LOGIN_DONE) == 0 && (lock || slot->pin)) { hx509_prompt prompt; char pin[20]; char *str; slot->flags |= P11_LOGIN_DONE; if (slot->pin == NULL) { memset(&prompt, 0, sizeof(prompt)); asprintf(&str, "PIN code for %s: ", slot->name); prompt.prompt = str; prompt.type = HX509_PROMPT_TYPE_PASSWORD; prompt.reply.data = pin; prompt.reply.length = sizeof(pin); ret = hx509_lock_prompt(lock, &prompt); if (ret) { free(str); if (context) hx509_set_error_string(context, 0, ret, "Failed to get pin code for slot " "id %d with error: %d", (int)slot->id, ret); return ret; } free(str); } else { strlcpy(pin, slot->pin, sizeof(pin)); } ret = P11FUNC(p, Login, (slot->session, CKU_USER, (unsigned char*)pin, strlen(pin))); if (ret != CKR_OK) { if (context) hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, "Failed to login on slot id %d " "with error: 0x%08x", (int)slot->id, ret); p11_put_session(p, slot, slot->session); return HX509_PKCS11_LOGIN; } if (slot->pin == NULL) { slot->pin = strdup(pin); if (slot->pin == NULL) { if (context) hx509_set_error_string(context, 0, ENOMEM, "out of memory"); p11_put_session(p, slot, slot->session); return ENOMEM; } } } else slot->flags |= P11_LOGIN_DONE; slot->flags |= P11_SESSION_IN_USE; *psession = slot->session; return 0;}static intp11_put_session(struct p11_module *p, struct p11_slot *slot, CK_SESSION_HANDLE session){ if ((slot->flags & P11_SESSION_IN_USE) == 0) _hx509_abort("slot not in session"); slot->flags &= ~P11_SESSION_IN_USE; return 0;}static intiterate_entries(hx509_context context, struct p11_module *p, struct p11_slot *slot, CK_SESSION_HANDLE session, CK_ATTRIBUTE *search_data, int num_search_data, CK_ATTRIBUTE *query, int num_query, int (*func)(hx509_context, struct p11_module *, struct p11_slot *, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, void *, CK_ATTRIBUTE *, int), void *ptr){ CK_OBJECT_HANDLE object; CK_ULONG object_count; int ret, i; ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data)); if (ret != CKR_OK) { return -1; } while (1) { ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count)); if (ret != CKR_OK) { return -1; } if (object_count == 0) break; for (i = 0; i < num_query; i++) query[i].pValue = NULL; ret = P11FUNC(p, GetAttributeValue, (session, object, query, num_query)); if (ret != CKR_OK) { return -1; } for (i = 0; i < num_query; i++) { query[i].pValue = malloc(query[i].ulValueLen); if (query[i].pValue == NULL) { ret = ENOMEM; goto out; } } ret = P11FUNC(p, GetAttributeValue, (session, object, query, num_query)); if (ret != CKR_OK) { ret = -1; goto out; } ret = (*func)(context, p, slot, session, object, ptr, query, num_query); if (ret) goto out; for (i = 0; i < num_query; i++) { if (query[i].pValue) free(query[i].pValue); query[i].pValue = NULL; } } out: for (i = 0; i < num_query; i++) { if (query[i].pValue) free(query[i].pValue); query[i].pValue = NULL; } ret = P11FUNC(p, FindObjectsFinal, (session)); if (ret != CKR_OK) { return -2; } return 0;} static BIGNUM *getattr_bn(struct p11_module *p, struct p11_slot *slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, unsigned int type){ CK_ATTRIBUTE query; BIGNUM *bn; int ret; query.type = type; query.pValue = NULL; query.ulValueLen = 0; ret = P11FUNC(p, GetAttributeValue, (session, object, &query, 1)); if (ret != CKR_OK) return NULL; query.pValue = malloc(query.ulValueLen); ret = P11FUNC(p, GetAttributeValue, (session, object, &query, 1)); if (ret != CKR_OK) { free(query.pValue); return NULL; } bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); free(query.pValue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -