libhsm.c
Go to the documentation of this file.
/*
* Copyright (c) 2009 .SE (The Internet Infrastructure Foundation).
* Copyright (c) 2009 NLNet Labs.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "config.h"
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <ldns/ldns.h>
#include <ldns/util.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/relaxng.h>
#include "libhsm.h"
#include "libhsmdns.h"
#include "compat.h"
#include "duration.h"
#include "status.h"
#include "utilities.h"
#include <pkcs11.h>
#include <pthread.h>
#define HSM_TOKEN_LABEL_LENGTH 32
hsm_ctx_t *_hsm_ctx;
pthread_mutex_t _hsm_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
static char const *
ldns_pkcs11_rv_str(CK_RV rv)
{
switch (rv)
{
case CKR_OK:
return "CKR_OK";
case CKR_CANCEL:
return "CKR_CANCEL";
case CKR_HOST_MEMORY:
return "CKR_HOST_MEMORY";
case CKR_GENERAL_ERROR:
return "CKR_GENERAL_ERROR";
case CKR_FUNCTION_FAILED:
return "CKR_FUNCTION_FAILED";
case CKR_SLOT_ID_INVALID:
return "CKR_SLOT_ID_INVALID";
case CKR_ATTRIBUTE_READ_ONLY:
return "CKR_ATTRIBUTE_READ_ONLY";
case CKR_ATTRIBUTE_SENSITIVE:
return "CKR_ATTRIBUTE_SENSITIVE";
case CKR_ATTRIBUTE_TYPE_INVALID:
return "CKR_ATTRIBUTE_TYPE_INVALID";
case CKR_ATTRIBUTE_VALUE_INVALID:
return "CKR_ATTRIBUTE_VALUE_INVALID";
case CKR_DATA_INVALID:
return "CKR_DATA_INVALID";
case CKR_DATA_LEN_RANGE:
return "CKR_DATA_LEN_RANGE";
case CKR_DEVICE_ERROR:
return "CKR_DEVICE_ERROR";
case CKR_DEVICE_MEMORY:
return "CKR_DEVICE_MEMORY";
case CKR_DEVICE_REMOVED:
return "CKR_DEVICE_REMOVED";
case CKR_ENCRYPTED_DATA_INVALID:
return "CKR_ENCRYPTED_DATA_INVALID";
case CKR_ENCRYPTED_DATA_LEN_RANGE:
return "CKR_ENCRYPTED_DATA_LEN_RANGE";
case CKR_FUNCTION_CANCELED:
return "CKR_FUNCTION_CANCELED";
case CKR_FUNCTION_NOT_PARALLEL:
return "CKR_FUNCTION_NOT_PARALLEL";
case CKR_FUNCTION_NOT_SUPPORTED:
return "CKR_FUNCTION_NOT_SUPPORTED";
case CKR_KEY_HANDLE_INVALID:
return "CKR_KEY_HANDLE_INVALID";
case CKR_KEY_SIZE_RANGE:
return "CKR_KEY_SIZE_RANGE";
case CKR_KEY_TYPE_INCONSISTENT:
return "CKR_KEY_TYPE_INCONSISTENT";
case CKR_MECHANISM_INVALID:
return "CKR_MECHANISM_INVALID";
case CKR_MECHANISM_PARAM_INVALID:
return "CKR_MECHANISM_PARAM_INVALID";
case CKR_OBJECT_HANDLE_INVALID:
return "CKR_OBJECT_HANDLE_INVALID";
case CKR_OPERATION_ACTIVE:
return "CKR_OPERATION_ACTIVE";
case CKR_OPERATION_NOT_INITIALIZED:
return "CKR_OPERATION_NOT_INITIALIZED";
case CKR_PIN_INCORRECT:
return "CKR_PIN_INCORRECT";
case CKR_PIN_INVALID:
return "CKR_PIN_INVALID";
case CKR_PIN_LEN_RANGE:
return "CKR_PIN_LEN_RANGE";
case CKR_SESSION_CLOSED:
return "CKR_SESSION_CLOSED";
case CKR_SESSION_COUNT:
return "CKR_SESSION_COUNT";
case CKR_SESSION_HANDLE_INVALID:
return "CKR_SESSION_HANDLE_INVALID";
case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
case CKR_SESSION_READ_ONLY:
return "CKR_SESSION_READ_ONLY";
case CKR_SESSION_EXISTS:
return "CKR_SESSION_EXISTS";
case CKR_SIGNATURE_INVALID:
return "CKR_SIGNATURE_INVALID";
case CKR_SIGNATURE_LEN_RANGE:
return "CKR_SIGNATURE_LEN_RANGE";
case CKR_TEMPLATE_INCOMPLETE:
return "CKR_TEMPLATE_INCOMPLETE";
case CKR_TEMPLATE_INCONSISTENT:
return "CKR_TEMPLATE_INCONSISTENT";
case CKR_TOKEN_NOT_PRESENT:
return "CKR_TOKEN_NOT_PRESENT";
case CKR_TOKEN_NOT_RECOGNIZED:
return "CKR_TOKEN_NOT_RECOGNIZED";
case CKR_TOKEN_WRITE_PROTECTED:
return "CKR_TOKEN_WRITE_PROTECTED";
case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
case CKR_UNWRAPPING_KEY_SIZE_RANGE:
return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
case CKR_USER_ALREADY_LOGGED_IN:
return "CKR_USER_ALREADY_LOGGED_IN";
case CKR_USER_NOT_LOGGED_IN:
return "CKR_USER_NOT_LOGGED_IN";
case CKR_USER_PIN_NOT_INITIALIZED:
return "CKR_USER_PIN_NOT_INITIALIZED";
case CKR_USER_TYPE_INVALID:
return "CKR_USER_TYPE_INVALID";
case CKR_WRAPPED_KEY_INVALID:
return "CKR_WRAPPED_KEY_INVALID";
case CKR_WRAPPED_KEY_LEN_RANGE:
return "CKR_WRAPPED_KEY_LEN_RANGE";
case CKR_WRAPPING_KEY_HANDLE_INVALID:
return "CKR_WRAPPING_KEY_HANDLE_INVALID";
case CKR_WRAPPING_KEY_SIZE_RANGE:
return "CKR_WRAPPING_KEY_SIZE_RANGE";
case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
case CKR_RANDOM_SEED_NOT_SUPPORTED:
return "CKR_RANDOM_SEED_NOT_SUPPORTED";
/*CKR_VENDOR_DEFINED is not a constant but a macro which expands in to an */
/*expression. Which we are not allowed to use in a switch.*/
/*case CKR_VENDOR_DEFINED:*/
case 0x80000000:
return "CKR_VENDOR_DEFINED";
case CKR_BUFFER_TOO_SMALL:
return "CKR_BUFFER_TOO_SMALL";
case CKR_SAVED_STATE_INVALID:
return "CKR_SAVED_STATE_INVALID";
case CKR_INFORMATION_SENSITIVE:
return "CKR_INFORMATION_SENSITIVE";
case CKR_STATE_UNSAVEABLE:
return "CKR_STATE_UNSAVEABLE";
case CKR_CRYPTOKI_NOT_INITIALIZED:
return "CKR_CRYPTOKI_NOT_INITIALIZED";
case CKR_CRYPTOKI_ALREADY_INITIALIZED:
return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
case CKR_MUTEX_BAD:
return "CKR_MUTEX_BAD";
case CKR_MUTEX_NOT_LOCKED:
return "CKR_MUTEX_NOT_LOCKED";
default:
return "Unknown error";
}
}
void
hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action,
const char *message, ...)
{
va_list args;
if (ctx && ctx->error == 0) {
ctx->error = error;
ctx->error_action = action;
va_start(args, message);
vsnprintf(ctx->error_message, sizeof(ctx->error_message),
message, args);
va_end(args);
}
}
static int
hsm_pkcs11_check_error(hsm_ctx_t *ctx, CK_RV rv, const char *action)
{
if (rv != CKR_OK) {
if (ctx && ctx->error == 0) {
ctx->error = (int) rv;
ctx->error_action = action;
strlcpy(ctx->error_message, ldns_pkcs11_rv_str(rv), sizeof(ctx->error_message));
}
return 1;
}
return 0;
}
static void
hsm_pkcs11_unload_functions(void *handle)
{
if (handle) {
#if defined(HAVE_LOADLIBRARY)
/* no idea */
#elif defined(HAVE_DLOPEN)
(void) dlclose(handle);
#endif
}
}
static CK_RV
hsm_pkcs11_load_functions(hsm_module_t *module)
{
CK_C_GetFunctionList pGetFunctionList = NULL;
if (module && module->path) {
/* library provided by application or user */
#if defined(HAVE_LOADLIBRARY)
/* Load PKCS #11 library */
HINSTANCE hDLL = LoadLibrary(_T(module->path));
if (hDLL == NULL) {
/* Failed to load the PKCS #11 library */
return CKR_FUNCTION_FAILED;
}
/* Retrieve the entry point for C_GetFunctionList */
pGetFunctionList = (CK_C_GetFunctionList)
GetProcAddress(hDLL, _T("C_GetFunctionList"));
#elif defined(HAVE_DLOPEN)
/* Load PKCS #11 library */
void* pDynLib = dlopen(module->path, RTLD_NOW | RTLD_LOCAL);
if (pDynLib == NULL) {
/* Failed to load the PKCS #11 library */
return CKR_FUNCTION_FAILED;
}
/* Retrieve the entry point for C_GetFunctionList */
pGetFunctionList = (CK_C_GetFunctionList) functioncast(dlsym(pDynLib, "C_GetFunctionList"));
/* Store the handle so we can dlclose it later */
module->handle = pDynLib;
#else
return CKR_FUNCTION_FAILED;
#endif
} else {
/* No library provided, use the statically compiled softHSM */
#ifdef HAVE_PKCS11_MODULE
return C_GetFunctionList(pkcs11_functions);
#else
return CKR_FUNCTION_FAILED;
#endif
}
if (pGetFunctionList == NULL) {
/* Failed to load the PKCS #11 library */
return CKR_FUNCTION_FAILED;
}
/* Retrieve the function list */
(pGetFunctionList)((CK_FUNCTION_LIST_PTR_PTR)(&module->sym));
return CKR_OK;
}
static void
hsm_remove_leading_zeroes(CK_BYTE_PTR data, CK_ULONG *len)
{
CK_BYTE_PTR p = data;
CK_ULONG l;
if (data == NULL || len == NULL) return;
l = *len;
while ((unsigned short int)(*p) == 0 && l > 1) {
p++;
l--;
}
if (p != data) {
memmove(data, p, l);
*len = l;
}
}
static int
hsm_pkcs11_check_token_name(hsm_ctx_t *ctx,
CK_FUNCTION_LIST_PTR pkcs11_functions,
CK_SLOT_ID slotId,
const char *token_name)
{
/* token label is always 32 bytes */
char token_name_bytes[HSM_TOKEN_LABEL_LENGTH];
int result = 0;
CK_RV rv;
CK_TOKEN_INFO token_info;
rv = pkcs11_functions->C_GetTokenInfo(slotId, &token_info);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
return 0;
}
memset(token_name_bytes, ' ', HSM_TOKEN_LABEL_LENGTH);
if (strlen(token_name) < HSM_TOKEN_LABEL_LENGTH) {
memcpy(token_name_bytes, token_name, strlen(token_name));
} else {
memcpy(token_name_bytes, token_name, HSM_TOKEN_LABEL_LENGTH);
}
result = memcmp(token_info.label,
token_name_bytes,
HSM_TOKEN_LABEL_LENGTH) == 0;
return result;
}
hsm_repository_t *
hsm_repository_new(char* name, char* module, char* tokenlabel, char* pin,
uint8_t use_pubkey, uint8_t allowextract, uint8_t require_backup)
{
hsm_repository_t* r;
if (!name || !module || !tokenlabel) return NULL;
r = malloc(sizeof(hsm_repository_t));
if (!r) return NULL;
r->next = NULL;
r->pin = NULL;
r->name = strdup(name);
r->module = strdup(module);
r->tokenlabel = strdup(tokenlabel);
if (!r->name || !r->module || !r->tokenlabel) {
hsm_repository_free(r);
return NULL;
}
if (pin) {
r->pin = strdup(pin);
if (!r->pin) {
hsm_repository_free(r);
return NULL;
}
}
r->use_pubkey = use_pubkey;
r->allow_extract = allowextract;
r->require_backup = require_backup;
return r;
}
void
hsm_repository_free(hsm_repository_t *r)
{
if (r) {
if (r->next) hsm_repository_free(r->next);
if (r->name) free(r->name);
if (r->module) free(r->module);
if (r->tokenlabel) free(r->tokenlabel);
if (r->pin) free(r->pin);
}
free(r);
}
static int
hsm_get_slot_id(hsm_ctx_t *ctx,
CK_FUNCTION_LIST_PTR pkcs11_functions,
const char *token_name, CK_SLOT_ID *slotId)
{
CK_RV rv;
CK_ULONG slotCount;
CK_SLOT_ID cur_slot;
CK_SLOT_ID *slotIds;
int found = 0;
if (token_name == NULL || slotId == NULL) return HSM_ERROR;
rv = pkcs11_functions->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
return HSM_ERROR;
}
if (slotCount < 1) {
hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
"No slots found in HSM");
return HSM_ERROR;
} else if (slotCount > (SIZE_MAX / sizeof(CK_SLOT_ID))) {
hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
"Too many slots found in HSM");
return HSM_ERROR;
}
CHECKALLOC(slotIds = malloc(sizeof(CK_SLOT_ID) * slotCount));
rv = pkcs11_functions->C_GetSlotList(CK_TRUE, slotIds, &slotCount);
if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
return HSM_ERROR;
}
for (cur_slot = 0; cur_slot < slotCount; cur_slot++) {
if (hsm_pkcs11_check_token_name(ctx,
pkcs11_functions,
slotIds[cur_slot],
token_name)) {
*slotId = slotIds[cur_slot];
found = 1;
break;
}
}
free(slotIds);
if (!found) {
hsm_ctx_set_error(ctx, -1, "hsm_get_slot_id()",
"could not find token with the name %s", token_name);
return HSM_ERROR;
}
return HSM_OK;
}
/* internal functions */
static hsm_module_t *
hsm_module_new(const char *repository,
const char *token_label,
const char *path,
const hsm_config_t *config)
{
hsm_module_t *module;
if (!repository || !path) return NULL;
CHECKALLOC(module = malloc(sizeof(hsm_module_t)));
if (config) {
CHECKALLOC(module->config = malloc(sizeof(hsm_config_t)));
memcpy(module->config, config, sizeof(hsm_config_t));
} else {
module->config = NULL;
}
module->id = 0; /*TODO i think we can remove this*/
module->name = strdup(repository);
module->token_label = strdup(token_label);
module->path = dupstr(path);
module->handle = NULL;
module->sym = NULL;
return module;
}
static void
hsm_module_free(hsm_module_t *module)
{
if (module) {
if (module->name) free(module->name);
if (module->token_label) free(module->token_label);
if (module->path) free(module->path);
if (module->config) free(module->config);
free(module);
}
}
static hsm_session_t *
hsm_session_new(hsm_module_t *module, CK_SESSION_HANDLE session_handle)
{
hsm_session_t *session;
CHECKALLOC(session = malloc(sizeof(hsm_session_t)));
session->module = module;
session->session = session_handle;
return session;
}
static void
hsm_session_free(hsm_session_t *session) {
if (session) {
free(session);
}
}
static void
hsm_config_default(hsm_config_t *config)
{
config->use_pubkey = 1;
config->allow_extract = 0;
}
/* creates a session_t structure, and automatically adds and initializes
* a module_t struct for it
*/
static int
hsm_session_init(hsm_ctx_t *ctx, hsm_session_t **session,
const char *repository, const char *token_label,
const char *module_path, const char *pin,
const hsm_config_t *config)
{
CK_RV rv;
CK_RV rv_login;
hsm_module_t *module;
CK_SLOT_ID slot_id;
CK_SESSION_HANDLE session_handle;
int first = 1, result;
CK_C_INITIALIZE_ARGS InitArgs = {NULL, NULL, NULL, NULL,
CKF_OS_LOCKING_OK, NULL };
if (pin == NULL) return HSM_ERROR;
module = hsm_module_new(repository, token_label, module_path, config);
if (!module) return HSM_ERROR;
rv = hsm_pkcs11_load_functions(module);
if (rv != CKR_OK) {
hsm_ctx_set_error(ctx, HSM_MODULE_NOT_FOUND,
"hsm_session_init()",
"PKCS#11 module load failed: %s", module_path);
hsm_module_free(module);
return HSM_MODULE_NOT_FOUND;
}
rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Initialize((CK_VOID_PTR) &InitArgs);
/* ALREADY_INITIALIZED is ok, apparently we are using a second
* device with the same library */
if (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
if (hsm_pkcs11_check_error(ctx, rv, "Initialization")) {
hsm_module_free(module);
return HSM_ERROR;
}
} else {
first = 0;
}
result = hsm_get_slot_id(ctx, module->sym, token_label, &slot_id);
if (result != HSM_OK) {
hsm_module_free(module);
return HSM_ERROR;
}
rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_OpenSession(slot_id,
CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL,
NULL,
&session_handle);
if (hsm_pkcs11_check_error(ctx, rv, "Open first session")) {
hsm_module_free(module);
return HSM_ERROR;
}
rv_login = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Login(session_handle,
CKU_USER,
(unsigned char *) pin,
strlen((char *)pin));
if (rv_login == CKR_OK || rv_login == CKR_USER_ALREADY_LOGGED_IN) {
*session = hsm_session_new(module, session_handle);
return HSM_OK;
} else {
/* uninitialize the session again */
if (session_handle) {
rv = ((CK_FUNCTION_LIST_PTR) module->sym)->
C_CloseSession(session_handle);
if (hsm_pkcs11_check_error(ctx, rv,
"finalize after failed login")) {
hsm_module_free(module);
return HSM_ERROR;
}
}
/* if this was not the first, don't close the library for
* the rest of us */
if (first) {
rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Finalize(NULL);
if (hsm_pkcs11_check_error(ctx, rv, "finalize after failed login")) {
hsm_module_free(module);
return HSM_ERROR;
}
}
hsm_module_free(module);
*session = NULL;
switch(rv_login) {
case CKR_PIN_INCORRECT:
hsm_ctx_set_error(ctx, HSM_PIN_INCORRECT,
"hsm_session_init()",
"Incorrect PIN for repository %s", repository);
return HSM_PIN_INCORRECT;
default:
return HSM_ERROR;
}
}
}
/* open a second session from the given one */
static hsm_session_t *
hsm_session_clone(hsm_ctx_t *ctx, hsm_session_t *session)
{
CK_RV rv;
CK_SLOT_ID slot_id;
CK_SESSION_HANDLE session_handle;
hsm_session_t *new_session;
int result;
result = hsm_get_slot_id(ctx,
session->module->sym,
session->module->token_label,
&slot_id);
if (result != HSM_OK) return NULL;
rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_OpenSession(slot_id,
CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL,
NULL,
&session_handle);
if (hsm_pkcs11_check_error(ctx, rv, "Clone session")) {
return NULL;
}
new_session = hsm_session_new(session->module, session_handle);
return new_session;
}
static hsm_ctx_t *
hsm_ctx_new()
{
hsm_ctx_t *ctx;
CHECKALLOC(ctx = malloc(sizeof(hsm_ctx_t)));
memset(ctx->session, 0, HSM_MAX_SESSIONS * sizeof(hsm_ctx_t*));
ctx->session_count = 0;
ctx->error = 0;
return ctx;
}
/* ctx_free frees the structure */
static void
hsm_ctx_free(hsm_ctx_t *ctx)
{
unsigned int i;
if (ctx) {
for (i = 0; i < ctx->session_count; i++) {
hsm_session_free(ctx->session[i]);
}
free(ctx);
}
}
/* close the session, and free the allocated data
*
* if unload is non-zero, C_Logout() is called,
* the dlopen()d module is closed and unloaded
* (only call this on the last session for each
* module, ie. the one in the global ctx)
*/
static void
hsm_session_close(hsm_ctx_t *ctx, hsm_session_t *session, int unload)
{
/* If we loaded this library more than once, we may have
* already finalized it before, so we can safely ignore
* NOT_INITIALIZED */
CK_RV rv;
if (unload) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Logout(session->session);
if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
(void) hsm_pkcs11_check_error(ctx, rv, "Logout");
}
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session->session);
if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
(void) hsm_pkcs11_check_error(ctx, rv, "Close session");
}
if (unload) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Finalize(NULL);
if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
(void) hsm_pkcs11_check_error(ctx, rv, "Finalize");
hsm_pkcs11_unload_functions(session->module->handle);
}
hsm_module_free(session->module);
session->module = NULL;
}
hsm_session_free(session);
}
/* ctx_close closes all session, and free
* the structures.
*
* if unload is non-zero, the associated dynamic libraries are unloaded
* (hence only use that on the last, global, ctx)
*/
static void
hsm_ctx_close(hsm_ctx_t *ctx, int unload)
{
size_t i;
if (!ctx) return;
for (i = 0; i < ctx->session_count; i++) {
hsm_session_close(ctx, ctx->session[i], unload);
ctx->session[i] = NULL;
}
hsm_ctx_free(ctx);
}
/* adds a session to the context.
* returns 0 on success
* 1 if the maximum number of sessions (HSM_MAX_SESSIONS) was
* reached
* -1 if one of the arguments is NULL
*/
static int
hsm_ctx_add_session(hsm_ctx_t *ctx, hsm_session_t *session)
{
if (!ctx || !session) return -1;
if (ctx->session_count >= HSM_MAX_SESSIONS) return 1;
ctx->session[ctx->session_count] = session;
ctx->session_count++;
return 0;
}
static hsm_ctx_t *
hsm_ctx_clone(hsm_ctx_t *ctx)
{
unsigned int i;
hsm_ctx_t *new_ctx;
hsm_session_t *new_session;
new_ctx = NULL;
if (ctx) {
new_ctx = hsm_ctx_new();
for (i = 0; i < ctx->session_count; i++) {
new_session = hsm_session_clone(ctx, ctx->session[i]);
if (!new_session) {
/* one of the sessions failed to clone. Clear the
* new ctx and return NULL */
hsm_ctx_close(new_ctx, 0);
return NULL;
}
hsm_ctx_add_session(new_ctx, new_session);
}
new_ctx->keycache = ctx->keycache;
new_ctx->keycache_lock = ctx->keycache_lock;
}
return new_ctx;
}
static libhsm_key_t *
libhsm_key_new()
{
libhsm_key_t *key;
CHECKALLOC(key = malloc(sizeof(libhsm_key_t)));
key->modulename = NULL;
key->private_key = 0;
key->public_key = 0;
return key;
}
/* find the session belonging to a key, by iterating over the modules
* in the context */
static hsm_session_t *
hsm_find_key_session(hsm_ctx_t *ctx, const libhsm_key_t *key)
{
unsigned int i;
if (!key || !key->modulename) return NULL;
for (i = 0; i < ctx->session_count; i++) {
if (ctx->session[i] && !strcmp(ctx->session[i]->module->name, key->modulename)) {
return ctx->session[i];
}
}
return NULL;
}
/* Returns the key type (algorithm) of the given key */
static CK_KEY_TYPE
hsm_get_key_algorithm(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
CK_KEY_TYPE key_type;
CK_ATTRIBUTE template[] = {
{CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}
};
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->private_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv,
"Get attr value algorithm type")) {
/* this is actually not a good return value;
* CKK_RSA is also 0. But we can't return a negative
* value. Should we #define a specific 'key type' that
* indicates an error? (TODO) */
return 0;
}
if ((CK_LONG)template[0].ulValueLen < 1) {
/* this is actually not a good return value;
* CKK_RSA is also 0. But we can't return a negative
* value. Should we #define a specific 'key type' that
* indicates an error? (TODO) */
return 0;
}
return key_type;
}
/* returns a CK_ULONG with the key size of the given RSA key. The
* key is not checked for type. For RSA, the number of bits in the
* modulus is the key size (CKA_MODULUS_BITS)
*/
static CK_ULONG
hsm_get_key_size_rsa(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
CK_ULONG modulus_bits;
/* Template for public keys */
CK_ATTRIBUTE template[] = {
{CKA_MODULUS_BITS, &modulus_bits, sizeof(CK_KEY_TYPE)}
};
/* Template for private keys */
CK_BYTE_PTR modulus = NULL;
int mask;
CK_ATTRIBUTE template2[] = {
{CKA_MODULUS, NULL, 0}
};
if (key->public_key) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv,
"Get attr value algorithm type")) {
return 0;
}
if ((CK_ULONG)template[0].ulValueLen < 1) {
return 0;
}
} else {
// Get buffer size
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->private_key,
template2,
1);
if (hsm_pkcs11_check_error(ctx, rv, "Could not get the size of the modulus of the private key")) {
return 0;
}
// Allocate memory
modulus = (CK_BYTE_PTR)malloc(template2[0].ulValueLen);
template2[0].pValue = modulus;
if (modulus == NULL) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_size_rsa()",
"Error allocating memory for modulus");
return 0;
}
// Get attribute
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->private_key,
template2,
1);
if (hsm_pkcs11_check_error(ctx, rv, "Could not get the modulus of the private key")) {
free(modulus);
return 0;
}
// Calculate size
modulus_bits = template2[0].ulValueLen * 8;
mask = 0x80;
for (int i = 0; modulus_bits && (modulus[i] & mask) == 0; modulus_bits--) {
mask >>= 1;
if (mask == 0) {
i++;
mask = 0x80;
}
}
free(modulus);
}
return modulus_bits;
}
/* returns a CK_ULONG with the key size of the given DSA key. The
* key is not checked for type. For DSA, the number of bits in the
* prime is the key size (CKA_PRIME)
*/
static CK_ULONG
hsm_get_key_size_dsa(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
/* Template */
CK_ATTRIBUTE template2[] = {
{CKA_PRIME, NULL, 0}
};
// Get buffer size
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->private_key,
template2,
1);
if (hsm_pkcs11_check_error(ctx, rv, "Could not get the size of the prime of the private key")) {
return 0;
}
return template2[0].ulValueLen * 8;
}
/* Returns the DER decoded value of Q for ECDSA key
* Byte string with uncompressed form of a curve point, "x | y"
*/
static unsigned char *
hsm_get_key_ecdsa_value(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key, CK_ULONG *data_len)
{
CK_RV rv;
CK_BYTE_PTR value = NULL;
CK_BYTE_PTR data = NULL;
CK_ULONG value_len = 0;
CK_ULONG header_len = 0;
CK_ATTRIBUTE template[] = {
{CKA_EC_POINT, NULL, 0},
};
if (!session || !session->module || !key || !data_len) {
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
return NULL;
}
value_len = template[0].ulValueLen;
CHECKALLOC(value = template[0].pValue = malloc(value_len));
memset(value, 0, value_len);
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
free(value);
return NULL;
}
if(value_len != template[0].ulValueLen) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"HSM returned two different length for a same CKA_EC_POINT. " \
"Abnormal behaviour detected.");
free(value);
return NULL;
}
/* Check that we have the first two octets */
if (value_len < 2) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"The DER value is too short");
free(value);
return NULL;
}
/* Check the identifier octet, PKCS#11 requires octet string */
if (value[0] != 0x04) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"Invalid identifier octet in the DER value");
free(value);
return NULL;
}
header_len++;
/* Check the length octets, but we do not validate the length */
if (value[1] <= 0x7F) {
header_len++;
} else if (value[1] == 0x80) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"Indefinite length is not supported in DER values");
free(value);
return NULL;
} else {
header_len++;
header_len += value[1] & 0x80;
}
/* Check that we have more data than the header */
if (value_len - header_len < 2) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"The value is too short");
free(value);
return NULL;
}
/* Check that we have uncompressed data */
/* TODO: Not supporting compressed data */
if (value[header_len] != 0x04) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
"The value is not uncompressed");
free(value);
return NULL;
}
header_len++;
*data_len = value_len - header_len;
CHECKALLOC(data = malloc(*data_len));
memcpy(data, value + header_len, *data_len);
free(value);
return data;
}
/* returns a CK_ULONG with the key size of the given ECDSA key. The
* key is not checked for type. For ECDSA, the number of bits in the
* value X is the key size
*/
static CK_ULONG
hsm_get_key_size_ecdsa(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key)
{
CK_ULONG value_len;
unsigned char* value = hsm_get_key_ecdsa_value(ctx, session, key, &value_len);
CK_ULONG bits = 0;
if (value == NULL) return 0;
if( ((CK_ULONG) - 1) / (8/2) < value_len) {
free(value);
return 0;
}
/* value = x | y */
bits = value_len * 8 / 2;
free(value);
return bits;
}
/* Returns the DER decoded value of the EDDSA public key
* Byte string with b-bit public key in little endian order
*/
static unsigned char *
hsm_get_key_eddsa_value(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key, CK_ULONG *data_len)
{
CK_RV rv;
CK_BYTE_PTR value = NULL;
CK_BYTE_PTR data = NULL;
CK_ULONG value_len = 0;
CK_ULONG header_len = 0;
CK_ATTRIBUTE template[] = {
{CKA_EC_POINT, NULL, 0},
};
if (!session || !session->module || !key || !data_len) {
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
return NULL;
}
value_len = template[0].ulValueLen;
value = template[0].pValue = malloc(value_len);
if (!value) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"Error allocating memory for value");
return NULL;
}
memset(value, 0, value_len);
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
free(value);
return NULL;
}
if(value_len != template[0].ulValueLen) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"HSM returned two different length for the same CKA_EC_POINT. " \
"Abnormal behaviour detected.");
free(value);
return NULL;
}
/* Check that we have the first two octets */
if (value_len < 2) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"The DER value is too short");
free(value);
return NULL;
}
/* Check the identifier octet, PKCS#11 requires octet string */
if (value[0] != 0x04) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"Invalid identifier octet in the DER value");
free(value);
return NULL;
}
header_len++;
/* Check the length octets, but we do not validate the length */
if (value[1] <= 0x7F) {
header_len++;
} else if (value[1] == 0x80) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"Indefinite length is not supported in DER values");
free(value);
return NULL;
} else {
header_len++;
header_len += value[1] & 0x80;
}
/* Check that we have more data than the header */
if (value_len - header_len < 2) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"The value is too short");
free(value);
return NULL;
}
*data_len = value_len - header_len;
data = malloc(*data_len);
if (data == NULL) {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
"Error allocating memory for data");
free(value);
return NULL;
}
memcpy(data, value + header_len, *data_len);
free(value);
return data;
}
/* returns a CK_ULONG with the key size of the given EDDSA key. The
* key is not checked for type. For EDDSA, the key size is the number
* of bits in the curve not the size of the public key representation,
* which is larger.
*/
static CK_ULONG
hsm_get_key_size_eddsa(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key)
{
CK_ULONG value_len;
unsigned char* value = hsm_get_key_eddsa_value(ctx, session, key, &value_len);
CK_ULONG bits = 0;
if (value == NULL) return 0;
if( ((CK_ULONG) - 1) / 8 < value_len) {
free(value);
return 0;
}
bits = value_len * 8;
free(value);
switch (bits) {
// ED25519 keys are 255 bits represented as 256 bits (RFC8080 section 3)
case 256:
bits = 255;
break;
// ED448 keys are 448 bits represented as 456 bits (RFC8080 section 3)
case 456:
bits = 448;
break;
default:
bits = 0;
break;
}
return bits;
}
/* Wrapper for specific key size functions */
static CK_ULONG
hsm_get_key_size(hsm_ctx_t *ctx, const hsm_session_t *session,
const libhsm_key_t *key, const unsigned long algorithm)
{
switch (algorithm) {
case CKK_RSA:
return hsm_get_key_size_rsa(ctx, session, key);
break;
case CKK_DSA:
return hsm_get_key_size_dsa(ctx, session, key);
break;
case CKK_GOSTR3410:
/* GOST public keys always have a size of 512 bits */
return 512;
case CKK_EC:
return hsm_get_key_size_ecdsa(ctx, session, key);
case CKK_EC_EDWARDS:
return hsm_get_key_size_eddsa(ctx, session, key);
default:
return 0;
}
}
static CK_OBJECT_HANDLE
hsm_find_object_handle_for_id(hsm_ctx_t *ctx,
const hsm_session_t *session,
CK_OBJECT_CLASS key_class,
CK_BYTE *id,
CK_ULONG id_len)
{
CK_ULONG objectCount;
CK_OBJECT_HANDLE object;
CK_RV rv;
CK_ATTRIBUTE template[] = {
{ CKA_CLASS, &key_class, sizeof(key_class) },
{ CKA_ID, id, id_len },
};
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
template, 2);
if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
return 0;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
&object,
1,
&objectCount);
if (hsm_pkcs11_check_error(ctx, rv, "Find object")) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
hsm_pkcs11_check_error(ctx, rv, "Find objects cleanup");
return 0;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
if (hsm_pkcs11_check_error(ctx, rv, "Find object final")) {
return 0;
}
if (objectCount > 0) {
return object;
} else {
return 0;
}
}
/*
* Parses the null-terminated string hex as hex values,
* Returns allocated data that needs to be freed (or NULL on error)
* len will contain the number of bytes allocated, or 0 on error
*/
static unsigned char *
hsm_hex_parse(const char *hex, size_t *len)
{
unsigned char *bytes;
/* length of the hex input */
size_t hex_len;
size_t i;
if (!len) return NULL;
*len = 0;
if (!hex) return NULL;
hex_len = strlen(hex);
if (hex_len % 2 != 0) {
return NULL;
}
*len = hex_len / 2;
CHECKALLOC(bytes = malloc(*len));
for (i = 0; i < *len; i++) {
bytes[i] = ldns_hexdigit_to_int(hex[2*i]) * 16 +
ldns_hexdigit_to_int(hex[2*i+1]);
}
return bytes;
}
/* put a hexadecimal representation of the data from src into dst
* len is the number of bytes to read from src
* dst must have allocated enough space (len*2 + 1)
*/
static void
hsm_hex_unparse(char *dst, const unsigned char *src, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
snprintf(dst + (2*i), 3, "%02x", src[i]);
}
dst[len*2] = '\0';
}
/* returns an allocated byte array with the CKA_ID for the given object
* len will contain the result size
* returns NULL and size zero if not found in this session
*/
static CK_BYTE *
hsm_get_id_for_object(hsm_ctx_t *ctx,
const hsm_session_t *session,
CK_OBJECT_HANDLE object,
size_t *len)
{
CK_RV rv;
CK_BYTE *id = NULL;
CK_ATTRIBUTE template[] = {
{CKA_ID, id, 0}
};
/* find out the size of the id first */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
object,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "Get attr value")) {
*len = 0;
return NULL;
}
if ((CK_LONG)template[0].ulValueLen < 1) {
/* No CKA_ID found, return NULL */
*len = 0;
return NULL;
}
CHECKALLOC(template[0].pValue = malloc(template[0].ulValueLen));
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
object,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "Get attr value 2")) {
*len = 0;
free(template[0].pValue);
return NULL;
}
*len = template[0].ulValueLen;
return template[0].pValue;
}
/* returns an libhsm_key_t object for the given *private key* object handle
* the module, private key, and public key handle are set
* The session needs to be free to perform a search for the public key
*/
static libhsm_key_t *
libhsm_key_new_privkey_object_handle(hsm_ctx_t *ctx,
const hsm_session_t *session,
CK_OBJECT_HANDLE object)
{
libhsm_key_t *key;
CK_BYTE *id;
size_t len;
id = hsm_get_id_for_object(ctx, session, object, &len);
if (!id) return NULL;
key = libhsm_key_new();
key->modulename = strdup(session->module->name);
key->private_key = object;
key->public_key = hsm_find_object_handle_for_id(
ctx,
session,
CKO_PUBLIC_KEY,
id,
len);
free(id);
return key;
}
/* helper function to find both key counts or the keys themselves
* if the argument store is 0, results are not returned; the
* function will only set the count and return NULL
* Otherwise, a newly allocated key array will be returned
* (on error, the count will also be zero and NULL returned)
*/
static libhsm_key_t **
hsm_list_keys_session_internal(hsm_ctx_t *ctx,
const hsm_session_t *session,
size_t *count,
int store)
{
libhsm_key_t **keys = NULL;
libhsm_key_t *key;
CK_RV rv;
CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
CK_ATTRIBUTE template[] = {
{ CKA_CLASS, &key_class, sizeof(key_class) },
};
CK_ULONG total_count = 0;
CK_ULONG objectCount = 1;
/* find 100 keys at a time (and loop until there are none left) */
CK_ULONG max_object_count = 100;
CK_ULONG i, j;
CK_OBJECT_HANDLE object[max_object_count];
CK_OBJECT_HANDLE *key_handles = NULL, *new_key_handles = NULL;
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
template, 1);
if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
goto err;
}
j = 0;
while (objectCount > 0) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
object,
max_object_count,
&objectCount);
if (hsm_pkcs11_check_error(ctx, rv, "Find first object")) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
hsm_pkcs11_check_error(ctx, rv, "Find objects cleanup");
goto err;
}
total_count += objectCount;
if (objectCount > 0 && store) {
if (SIZE_MAX / sizeof(CK_OBJECT_HANDLE) < total_count) {
hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
"Too much object handle returned by HSM to allocate key_handles");
goto err;
}
new_key_handles = realloc(key_handles, total_count * sizeof(CK_OBJECT_HANDLE));
if (new_key_handles != NULL) {
key_handles = new_key_handles;
} else {
hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
"Error allocating memory for object handle (OOM)");
goto err;
}
for (i = 0; i < objectCount; i++) {
key_handles[j] = object[i];
j++;
}
}
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
if (hsm_pkcs11_check_error(ctx, rv, "Find objects final")) {
goto err;
}
if (store) {
if(SIZE_MAX / sizeof(libhsm_key_t *) < total_count) {
hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
"Too much object handle returned by HSM to allocate keys");
goto err;
}
CHECKALLOC(keys = malloc(total_count * sizeof(libhsm_key_t *)));
for (i = 0; i < total_count; i++) {
key = libhsm_key_new_privkey_object_handle(ctx, session,
key_handles[i]);
if(!key) {
libhsm_key_list_free(keys, i);
goto err;
}
keys[i] = key;
}
}
free(key_handles);
*count = total_count;
return keys;
err:
free(key_handles);
*count = 0;
return NULL;
}
/* returns an array of all keys available to the given session
*
* \param session the session to find the keys in
* \param count this value will contain the number of keys found
*
* \return the list of keys
*/
static libhsm_key_t **
hsm_list_keys_session(hsm_ctx_t *ctx, const hsm_session_t *session,
size_t *count)
{
return hsm_list_keys_session_internal(ctx, session, count, 1);
}
/* returns a newly allocated key structure containing the key data
* for the given CKA_ID available in the session. Returns NULL if not
* found
*/
static libhsm_key_t *
hsm_find_key_by_id_session(hsm_ctx_t *ctx, const hsm_session_t *session,
const unsigned char *id, size_t len)
{
libhsm_key_t *key;
CK_OBJECT_HANDLE private_key_handle;
private_key_handle = hsm_find_object_handle_for_id(
ctx,
session,
CKO_PRIVATE_KEY,
(CK_BYTE *) id,
(CK_ULONG) len);
if (private_key_handle != 0) {
key = libhsm_key_new_privkey_object_handle(ctx, session,
private_key_handle);
return key;
} else {
return NULL;
}
}
/* Find a key pair by CKA_ID (as byte array)
The returned key structure can be freed with free()
\param context HSM context
\param id CKA_ID of key to find (array of bytes)
\param len number of bytes in the id
\return key identifier or NULL if not found
*/
static libhsm_key_t *
hsm_find_key_by_id_bin(hsm_ctx_t *ctx,
const unsigned char *id,
size_t len)
{
libhsm_key_t *key;
unsigned int i;
if (!id) return NULL;
/* OPENDNSSEC-955: This procedure is mutexed to prevent a C_Login or
* C_OpenSession happening at the same * time as looking up a key with
* C_FindObject. Some HSMs like SoftHSM in database backend mode don't
* like this.
*/
pthread_mutex_lock(&_hsm_ctx_mutex);
for (i = 0; i < ctx->session_count; i++) {
key = hsm_find_key_by_id_session(ctx, ctx->session[i], id, len);
if (key) {
pthread_mutex_unlock(&_hsm_ctx_mutex);
return key;
}
}
pthread_mutex_unlock(&_hsm_ctx_mutex);
return NULL;
}
static hsm_session_t *
hsm_find_repository_session(hsm_ctx_t *ctx, const char *repository)
{
unsigned int i;
if (!repository) {
for (i = 0; i < ctx->session_count; i++) {
if (ctx->session[i]) {
return ctx->session[i];
}
}
} else {
for (i = 0; i < ctx->session_count; i++) {
if (ctx->session[i] &&
strcmp(repository, ctx->session[i]->module->name) == 0)
{
return ctx->session[i];
}
}
}
hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
"hsm_find_repository_session()",
"Can't find repository: %s", repository);
return NULL;
}
static ldns_rdf *
hsm_get_key_rdata_rsa(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
CK_BYTE_PTR public_exponent = NULL;
CK_ULONG public_exponent_len = 0;
CK_BYTE_PTR modulus = NULL;
CK_ULONG modulus_len = 0;
unsigned long hKey = 0;
unsigned char *data = NULL;
size_t data_size = 0;
CK_ATTRIBUTE template[] = {
{CKA_PUBLIC_EXPONENT, NULL, 0},
{CKA_MODULUS, NULL, 0},
};
ldns_rdf *rdf;
if (!session || !session->module) {
return NULL;
}
if (key->public_key) {
hKey = key->public_key;
} else {
hKey = key->private_key;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
hKey,
template,
2);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
return NULL;
}
public_exponent_len = template[0].ulValueLen;
modulus_len = template[1].ulValueLen;
CHECKALLOC(public_exponent = template[0].pValue = malloc(public_exponent_len));
CHECKALLOC(modulus = template[1].pValue = malloc(modulus_len));
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
hKey,
template,
2);
if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
free(template[0].pValue);
free(template[1].pValue);
return NULL;
}
// Remove leading zeroes
hsm_remove_leading_zeroes(public_exponent, &public_exponent_len);
hsm_remove_leading_zeroes(modulus, &modulus_len);
data_size = public_exponent_len + modulus_len + 1;
if (public_exponent_len <= 255) {
CHECKALLOC(data = malloc(data_size));
data[0] = public_exponent_len;
memcpy(&data[1], public_exponent, public_exponent_len);
memcpy(&data[1 + public_exponent_len], modulus, modulus_len);
} else if (public_exponent_len <= 65535) {
data_size += 2;
CHECKALLOC(data = malloc(data_size));
data[0] = 0;
ldns_write_uint16(&data[1], (uint16_t) public_exponent_len);
memcpy(&data[3], public_exponent, public_exponent_len);
memcpy(&data[3 + public_exponent_len], modulus, modulus_len);
} else {
hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
"Public exponent too big");
free(public_exponent);
free(modulus);
return NULL;
}
rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, data_size, data);
free(public_exponent);
free(modulus);
return rdf;
}
static ldns_rdf *
hsm_get_key_rdata_dsa(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
CK_BYTE_PTR prime = NULL;
CK_ULONG prime_len = 0;
CK_BYTE_PTR subprime = NULL;
CK_ULONG subprime_len = 0;
CK_BYTE_PTR base = NULL;
CK_ULONG base_len = 0;
CK_BYTE_PTR value = NULL;
CK_ULONG value_len = 0;
unsigned char *data = NULL;
size_t data_size = 0;
CK_ATTRIBUTE template[] = {
{CKA_PRIME, NULL, 0},
{CKA_SUBPRIME, NULL, 0},
{CKA_BASE, NULL, 0},
{CKA_VALUE, NULL, 0},
};
ldns_rdf *rdf;
if (!session || !session->module) {
return NULL;
}
/* DSA needs the public key compared with RSA */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
4);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
return NULL;
}
prime_len = template[0].ulValueLen;
subprime_len = template[1].ulValueLen;
base_len = template[2].ulValueLen;
value_len = template[3].ulValueLen;
CHECKALLOC(prime = template[0].pValue = malloc(prime_len));
CHECKALLOC(subprime = template[1].pValue = malloc(subprime_len));
CHECKALLOC(base = template[2].pValue = malloc(base_len));
CHECKALLOC(value = template[3].pValue = malloc(value_len));
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
4);
if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
free(prime);
free(subprime);
free(base);
free(value);
return NULL;
}
data_size = prime_len + subprime_len + base_len + value_len + 1;
CHECKALLOC(data = malloc(data_size));
data[0] = (prime_len - 64) / 8;
memcpy(&data[1], subprime, subprime_len);
memcpy(&data[1 + subprime_len], prime, prime_len);
memcpy(&data[1 + subprime_len + prime_len], base, base_len);
memcpy(&data[1 + subprime_len + prime_len + base_len], value, value_len);
rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, data_size, data);
free(prime);
free(subprime);
free(base);
free(value);
return rdf;
}
static ldns_rdf *
hsm_get_key_rdata_gost(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
CK_RV rv;
CK_BYTE_PTR value = NULL;
CK_ULONG value_len = 0;
CK_ATTRIBUTE template[] = {
{CKA_VALUE, NULL, 0},
};
ldns_rdf *rdf;
if (!session || !session->module) {
return NULL;
}
/* GOST needs the public key compared with RSA */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
return NULL;
}
value_len = template[0].ulValueLen;
CHECKALLOC(value = template[0].pValue = malloc(value_len));
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
session->session,
key->public_key,
template,
1);
if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
free(value);
return NULL;
}
rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
return rdf;
}
static ldns_rdf *
hsm_get_key_rdata_ecdsa(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
CK_ULONG value_len;
unsigned char* value = hsm_get_key_ecdsa_value(ctx, session, key, &value_len);
if (value == NULL) return NULL;
ldns_rdf *rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
return rdf;
}
static ldns_rdf *
hsm_get_key_rdata_eddsa(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
CK_ULONG value_len;
unsigned char* value = hsm_get_key_eddsa_value(ctx, session, key, &value_len);
if (value == NULL) return NULL;
ldns_rdf *rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
return rdf;
}
static ldns_rdf *
hsm_get_key_rdata(hsm_ctx_t *ctx, hsm_session_t *session,
const libhsm_key_t *key)
{
switch (hsm_get_key_algorithm(ctx, session, key)) {
case CKK_RSA:
return hsm_get_key_rdata_rsa(ctx, session, key);
break;
case CKK_DSA:
return hsm_get_key_rdata_dsa(ctx, session, key);
break;
case CKK_GOSTR3410:
return hsm_get_key_rdata_gost(ctx, session, key);
break;
case CKK_EC:
return hsm_get_key_rdata_ecdsa(ctx, session, key);
case CKK_EC_EDWARDS:
return hsm_get_key_rdata_eddsa(ctx, session, key);
default:
return 0;
}
}
/* this function allocates memory for the mechanism ID and enough room
* to leave the upcoming digest data. It fills in the mechanism id
* use with care. The returned data must be free'd by the caller.
* Only used by RSA PKCS. */
static CK_BYTE *
hsm_create_prefix(CK_ULONG digest_len,
ldns_algorithm algorithm,
CK_ULONG *data_size)
{
CK_BYTE *data;
const CK_BYTE RSA_MD5_ID[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };
const CK_BYTE RSA_SHA1_ID[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 };
const CK_BYTE RSA_SHA256_ID[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
const CK_BYTE RSA_SHA512_ID[] = { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 };
switch((ldns_signing_algorithm)algorithm) {
case LDNS_SIGN_RSAMD5:
*data_size = sizeof(RSA_MD5_ID) + digest_len;
CHECKALLOC(data = malloc(*data_size));
memcpy(data, RSA_MD5_ID, sizeof(RSA_MD5_ID));
break;
case LDNS_SIGN_RSASHA1:
case LDNS_SIGN_RSASHA1_NSEC3:
*data_size = sizeof(RSA_SHA1_ID) + digest_len;
CHECKALLOC(data = malloc(*data_size));
memcpy(data, RSA_SHA1_ID, sizeof(RSA_SHA1_ID));
break;
case LDNS_SIGN_RSASHA256:
*data_size = sizeof(RSA_SHA256_ID) + digest_len;
CHECKALLOC(data = malloc(*data_size));
memcpy(data, RSA_SHA256_ID, sizeof(RSA_SHA256_ID));
break;
case LDNS_SIGN_RSASHA512:
*data_size = sizeof(RSA_SHA512_ID) + digest_len;
CHECKALLOC(data = malloc(*data_size));
memcpy(data, RSA_SHA512_ID, sizeof(RSA_SHA512_ID));
break;
case LDNS_SIGN_DSA:
case LDNS_SIGN_DSA_NSEC3:
case LDNS_SIGN_ECC_GOST:
case LDNS_SIGN_ECDSAP256SHA256:
case LDNS_SIGN_ECDSAP384SHA384:
*data_size = digest_len;
CHECKALLOC(data = malloc(*data_size));
break;
default:
return NULL;
}
return data;
}
static CK_BYTE *
hsm_digest_through_hsm(hsm_ctx_t *ctx,
hsm_session_t *session,
CK_MECHANISM_TYPE mechanism_type,
CK_ULONG digest_len,
ldns_buffer *sign_buf)
{
CK_MECHANISM digest_mechanism;
CK_BYTE *digest;
CK_RV rv;
digest_mechanism.pParameter = NULL;
digest_mechanism.ulParameterLen = 0;
digest_mechanism.mechanism = mechanism_type;
CHECKALLOC(digest = malloc(digest_len));
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DigestInit(session->session,
&digest_mechanism);
if (hsm_pkcs11_check_error(ctx, rv, "HSM digest init")) {
free(digest);
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Digest(session->session,
ldns_buffer_begin(sign_buf),
ldns_buffer_position(sign_buf),
digest,
&digest_len);
if (hsm_pkcs11_check_error(ctx, rv, "HSM digest")) {
free(digest);
return NULL;
}
return digest;
}
static ldns_rdf *
hsm_sign_buffer(hsm_ctx_t *ctx,
ldns_buffer *sign_buf,
const libhsm_key_t *key,
ldns_algorithm algorithm)
{
CK_RV rv;
CK_ULONG signatureLen = HSM_MAX_SIGNATURE_LENGTH;
CK_BYTE signature[HSM_MAX_SIGNATURE_LENGTH];
CK_MECHANISM sign_mechanism;
int data_direct = 0; // don't pre-create digest, use data directly
ldns_rdf *sig_rdf;
CK_BYTE *digest = NULL;
CK_ULONG digest_len = 0;
CK_BYTE *data = NULL;
CK_ULONG data_len = 0;
hsm_session_t *session;
session = hsm_find_key_session(ctx, key);
if (!session) return NULL;
/* some HSMs don't really handle CKM_SHA1_RSA_PKCS well, so
* we'll do the hashing manually */
/* When adding algorithms, remember there is another switch below */
switch ((ldns_signing_algorithm)algorithm) {
case LDNS_SIGN_RSAMD5:
digest_len = 16;
digest = hsm_digest_through_hsm(ctx, session,
CKM_MD5, digest_len,
sign_buf);
break;
case LDNS_SIGN_RSASHA1:
case LDNS_SIGN_RSASHA1_NSEC3:
case LDNS_SIGN_DSA:
case LDNS_SIGN_DSA_NSEC3:
digest_len = LDNS_SHA1_DIGEST_LENGTH;
CHECKALLOC(digest = malloc(digest_len));
digest = ldns_sha1(ldns_buffer_begin(sign_buf),
ldns_buffer_position(sign_buf),
digest);
break;
case LDNS_SIGN_RSASHA256:
case LDNS_SIGN_ECDSAP256SHA256:
digest_len = LDNS_SHA256_DIGEST_LENGTH;
CHECKALLOC(digest = malloc(digest_len));
digest = ldns_sha256(ldns_buffer_begin(sign_buf),
ldns_buffer_position(sign_buf),
digest);
break;
case LDNS_SIGN_ECDSAP384SHA384:
digest_len = LDNS_SHA384_DIGEST_LENGTH;
CHECKALLOC(digest = malloc(digest_len));
digest = ldns_sha384(ldns_buffer_begin(sign_buf),
ldns_buffer_position(sign_buf),
digest);
break;
case LDNS_SIGN_RSASHA512:
digest_len = LDNS_SHA512_DIGEST_LENGTH;
CHECKALLOC(digest = malloc(digest_len));
digest = ldns_sha512(ldns_buffer_begin(sign_buf),
ldns_buffer_position(sign_buf),
digest);
break;
case LDNS_SIGN_ECC_GOST:
digest_len = 32;
digest = hsm_digest_through_hsm(ctx, session,
CKM_GOSTR3411, digest_len,
sign_buf);
break;
#if (LDNS_REVISION >= ((1<<16)|(7<<8)|(0)))
case LDNS_SIGN_ED25519:
data_direct = 1;
break;
case LDNS_SIGN_ED448:
data_direct = 1;
break;
#endif
default:
/* log error? or should we not even get here for
* unsupported algorithms? */
return NULL;
}
if (!data_direct && !digest) {
return NULL;
}
if (data_direct) {
data = ldns_buffer_begin(sign_buf);
data_len = ldns_buffer_position(sign_buf);
} else {
/* CKM_RSA_PKCS does the padding, but cannot know the identifier
* prefix, so we need to add that ourselves.
* The other algorithms will just get the digest buffer returned. */
data = hsm_create_prefix(digest_len, algorithm, &data_len);
memcpy(data + data_len - digest_len, digest, digest_len);
}
sign_mechanism.pParameter = NULL;
sign_mechanism.ulParameterLen = 0;
switch((ldns_signing_algorithm)algorithm) {
case LDNS_SIGN_RSAMD5:
case LDNS_SIGN_RSASHA1:
case LDNS_SIGN_RSASHA1_NSEC3:
case LDNS_SIGN_RSASHA256:
case LDNS_SIGN_RSASHA512:
sign_mechanism.mechanism = CKM_RSA_PKCS;
break;
case LDNS_SIGN_DSA:
case LDNS_SIGN_DSA_NSEC3:
sign_mechanism.mechanism = CKM_DSA;
break;
case LDNS_SIGN_ECC_GOST:
sign_mechanism.mechanism = CKM_GOSTR3410;
break;
case LDNS_SIGN_ECDSAP256SHA256:
case LDNS_SIGN_ECDSAP384SHA384:
sign_mechanism.mechanism = CKM_ECDSA;
break;
#if (LDNS_REVISION >= ((1<<16)|(7<<8)|(0)))
case LDNS_SIGN_ED25519:
sign_mechanism.mechanism = CKM_EDDSA;
break;
case LDNS_SIGN_ED448:
sign_mechanism.mechanism = CKM_EDDSA;
break;
#endif
default:
/* log error? or should we not even get here for
* unsupported algorithms? */
free(data);
free(digest);
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_SignInit(
session->session,
&sign_mechanism,
key->private_key);
if (hsm_pkcs11_check_error(ctx, rv, "sign init")) {
if (!data_direct) {
free(data);
free(digest);
}
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Sign(session->session, data, data_len,
signature,
&signatureLen);
if (hsm_pkcs11_check_error(ctx, rv, "sign final")) {
if (!data_direct) {
free(data);
free(digest);
}
return NULL;
}
sig_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
signatureLen,
signature);
if (!data_direct) {
free(data);
free(digest);
}
return sig_rdf;
}
static int
hsm_dname_is_wildcard(const ldns_rdf* dname)
{
return ( ldns_dname_label_count(dname) > 0 &&
ldns_rdf_data(dname)[0] == 1 &&
ldns_rdf_data(dname)[1] == '*');
}
static ldns_rr *
hsm_create_empty_rrsig(const ldns_rr_list *rrset,
const hsm_sign_params_t *sign_params)
{
ldns_rr *rrsig;
uint32_t orig_ttl;
uint32_t orig_class;
time_t now;
uint8_t label_count;
label_count = ldns_dname_label_count(
ldns_rr_owner(ldns_rr_list_rr(rrset, 0)));
/* RFC 4035 section 2.2: dnssec label length and wildcards */
if (hsm_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0)))) {
label_count--;
}
rrsig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
/* set the type on the new signature */
orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));
orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
ldns_rr_set_class(rrsig, orig_class);
ldns_rr_set_ttl(rrsig, orig_ttl);
ldns_rr_set_owner(rrsig,
ldns_rdf_clone(
ldns_rr_owner(
ldns_rr_list_rr(rrset,
0))));
/* fill in what we know of the signature */
/* set the orig_ttl */
(void)ldns_rr_rrsig_set_origttl(
rrsig,
ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
orig_ttl));
/* the signers name */
(void)ldns_rr_rrsig_set_signame(
rrsig,
ldns_rdf_clone(sign_params->owner));
/* label count - get it from the first rr in the rr_list */
(void)ldns_rr_rrsig_set_labels(
rrsig,
ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
label_count));
/* inception, expiration */
now = time_now();
if (sign_params->inception != 0) {
(void)ldns_rr_rrsig_set_inception(
rrsig,
ldns_native2rdf_int32(
LDNS_RDF_TYPE_TIME,
sign_params->inception));
} else {
(void)ldns_rr_rrsig_set_inception(
rrsig,
ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
}
if (sign_params->expiration != 0) {
(void)ldns_rr_rrsig_set_expiration(
rrsig,
ldns_native2rdf_int32(
LDNS_RDF_TYPE_TIME,
sign_params->expiration));
} else {
(void)ldns_rr_rrsig_set_expiration(
rrsig,
ldns_native2rdf_int32(
LDNS_RDF_TYPE_TIME,
now + LDNS_DEFAULT_EXP_TIME));
}
(void)ldns_rr_rrsig_set_keytag(
rrsig,
ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
sign_params->keytag));
(void)ldns_rr_rrsig_set_algorithm(
rrsig,
ldns_native2rdf_int8(
LDNS_RDF_TYPE_ALG,
sign_params->algorithm));
(void)ldns_rr_rrsig_set_typecovered(
rrsig,
ldns_native2rdf_int16(
LDNS_RDF_TYPE_TYPE,
ldns_rr_get_type(ldns_rr_list_rr(rrset,
0))));
return rrsig;
}
/*
* API functions
*/
int
hsm_open2(hsm_repository_t* rlist,
char *(pin_callback)(unsigned int, const char *, unsigned int))
{
hsm_config_t module_config;
hsm_repository_t* repo = NULL;
char* module_pin = NULL;
int result = HSM_OK;
int tries;
int repositories = 0;
pthread_mutex_lock(&_hsm_ctx_mutex);
/* create an internal context with an attached session for each
* configured HSM. */
if ((_hsm_ctx = hsm_ctx_new())) {
keycache_create(_hsm_ctx);
}
repo = rlist;
while (repo) {
hsm_config_default(&module_config);
module_config.use_pubkey = repo->use_pubkey;
module_config.allow_extract = repo->allow_extract;
if (repo->name && repo->module && repo->tokenlabel) {
if (repo->pin) {
result = hsm_attach(repo->name, repo->tokenlabel,
repo->module, repo->pin, &module_config);
} else {
if (pin_callback) {
result = HSM_PIN_INCORRECT;
tries = 0;
while (result == HSM_PIN_INCORRECT && tries < 3) {
module_pin = pin_callback(_hsm_ctx->session_count,
repo->name, tries?HSM_PIN_RETRY:HSM_PIN_FIRST);
if (module_pin == NULL) break;
result = hsm_attach(repo->name, repo->tokenlabel,
repo->module, module_pin, &module_config);
if (result == HSM_OK) {
pin_callback(_hsm_ctx->session_count - 1,
repo->name, HSM_PIN_SAVE);
}
memset(module_pin, 0, strlen(module_pin));
tries++;
}
} else {
/* no pin, no callback */
hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_open2()",
"No pin or callback function");
result = HSM_ERROR;
}
}
if (result != HSM_OK) {
break;
}
repositories++;
}
repo = repo->next;
}
if (result == HSM_OK && repositories == 0) {
hsm_ctx_set_error(_hsm_ctx, HSM_NO_REPOSITORIES, "hsm_open2()",
"No repositories found");
result = HSM_NO_REPOSITORIES;
}
pthread_mutex_unlock(&_hsm_ctx_mutex);
return result;
}
void
hsm_close()
{
pthread_mutex_lock(&_hsm_ctx_mutex);
keycache_destroy(_hsm_ctx);
hsm_ctx_close(_hsm_ctx, 1);
_hsm_ctx = NULL;
pthread_mutex_unlock(&_hsm_ctx_mutex);
}
hsm_ctx_t *
hsm_create_context()
{
hsm_ctx_t* newctx;
pthread_mutex_lock(&_hsm_ctx_mutex);
newctx = hsm_ctx_clone(_hsm_ctx);
pthread_mutex_unlock(&_hsm_ctx_mutex);
return newctx;
}
int
hsm_check_context()
{
unsigned int i;
hsm_session_t *session;
CK_SESSION_INFO info;
CK_RV rv;
CK_SESSION_HANDLE session_handle;
hsm_ctx_t *ctx;
pthread_mutex_lock(&_hsm_ctx_mutex);
ctx = _hsm_ctx;
for (i = 0; i < ctx->session_count; i++) {
session = ctx->session[i];
if (session == NULL) continue;
/* Get session info */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetSessionInfo(
session->session,
&info);
if (hsm_pkcs11_check_error(ctx, rv, "get session info")) {
pthread_mutex_unlock(&_hsm_ctx_mutex);
return HSM_ERROR;
}
/* Check session info */
if (info.state != CKS_RW_USER_FUNCTIONS) {
hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_check_context()",
"Session not logged in");
pthread_mutex_unlock(&_hsm_ctx_mutex);
return HSM_ERROR;
}
/* Try open and close a session with the token */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_OpenSession(info.slotID,
CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL,
NULL,
&session_handle);
if (hsm_pkcs11_check_error(ctx, rv, "test open session")) {
pthread_mutex_unlock(&_hsm_ctx_mutex);
return HSM_ERROR;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session_handle);
if (hsm_pkcs11_check_error(ctx, rv, "test close session")) {
pthread_mutex_unlock(&_hsm_ctx_mutex);
return HSM_ERROR;
}
}
pthread_mutex_unlock(&_hsm_ctx_mutex);
return HSM_OK;
}
void
hsm_destroy_context(hsm_ctx_t *ctx)
{
hsm_ctx_close(ctx, 0);
}
hsm_sign_params_t *
hsm_sign_params_new()
{
hsm_sign_params_t *params;
CHECKALLOC(params = malloc(sizeof(hsm_sign_params_t)));
params->algorithm = LDNS_RSASHA256;
params->flags = LDNS_KEY_ZONE_KEY;
params->inception = 0;
params->expiration = 0;
params->keytag = 0;
params->owner = NULL;
return params;
}
void
hsm_sign_params_free(hsm_sign_params_t *params)
{
if (params) {
if (params->owner) ldns_rdf_deep_free(params->owner);
free(params);
}
}
void
libhsm_key_free(libhsm_key_t *key)
{
free(key->modulename);
free(key);
}
libhsm_key_t **
hsm_list_keys(hsm_ctx_t *ctx, size_t *count)
{
libhsm_key_t **keys = NULL;
size_t key_count = 0;
size_t cur_key_count;
libhsm_key_t **session_keys;
unsigned int i, j;
for (i = 0; i < ctx->session_count; i++) {
session_keys = hsm_list_keys_session(ctx, ctx->session[i],
&cur_key_count);
CHECKALLOC(keys = realloc(keys,
(key_count + cur_key_count) * sizeof(libhsm_key_t *)));
for (j = 0; j < cur_key_count; j++) {
keys[key_count + j] = session_keys[j];
}
key_count += cur_key_count;
free(session_keys);
}
if (count) {
*count = key_count;
}
return keys;
}
libhsm_key_t **
hsm_list_keys_repository(hsm_ctx_t *ctx,
size_t *count,
const char *repository)
{
hsm_session_t *session;
if (!repository) return NULL;
session = hsm_find_repository_session(ctx, repository);
if (!session) {
*count = 0;
return NULL;
}
return hsm_list_keys_session(ctx, session, count);
}
libhsm_key_t *
hsm_find_key_by_id(hsm_ctx_t *ctx, const char *id)
{
unsigned char *id_bytes;
size_t len;
libhsm_key_t *key;
id_bytes = hsm_hex_parse(id, &len);
if (!id_bytes) return NULL;
key = hsm_find_key_by_id_bin(ctx, id_bytes, len);
free(id_bytes);
return key;
}
static void
generate_unique_id(hsm_ctx_t *ctx, unsigned char *buf, size_t bufsize)
{
libhsm_key_t *key;
/* check whether this key doesn't happen to exist already */
hsm_random_buffer(ctx, buf, bufsize);
while ((key = hsm_find_key_by_id_bin(ctx, buf, bufsize))) {
libhsm_key_free(key);
hsm_random_buffer(ctx, buf, bufsize);
}
}
libhsm_key_t *
hsm_generate_rsa_key(hsm_ctx_t *ctx,
const char *repository,
unsigned long keysize)
{
libhsm_key_t *new_key;
hsm_session_t *session;
/* ids we create are 16 bytes of data */
unsigned char id[16];
/* that's 33 bytes in string (16*2 + 1 for \0) */
char id_str[33];
CK_RV rv;
CK_OBJECT_HANDLE publicKey, privateKey;
CK_KEY_TYPE keyType = CKK_RSA;
CK_MECHANISM mechanism = {
CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
};
CK_BYTE publicExponent[] = { 1, 0, 1 };
CK_BBOOL ctrue = CK_TRUE;
CK_BBOOL cfalse = CK_FALSE;
CK_BBOOL ctoken = CK_TRUE;
CK_BBOOL cextractable = CK_FALSE;
session = hsm_find_repository_session(ctx, repository);
if (!session) return NULL;
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
generate_unique_id(ctx, id, 16);
/* the CKA_LABEL will contain a hexadecimal string representation
* of the id */
hsm_hex_unparse(id_str, id, 16);
if (! session->module->config->use_pubkey) {
ctoken = CK_FALSE;
}
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen(id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_VERIFY, &ctrue, sizeof(ctrue) },
{ CKA_ENCRYPT, &cfalse, sizeof(cfalse) },
{ CKA_WRAP, &cfalse, sizeof(cfalse) },
{ CKA_TOKEN, &ctoken, sizeof(ctoken) },
{ CKA_MODULUS_BITS, &keysize, sizeof(keysize) },
{ CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR *) id_str, strlen (id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_SIGN, &ctrue, sizeof (ctrue) },
{ CKA_DECRYPT, &cfalse, sizeof (cfalse) },
{ CKA_UNWRAP, &cfalse, sizeof (cfalse) },
{ CKA_SENSITIVE, &ctrue, sizeof (ctrue) },
{ CKA_TOKEN, &ctrue, sizeof (ctrue) },
{ CKA_PRIVATE, &ctrue, sizeof (ctrue) },
{ CKA_EXTRACTABLE, &cextractable, sizeof (cextractable) }
};
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
&mechanism,
publicKeyTemplate, 9,
privateKeyTemplate, 10,
&publicKey,
&privateKey);
if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
return NULL;
}
new_key = libhsm_key_new();
new_key->modulename = strdup(session->module->name);
if (session->module->config->use_pubkey) {
new_key->public_key = publicKey;
} else {
/* Destroy the object directly in order to optimize storage in HSM */
/* Ignore return value, it is just a session object and will be destroyed later */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session, publicKey);
new_key->public_key = 0;
}
new_key->private_key = privateKey;
return new_key;
}
libhsm_key_t *
hsm_generate_dsa_key(hsm_ctx_t *ctx,
const char *repository,
unsigned long keysize)
{
CK_RV rv;
libhsm_key_t *new_key;
hsm_session_t *session;
CK_OBJECT_HANDLE domainPar, publicKey, privateKey;
CK_BBOOL ctrue = CK_TRUE;
CK_BBOOL cfalse = CK_FALSE;
CK_BBOOL cextractable = CK_FALSE;
/* ids we create are 16 bytes of data */
unsigned char id[16];
/* that's 33 bytes in string (16*2 + 1 for \0) */
char id_str[33];
session = hsm_find_repository_session(ctx, repository);
if (!session) return NULL;
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
generate_unique_id(ctx, id, 16);
/* the CKA_LABEL will contain a hexadecimal string representation
* of the id */
hsm_hex_unparse(id_str, id, 16);
CK_KEY_TYPE keyType = CKK_DSA;
CK_MECHANISM mechanism1 = {
CKM_DSA_PARAMETER_GEN, NULL_PTR, 0
};
CK_MECHANISM mechanism2 = {
CKM_DSA_KEY_PAIR_GEN, NULL_PTR, 0
};
/* The maximum size for DSA in DNSSEC */
CK_BYTE dsa_p[128];
CK_BYTE dsa_q[20];
CK_BYTE dsa_g[128];
CK_ATTRIBUTE domainTemplate[] = {
{ CKA_PRIME_BITS, &keysize, sizeof(keysize) }
};
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_PRIME, dsa_p, sizeof(dsa_p) },
{ CKA_SUBPRIME, dsa_q, sizeof(dsa_q) },
{ CKA_BASE, dsa_g, sizeof(dsa_g) },
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen(id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_VERIFY, &ctrue, sizeof(ctrue) },
{ CKA_ENCRYPT, &cfalse, sizeof(cfalse) },
{ CKA_WRAP, &cfalse, sizeof(cfalse) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) }
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen (id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_SIGN, &ctrue, sizeof(ctrue) },
{ CKA_DECRYPT, &cfalse, sizeof(cfalse) },
{ CKA_UNWRAP, &cfalse, sizeof(cfalse) },
{ CKA_SENSITIVE, &ctrue, sizeof(ctrue) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) },
{ CKA_PRIVATE, &ctrue, sizeof(ctrue) },
{ CKA_EXTRACTABLE, &cextractable, sizeof (cextractable) }
};
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
/* Generate the domain parameters */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKey(session->session,
&mechanism1,
domainTemplate, 1,
&domainPar);
if (hsm_pkcs11_check_error(ctx, rv, "generate domain parameters")) {
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(session->session,
domainPar, publicKeyTemplate, 3);
if (hsm_pkcs11_check_error(ctx, rv, "get domain parameters")) {
return NULL;
}
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session, domainPar);
if (hsm_pkcs11_check_error(ctx, rv, "destroy domain parameters")) {
return NULL;
}
/* Generate key pair */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
&mechanism2,
publicKeyTemplate, 10,
privateKeyTemplate, 10,
&publicKey,
&privateKey);
if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
return NULL;
}
new_key = libhsm_key_new();
new_key->modulename = strdup(session->module->name);
new_key->public_key = publicKey;
new_key->private_key = privateKey;
return new_key;
}
libhsm_key_t *
hsm_generate_gost_key(hsm_ctx_t *ctx,
const char *repository)
{
CK_RV rv;
libhsm_key_t *new_key;
hsm_session_t *session;
CK_OBJECT_HANDLE publicKey, privateKey;
CK_BBOOL ctrue = CK_TRUE;
CK_BBOOL cfalse = CK_FALSE;
CK_BBOOL cextractable = CK_FALSE;
/* ids we create are 16 bytes of data */
unsigned char id[16];
/* that's 33 bytes in string (16*2 + 1 for \0) */
char id_str[33];
session = hsm_find_repository_session(ctx, repository);
if (!session) return NULL;
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
generate_unique_id(ctx, id, 16);
/* the CKA_LABEL will contain a hexadecimal string representation
* of the id */
hsm_hex_unparse(id_str, id, 16);
CK_KEY_TYPE keyType = CKK_GOSTR3410;
CK_MECHANISM mechanism = {
CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0
};
CK_BYTE oid1[] = { 0x06, 0x07, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };
CK_BYTE oid2[] = { 0x06, 0x07, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x1E, 0x01 };
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_GOSTR3410PARAMS, oid1, sizeof(oid1) },
{ CKA_GOSTR3411PARAMS, oid2, sizeof(oid2) },
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen(id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_VERIFY, &ctrue, sizeof(ctrue) },
{ CKA_ENCRYPT, &cfalse, sizeof(cfalse) },
{ CKA_WRAP, &cfalse, sizeof(cfalse) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) }
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen (id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_SIGN, &ctrue, sizeof(ctrue) },
{ CKA_DECRYPT, &cfalse, sizeof(cfalse) },
{ CKA_UNWRAP, &cfalse, sizeof(cfalse) },
{ CKA_SENSITIVE, &ctrue, sizeof(ctrue) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) },
{ CKA_PRIVATE, &ctrue, sizeof(ctrue) },
{ CKA_EXTRACTABLE, &cextractable, sizeof (cextractable) }
};
/* Generate key pair */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
&mechanism,
publicKeyTemplate, 9,
privateKeyTemplate, 10,
&publicKey,
&privateKey);
if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
return NULL;
}
new_key = libhsm_key_new();
new_key->modulename = strdup(session->module->name);
new_key->public_key = publicKey;
new_key->private_key = privateKey;
return new_key;
}
libhsm_key_t *
hsm_generate_ecdsa_key(hsm_ctx_t *ctx,
const char *repository,
const char *curve)
{
CK_RV rv;
libhsm_key_t *new_key;
hsm_session_t *session;
CK_OBJECT_HANDLE publicKey, privateKey;
CK_BBOOL ctrue = CK_TRUE;
CK_BBOOL cfalse = CK_FALSE;
CK_BBOOL cextractable = CK_FALSE;
/* ids we create are 16 bytes of data */
unsigned char id[16];
/* that's 33 bytes in string (16*2 + 1 for \0) */
char id_str[33];
session = hsm_find_repository_session(ctx, repository);
if (!session) return NULL;
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
generate_unique_id(ctx, id, 16);
/* the CKA_LABEL will contain a hexadecimal string representation
* of the id */
hsm_hex_unparse(id_str, id, 16);
CK_KEY_TYPE keyType = CKK_EC;
CK_MECHANISM mechanism = {
CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
};
CK_BYTE oidP256[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 };
CK_BYTE oidP384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 };
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_EC_PARAMS, NULL, 0 },
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen(id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_VERIFY, &ctrue, sizeof(ctrue) },
{ CKA_ENCRYPT, &cfalse, sizeof(cfalse) },
{ CKA_WRAP, &cfalse, sizeof(cfalse) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) }
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen (id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_SIGN, &ctrue, sizeof(ctrue) },
{ CKA_DECRYPT, &cfalse, sizeof(cfalse) },
{ CKA_UNWRAP, &cfalse, sizeof(cfalse) },
{ CKA_SENSITIVE, &ctrue, sizeof(ctrue) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) },
{ CKA_PRIVATE, &ctrue, sizeof(ctrue) },
{ CKA_EXTRACTABLE, &cextractable, sizeof (cextractable) }
};
/* Select the curve */
if (strcmp(curve, "P-256") == 0)
{
publicKeyTemplate[0].pValue = oidP256;
publicKeyTemplate[0].ulValueLen = sizeof(oidP256);
}
else if (strcmp(curve, "P-384") == 0)
{
publicKeyTemplate[0].pValue = oidP384;
publicKeyTemplate[0].ulValueLen = sizeof(oidP384);
}
else
{
return NULL;
}
/* Generate key pair */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
&mechanism,
publicKeyTemplate, 8,
privateKeyTemplate, 10,
&publicKey,
&privateKey);
if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
return NULL;
}
new_key = libhsm_key_new();
new_key->modulename = strdup(session->module->name);
new_key->public_key = publicKey;
new_key->private_key = privateKey;
return new_key;
}
libhsm_key_t *
hsm_generate_eddsa_key(hsm_ctx_t *ctx,
const char *repository,
const char *curve)
{
CK_RV rv;
libhsm_key_t *new_key;
hsm_session_t *session;
CK_OBJECT_HANDLE publicKey, privateKey;
CK_BBOOL ctrue = CK_TRUE;
CK_BBOOL cfalse = CK_FALSE;
CK_BBOOL cextractable = CK_FALSE;
/* ids we create are 16 bytes of data */
unsigned char id[16];
/* that's 33 bytes in string (16*2 + 1 for \0) */
char id_str[33];
session = hsm_find_repository_session(ctx, repository);
if (!session) return NULL;
cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
generate_unique_id(ctx, id, 16);
/* the CKA_LABEL will contain a hexadecimal string representation
* of the id */
hsm_hex_unparse(id_str, id, 16);
CK_KEY_TYPE keyType = CKK_EC_EDWARDS;
CK_MECHANISM mechanism = {
CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL_PTR, 0
};
CK_BYTE oid25519[] = { 0x06, 0x03, 0x2B, 0x65, 0x70 };
CK_BYTE oid448[] = { 0x06, 0x03, 0x2B, 0x65, 0x71 };
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_EC_PARAMS, NULL, 0 },
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen(id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_VERIFY, &ctrue, sizeof(ctrue) },
{ CKA_ENCRYPT, &cfalse, sizeof(cfalse) },
{ CKA_WRAP, &cfalse, sizeof(cfalse) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) }
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_LABEL,(CK_UTF8CHAR*) id_str, strlen (id_str) },
{ CKA_ID, id, 16 },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_SIGN, &ctrue, sizeof(ctrue) },
{ CKA_DECRYPT, &cfalse, sizeof(cfalse) },
{ CKA_UNWRAP, &cfalse, sizeof(cfalse) },
{ CKA_SENSITIVE, &ctrue, sizeof(ctrue) },
{ CKA_TOKEN, &ctrue, sizeof(ctrue) },
{ CKA_PRIVATE, &ctrue, sizeof(ctrue) },
{ CKA_EXTRACTABLE, &cextractable, sizeof (cextractable) }
};
/* Select the curve */
if (strcmp(curve, "edwards25519") == 0)
{
publicKeyTemplate[0].pValue = oid25519;
publicKeyTemplate[0].ulValueLen = sizeof(oid25519);
}
else if (strcmp(curve, "edwards448") == 0)
{
publicKeyTemplate[0].pValue = oid448;
publicKeyTemplate[0].ulValueLen = sizeof(oid448);
}
else
{
return NULL;
}
/* Generate key pair */
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
&mechanism,
publicKeyTemplate, 8,
privateKeyTemplate, 10,
&publicKey,
&privateKey);
if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
return NULL;
}
new_key = libhsm_key_new();
new_key->modulename = strdup(session->module->name);
new_key->public_key = publicKey;
new_key->private_key = privateKey;
return new_key;
}
int
hsm_remove_key(hsm_ctx_t *ctx, libhsm_key_t *key)
{
CK_RV rv;
hsm_session_t *session;
if (!key) return -1;
session = hsm_find_key_session(ctx, key);
if (!session) return -2;
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
key->private_key);
if (hsm_pkcs11_check_error(ctx, rv, "Destroy private key")) {
return -3;
}
key->private_key = 0;
if (key->public_key) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
key->public_key);
if (hsm_pkcs11_check_error(ctx, rv, "Destroy public key")) {
return -4;
}
}
key->public_key = 0;
return 0;
}
void
libhsm_key_list_free(libhsm_key_t **key_list, size_t count)
{
size_t i;
for (i = 0; i < count; i++) {
libhsm_key_free(key_list[i]);
}
free(key_list);
}
char *
hsm_get_key_id(hsm_ctx_t *ctx, const libhsm_key_t *key)
{
unsigned char *id;
char *id_str;
size_t len;
hsm_session_t *session;
if (!key) return NULL;
session = hsm_find_key_session(ctx, key);
if (!session) return NULL;
id = hsm_get_id_for_object(ctx, session, key->private_key, &len);
if (!id) return NULL;
/* this is plain binary data, we need to convert it to hex */
CHECKALLOC(id_str = malloc(len * 2 + 1));
hsm_hex_unparse(id_str, id, len);
free(id);
return id_str;
}
libhsm_key_info_t *
hsm_get_key_info(hsm_ctx_t *ctx,
const libhsm_key_t *key)
{
libhsm_key_info_t *key_info;
hsm_session_t *session;
session = hsm_find_key_session(ctx, key);
if (!session) return NULL;
CHECKALLOC(key_info = malloc(sizeof(libhsm_key_info_t)));
key_info->id = hsm_get_key_id(ctx, key);
if (key_info->id == NULL) {
key_info->id = strdup("");
}
key_info->algorithm = (unsigned long) hsm_get_key_algorithm(ctx,
session,
key);
key_info->keysize = (unsigned long) hsm_get_key_size(ctx,
session,
key,
key_info->algorithm);
switch(key_info->algorithm) {
case CKK_RSA:
key_info->algorithm_name = strdup("RSA");
break;
case CKK_DSA:
key_info->algorithm_name = strdup("DSA");
break;
case CKK_GOSTR3410:
key_info->algorithm_name = strdup("GOST");
break;
case CKK_EC:
key_info->algorithm_name = strdup("ECDSA");
break;
case CKK_EC_EDWARDS:
key_info->algorithm_name = strdup("EDDSA");
break;
default:
CHECKALLOC(key_info->algorithm_name = malloc(HSM_MAX_ALGONAME));
snprintf(key_info->algorithm_name, HSM_MAX_ALGONAME,
"%lu", key_info->algorithm);
break;
}
return key_info;
}
void
libhsm_key_info_free(libhsm_key_info_t *key_info)
{
if (key_info) {
if (key_info->id) {
free(key_info->id);
}
if (key_info->algorithm_name) {
free(key_info->algorithm_name);
}
free(key_info);
}
}
ldns_rr*
hsm_sign_rrset(hsm_ctx_t *ctx,
const ldns_rr_list* rrset,
const libhsm_key_t *key,
const hsm_sign_params_t *sign_params)
{
ldns_rr *signature;
ldns_buffer *sign_buf;
ldns_rdf *b64_rdf;
size_t i;
if (!key) return NULL;
if (!sign_params) return NULL;
signature = hsm_create_empty_rrsig((ldns_rr_list *)rrset,
sign_params);
/* right now, we have: a key, a semi-sig and an rrset. For
* which we can create the sig and base64 encode that and
* add that to the signature */
sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (ldns_rrsig2buffer_wire(sign_buf, signature)
!= LDNS_STATUS_OK) {
ldns_buffer_free(sign_buf);
/* ERROR */
ldns_rr_free(signature);
return NULL;
}
/* make it canonical */
for(i = 0; i < ldns_rr_list_rr_count(rrset); i++) {
ldns_rr2canonical(ldns_rr_list_rr(rrset, i));
}
/* add the rrset in sign_buf */
if (ldns_rr_list2buffer_wire(sign_buf, rrset)
!= LDNS_STATUS_OK) {
ldns_buffer_free(sign_buf);
ldns_rr_free(signature);
return NULL;
}
b64_rdf = hsm_sign_buffer(ctx, sign_buf, key, sign_params->algorithm);
ldns_buffer_free(sign_buf);
if (!b64_rdf) {
/* signing went wrong */
ldns_rr_free(signature);
return NULL;
}
ldns_rr_rrsig_set_sig(signature, b64_rdf);
return signature;
}
int
hsm_keytag(const char* loc, int alg, int sep, uint16_t* keytag)
{
uint16_t tag;
hsm_ctx_t *hsm_ctx;
hsm_sign_params_t *sign_params;
libhsm_key_t *hsmkey;
ldns_rr *dnskey_rr;
if (!loc) {
return 1;
}
if (!(hsm_ctx = hsm_create_context())) {
return 1;
}
if (!(sign_params = hsm_sign_params_new())) {
hsm_destroy_context(hsm_ctx);
return 1;
}
/* The owner name is not relevant for the keytag calculation.
* However, a ldns_rdf_clone down the path will trip over it. */
sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "dummy");
sign_params->algorithm = (ldns_algorithm) alg;
sign_params->flags = LDNS_KEY_ZONE_KEY;
if (sep)
sign_params->flags |= LDNS_KEY_SEP_KEY;
hsmkey = hsm_find_key_by_id(hsm_ctx, loc);
if (!hsmkey) {
hsm_sign_params_free(sign_params);
hsm_destroy_context(hsm_ctx);
return 1;
}
dnskey_rr = hsm_get_dnskey(hsm_ctx, hsmkey, sign_params);
if (!dnskey_rr) {
libhsm_key_free(hsmkey);
hsm_sign_params_free(sign_params);
hsm_destroy_context(hsm_ctx);
return 1;
}
tag = ldns_calc_keytag(dnskey_rr);
ldns_rr_free(dnskey_rr);
libhsm_key_free(hsmkey);
hsm_sign_params_free(sign_params);
hsm_destroy_context(hsm_ctx);
if (keytag)
*keytag = tag;
return 0;
}
ldns_rr *
hsm_get_dnskey(hsm_ctx_t *ctx,
const libhsm_key_t *key,
const hsm_sign_params_t *sign_params)
{
/* CK_RV rv; */
ldns_rr *dnskey;
hsm_session_t *session;
ldns_rdf *rdata;
if (!key) {
hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL key");
return NULL;
}
if (!sign_params) {
hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL sign_params");
return NULL;
}
session = hsm_find_key_session(ctx, key);
if (!session) return NULL;
dnskey = ldns_rr_new();
ldns_rr_set_type(dnskey, LDNS_RR_TYPE_DNSKEY);
ldns_rr_set_owner(dnskey, ldns_rdf_clone(sign_params->owner));
ldns_rr_push_rdf(dnskey,
ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
sign_params->flags));
ldns_rr_push_rdf(dnskey,
ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
LDNS_DNSSEC_KEYPROTO));
ldns_rr_push_rdf(dnskey,
ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG,
sign_params->algorithm));
rdata = hsm_get_key_rdata(ctx, session, key);
if (rdata == NULL) {
ldns_rr_free(dnskey);
return NULL;
}
ldns_rr_push_rdf(dnskey, rdata);
return dnskey;
}
int
hsm_random_buffer(hsm_ctx_t *ctx,
unsigned char *buffer,
unsigned long length)
{
CK_RV rv;
unsigned int i;
hsm_session_t *session;
if (!buffer) return -1;
/* just try every attached token. If one errors (be it NO_RNG, or
* any other error, simply try the next */
for (i = 0; i < ctx->session_count; i++) {
session = ctx->session[i];
if (session) {
rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateRandom(
session->session,
buffer,
length);
if (rv == CKR_OK) {
return 0;
}
}
}
return 1;
}
uint32_t
hsm_random32(hsm_ctx_t *ctx)
{
uint32_t rnd;
int result;
unsigned char rnd_buf[4];
result = hsm_random_buffer(ctx, rnd_buf, 4);
if (result == 0) {
memcpy(&rnd, rnd_buf, 4);
return rnd;
} else {
return 0;
}
}
uint64_t
hsm_random64(hsm_ctx_t *ctx)
{
uint64_t rnd;
int result;
unsigned char rnd_buf[8];
result = hsm_random_buffer(ctx, rnd_buf, 8);
if (result == 0) {
memcpy(&rnd, rnd_buf, 8);
return rnd;
} else {
return 0;
}
}
/*
* Additional functions
*/
int hsm_attach(const char *repository,
const char *token_label,
const char *path,
const char *pin,
const hsm_config_t *config)
{
hsm_session_t *session;
int result;
result = hsm_session_init(_hsm_ctx,
&session,
repository,
token_label,
path,
pin,
config);
if (result == HSM_OK) {
result = hsm_ctx_add_session(_hsm_ctx, session);
}
return result;
}
int
hsm_token_attached(hsm_ctx_t *ctx, const char *repository)
{
unsigned int i;
for (i = 0; i < ctx->session_count; i++) {
if (ctx->session[i] &&
strcmp(ctx->session[i]->module->name, repository) == 0) {
return 1;
}
}
hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
"hsm_token_attached()",
"Can't find repository: %s", repository);
return 0;
}
char *
hsm_get_error(hsm_ctx_t *gctx)
{
hsm_ctx_t *ctx;
char *message;
if (!gctx) {
ctx = _hsm_ctx;
} else {
ctx = gctx;
}
if (ctx->error) {
ctx->error = 0;
CHECKALLOC(message = malloc(HSM_ERROR_MSGSIZE+3));
snprintf(message, HSM_ERROR_MSGSIZE,
"%s: %s",
ctx->error_action ? ctx->error_action : "unknown()",
ctx->error_message[0] ? ctx->error_message : "unknown error");
/* Since both message and ctx->error_message have the same length, the
* snprintf statement above may be truncated. In this case the string
* won't be null-terminated. */
message[HSM_ERROR_MSGSIZE - 1U] = '\0';
return message;
};
return NULL;
}
void
hsm_print_session(hsm_session_t *session)
{
printf("\t\tmodule at %p (sym %p)\n", (void *) session->module, (void *) session->module->sym);
printf("\t\tmodule path: %s\n", session->module->path);
printf("\t\trepository name: %s\n", session->module->name);
printf("\t\ttoken label: %s\n", session->module->token_label);
printf("\t\tsess handle: %u\n", (unsigned int) session->session);
}
void
hsm_print_ctx(hsm_ctx_t *ctx) {
unsigned int i;
printf("CTX Sessions: %lu\n",
(long unsigned int) ctx->session_count);
for (i = 0; i < ctx->session_count; i++) {
printf("\tSession at %p\n", (void *) ctx->session[i]);
hsm_print_session(ctx->session[i]);
}
}
void
hsm_print_key(hsm_ctx_t *ctx, libhsm_key_t *key) {
libhsm_key_info_t *key_info;
if (key) {
key_info = hsm_get_key_info(ctx, key);
if (key_info) {
printf("key:\n");
printf("\tprivkey handle: %u\n", (unsigned int) key->private_key);
if (key->public_key) {
printf("\tpubkey handle: %u\n", (unsigned int) key->public_key);
} else {
printf("\tpubkey handle: %s\n", "NULL");
}
printf("\trepository: %s\n", key->modulename);
printf("\talgorithm: %s\n", key_info->algorithm_name);
printf("\tsize: %lu\n", key_info->keysize);
printf("\tid: %s\n", key_info->id);
libhsm_key_info_free(key_info);
} else {
printf("key: hsm_get_key_info() returned NULL\n");
}
} else {
printf("key: <void>\n");
}
}
void
hsm_print_error(hsm_ctx_t *gctx)
{
char *message;
message = hsm_get_error(gctx);
if (message) {
fprintf(stderr, "%s\n", message);
free(message);
} else {
fprintf(stderr, "Unknown error\n");
}
}
void
hsm_print_tokeninfo(hsm_ctx_t *ctx)
{
CK_RV rv;
CK_SLOT_ID slot_id;
CK_TOKEN_INFO token_info;
unsigned int i;
hsm_session_t *session;
int result;
for (i = 0; i < ctx->session_count; i++) {
session = ctx->session[i];
result = hsm_get_slot_id(ctx,
session->module->sym,
session->module->token_label,
&slot_id);
if (result != HSM_OK) return;
rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_GetTokenInfo(slot_id, &token_info);
if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
return;
}
printf("Repository: %s\n",session->module->name);
printf("\tModule: %s\n", session->module->path);
printf("\tSlot: %lu\n", slot_id);
printf("\tToken Label: %.*s\n",
(int) sizeof(token_info.label), token_info.label);
printf("\tManufacturer: %.*s\n",
(int) sizeof(token_info.manufacturerID), token_info.manufacturerID);
printf("\tModel: %.*s\n",
(int) sizeof(token_info.model), token_info.model);
printf("\tSerial: %.*s\n",
(int) sizeof(token_info.serialNumber), token_info.serialNumber);
if (i + 1 != ctx->session_count)
printf("\n");
}
}
static int
keycache_cmpfunc(const void* a, const void* b)
{
const char* x = (const char*)a;
const char* y = (const char*)b;
return strcmp(x, y);
}
static void
keycache_delfunc(ldns_rbnode_t* node, void* cargo)
{
(void)cargo;
free((void*)node->key);
free(((libhsm_key_t*)node->data)->modulename);
free((void*)node->data);
free((void*)node);
}
void
keycache_create(hsm_ctx_t* ctx)
{
ctx->keycache = ldns_rbtree_create(keycache_cmpfunc);
CHECKALLOC(_hsm_ctx->keycache_lock = malloc(sizeof (pthread_mutex_t)));
pthread_mutex_init(_hsm_ctx->keycache_lock, NULL);
}
void
keycache_destroy(hsm_ctx_t* ctx)
{
ldns_traverse_postorder(ctx->keycache, keycache_delfunc, NULL);
ldns_rbtree_free(ctx->keycache);
pthread_mutex_destroy(ctx->keycache_lock);
free(ctx->keycache_lock);
ctx->keycache_lock = NULL;
}
const libhsm_key_t*
keycache_lookup(hsm_ctx_t* ctx, const char* locator)
{
ldns_rbnode_t* node;
pthread_mutex_lock(ctx->keycache_lock);
node = ldns_rbtree_search(ctx->keycache, locator);
pthread_mutex_unlock(ctx->keycache_lock);
if (node == LDNS_RBTREE_NULL || node == NULL) {
libhsm_key_t* key;
if ((key = hsm_find_key_by_id(ctx, locator)) == NULL) {
node = NULL;
} else {
CHECKALLOC(node = malloc(sizeof(ldns_rbnode_t)));
node->key = strdup(locator);
node->data = key;
pthread_mutex_lock(ctx->keycache_lock);
node = ldns_rbtree_insert(ctx->keycache, node);
pthread_mutex_unlock(ctx->keycache_lock);
}
}
if (node == LDNS_RBTREE_NULL || node == NULL)
return NULL;
else
return node->data;
}
algorithm
ldns_algorithm algorithm
Definition hsmspeed.c:43
ctx
hsm_ctx_t * ctx
Definition hsmutil.c:46
hsm_repository_new
hsm_repository_t * hsm_repository_new(char *name, char *module, char *tokenlabel, char *pin, uint8_t use_pubkey, uint8_t allowextract, uint8_t require_backup)
Definition libhsm.c:374
_hsm_ctx
hsm_ctx_t * _hsm_ctx
Definition libhsm.c:59
hsm_sign_rrset
ldns_rr * hsm_sign_rrset(hsm_ctx_t *ctx, const ldns_rr_list *rrset, const libhsm_key_t *key, const hsm_sign_params_t *sign_params)
Definition libhsm.c:3153
libhsm_key_list_free
void libhsm_key_list_free(libhsm_key_t **key_list, size_t count)
Definition libhsm.c:3052
hsm_ctx_set_error
void hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action, const char *message,...)
Definition libhsm.c:209
keycache_lookup
const libhsm_key_t * keycache_lookup(hsm_ctx_t *ctx, const char *locator)
Definition libhsm.c:3585
_hsm_ctx_mutex
pthread_mutex_t _hsm_ctx_mutex
Definition libhsm.c:60
hsm_random64
uint64_t hsm_random64(hsm_ctx_t *ctx)
Definition libhsm.c:3354
hsm_get_error
char * hsm_get_error(hsm_ctx_t *gctx)
Definition libhsm.c:3413
hsm_random32
uint32_t hsm_random32(hsm_ctx_t *ctx)
Definition libhsm.c:3339
hsm_print_error
void hsm_print_error(hsm_ctx_t *gctx)
Definition libhsm.c:3492
hsm_find_key_by_id
libhsm_key_t * hsm_find_key_by_id(hsm_ctx_t *ctx, const char *id)
Definition libhsm.c:2520
hsm_token_attached
int hsm_token_attached(hsm_ctx_t *ctx, const char *repository)
Definition libhsm.c:3396
HSM_TOKEN_LABEL_LENGTH
#define HSM_TOKEN_LABEL_LENGTH
Definition libhsm.c:56
hsm_generate_rsa_key
libhsm_key_t * hsm_generate_rsa_key(hsm_ctx_t *ctx, const char *repository, unsigned long keysize)
Definition libhsm.c:2549
hsm_generate_gost_key
libhsm_key_t * hsm_generate_gost_key(hsm_ctx_t *ctx, const char *repository)
Definition libhsm.c:2751
hsm_print_key
void hsm_print_key(hsm_ctx_t *ctx, libhsm_key_t *key)
Definition libhsm.c:3466
hsm_sign_params_new
hsm_sign_params_t * hsm_sign_params_new()
Definition libhsm.c:2447
hsm_print_ctx
void hsm_print_ctx(hsm_ctx_t *ctx)
Definition libhsm.c:3455
hsm_repository_free
void hsm_repository_free(hsm_repository_t *r)
Definition libhsm.c:407
hsm_attach
int hsm_attach(const char *repository, const char *token_label, const char *path, const char *pin, const hsm_config_t *config)
Definition libhsm.c:3373
hsm_check_context
int hsm_check_context()
Definition libhsm.c:2383
hsm_get_key_id
char * hsm_get_key_id(hsm_ctx_t *ctx, const libhsm_key_t *key)
Definition libhsm.c:3062
libhsm_key_info_free
void libhsm_key_info_free(libhsm_key_info_t *key_info)
Definition libhsm.c:3139
hsm_list_keys_repository
libhsm_key_t ** hsm_list_keys_repository(hsm_ctx_t *ctx, size_t *count, const char *repository)
Definition libhsm.c:2503
hsm_random_buffer
int hsm_random_buffer(hsm_ctx_t *ctx, unsigned char *buffer, unsigned long length)
Definition libhsm.c:3312
hsm_open2
int hsm_open2(hsm_repository_t *rlist, char *(pin_callback)(unsigned int, const char *, unsigned int))
Definition libhsm.c:2296
hsm_get_dnskey
ldns_rr * hsm_get_dnskey(hsm_ctx_t *ctx, const libhsm_key_t *key, const hsm_sign_params_t *sign_params)
Definition libhsm.c:3266
hsm_generate_dsa_key
libhsm_key_t * hsm_generate_dsa_key(hsm_ctx_t *ctx, const char *repository, unsigned long keysize)
Definition libhsm.c:2637
hsm_generate_eddsa_key
libhsm_key_t * hsm_generate_eddsa_key(hsm_ctx_t *ctx, const char *repository, const char *curve)
Definition libhsm.c:2927
hsm_keytag
int hsm_keytag(const char *loc, int alg, int sep, uint16_t *keytag)
Definition libhsm.c:3210
hsm_generate_ecdsa_key
libhsm_key_t * hsm_generate_ecdsa_key(hsm_ctx_t *ctx, const char *repository, const char *curve)
Definition libhsm.c:2831
hsm_close
void hsm_close()
Definition libhsm.c:2363
hsm_print_session
void hsm_print_session(hsm_session_t *session)
Definition libhsm.c:3445
keycache_create
void keycache_create(hsm_ctx_t *ctx)
Definition libhsm.c:3567
hsm_remove_key
int hsm_remove_key(hsm_ctx_t *ctx, libhsm_key_t *key)
Definition libhsm.c:3023
hsm_print_tokeninfo
void hsm_print_tokeninfo(hsm_ctx_t *ctx)
Definition libhsm.c:3507
hsm_get_key_info
libhsm_key_info_t * hsm_get_key_info(hsm_ctx_t *ctx, const libhsm_key_t *key)
Definition libhsm.c:3088
hsm_destroy_context
void hsm_destroy_context(hsm_ctx_t *ctx)
Definition libhsm.c:2438
hsm_list_keys
libhsm_key_t ** hsm_list_keys(hsm_ctx_t *ctx, size_t *count)
Definition libhsm.c:2477
keycache_destroy
void keycache_destroy(hsm_ctx_t *ctx)
Definition libhsm.c:3575
libhsm_key_free
void libhsm_key_free(libhsm_key_t *key)
Definition libhsm.c:2470
hsm_sign_params_free
void hsm_sign_params_free(hsm_sign_params_t *params)
Definition libhsm.c:2461
hsm_create_context
hsm_ctx_t * hsm_create_context()
Definition libhsm.c:2373
libhsm.h
HSM_NO_REPOSITORIES
#define HSM_NO_REPOSITORIES
Definition libhsm.h:70
hsm_repository_t
struct hsm_repository_struct hsm_repository_t
Definition libhsm.h:117
HSM_ERROR
#define HSM_ERROR
Definition libhsm.h:66
HSM_PIN_RETRY
#define HSM_PIN_RETRY
Definition libhsm.h:75
HSM_ERROR_MSGSIZE
#define HSM_ERROR_MSGSIZE
Definition libhsm.h:49
HSM_MODULE_NOT_FOUND
#define HSM_MODULE_NOT_FOUND
Definition libhsm.h:71
HSM_PIN_SAVE
#define HSM_PIN_SAVE
Definition libhsm.h:76
HSM_MAX_ALGONAME
#define HSM_MAX_ALGONAME
Definition libhsm.h:47
HSM_REPOSITORY_NOT_FOUND
#define HSM_REPOSITORY_NOT_FOUND
Definition libhsm.h:69
HSM_PIN_FIRST
#define HSM_PIN_FIRST
Definition libhsm.h:74
HSM_MAX_SIGNATURE_LENGTH
#define HSM_MAX_SIGNATURE_LENGTH
Definition libhsm.h:53
HSM_OK
#define HSM_OK
Definition libhsm.h:65
HSM_MAX_SESSIONS
#define HSM_MAX_SESSIONS
Definition libhsm.h:35
HSM_PIN_INCORRECT
#define HSM_PIN_INCORRECT
Definition libhsm.h:67
libhsmdns.h
pkcs11.h
CKM_DSA_PARAMETER_GEN
#define CKM_DSA_PARAMETER_GEN
Definition pkcs11.h:682
CKR_SESSION_COUNT
#define CKR_SESSION_COUNT
Definition pkcs11.h:1152
CKR_DEVICE_MEMORY
#define CKR_DEVICE_MEMORY
Definition pkcs11.h:1124
CKA_TOKEN
#define CKA_TOKEN
Definition pkcs11.h:375
CKR_GENERAL_ERROR
#define CKR_GENERAL_ERROR
Definition pkcs11.h:1111
CKR_MECHANISM_INVALID
#define CKR_MECHANISM_INVALID
Definition pkcs11.h:1141
CKR_SLOT_ID_INVALID
#define CKR_SLOT_ID_INVALID
Definition pkcs11.h:1110
CKM_RSA_PKCS
#define CKM_RSA_PKCS
Definition pkcs11.h:482
CKR_ATTRIBUTE_TYPE_INVALID
#define CKR_ATTRIBUTE_TYPE_INVALID
Definition pkcs11.h:1119
CKO_PUBLIC_KEY
#define CKO_PUBLIC_KEY
Definition pkcs11.h:315
CKR_FUNCTION_CANCELED
#define CKR_FUNCTION_CANCELED
Definition pkcs11.h:1128
CKR_DATA_INVALID
#define CKR_DATA_INVALID
Definition pkcs11.h:1121
CKR_UNWRAPPING_KEY_HANDLE_INVALID
#define CKR_UNWRAPPING_KEY_HANDLE_INVALID
Definition pkcs11.h:1166
CKR_WRAPPING_KEY_SIZE_RANGE
#define CKR_WRAPPING_KEY_SIZE_RANGE
Definition pkcs11.h:1178
CKR_MECHANISM_PARAM_INVALID
#define CKR_MECHANISM_PARAM_INVALID
Definition pkcs11.h:1142
CKR_TOKEN_NOT_RECOGNIZED
#define CKR_TOKEN_NOT_RECOGNIZED
Definition pkcs11.h:1164
CKM_MD5
#define CKM_MD5
Definition pkcs11.h:541
CK_FALSE
#define CK_FALSE
Definition pkcs11.h:1227
CKR_ATTRIBUTE_SENSITIVE
#define CKR_ATTRIBUTE_SENSITIVE
Definition pkcs11.h:1118
CK_TOKEN_INFO
struct ck_token_info CK_TOKEN_INFO
Definition pkcs11.h:1249
CKR_PIN_LEN_RANGE
#define CKR_PIN_LEN_RANGE
Definition pkcs11.h:1148
CKR_DEVICE_ERROR
#define CKR_DEVICE_ERROR
Definition pkcs11.h:1123
CKR_RANDOM_SEED_NOT_SUPPORTED
#define CKR_RANDOM_SEED_NOT_SUPPORTED
Definition pkcs11.h:1180
CKR_SESSION_PARALLEL_NOT_SUPPORTED
#define CKR_SESSION_PARALLEL_NOT_SUPPORTED
Definition pkcs11.h:1154
CKM_DSA
#define CKM_DSA
Definition pkcs11.h:497
CKA_ID
#define CKA_ID
Definition pkcs11.h:396
CKR_ATTRIBUTE_READ_ONLY
#define CKR_ATTRIBUTE_READ_ONLY
Definition pkcs11.h:1117
CKR_WRAPPING_KEY_TYPE_INCONSISTENT
#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT
Definition pkcs11.h:1179
CKR_SESSION_EXISTS
#define CKR_SESSION_EXISTS
Definition pkcs11.h:1156
CK_ULONG
unsigned long int CK_ULONG
Definition pkcs11.h:1219
CKK_RSA
#define CKK_RSA
Definition pkcs11.h:334
CKA_PUBLIC_EXPONENT
#define CKA_PUBLIC_EXPONENT
Definition pkcs11.h:411
CKM_RSA_PKCS_KEY_PAIR_GEN
#define CKM_RSA_PKCS_KEY_PAIR_GEN
Definition pkcs11.h:481
CKR_SESSION_READ_ONLY
#define CKR_SESSION_READ_ONLY
Definition pkcs11.h:1155
CK_SESSION_INFO
struct ck_session_info CK_SESSION_INFO
Definition pkcs11.h:1254
CKA_GOSTR3410PARAMS
#define CKA_GOSTR3410PARAMS
Definition pkcs11.h:438
CKR_ENCRYPTED_DATA_LEN_RANGE
#define CKR_ENCRYPTED_DATA_LEN_RANGE
Definition pkcs11.h:1127
CKR_SIGNATURE_INVALID
#define CKR_SIGNATURE_INVALID
Definition pkcs11.h:1159
CKR_SESSION_HANDLE_INVALID
#define CKR_SESSION_HANDLE_INVALID
Definition pkcs11.h:1153
CKF_RW_SESSION
#define CKF_RW_SESSION
Definition pkcs11.h:304
CKA_PRIME
#define CKA_PRIME
Definition pkcs11.h:418
CKR_CANCEL
#define CKR_CANCEL
Definition pkcs11.h:1108
CKA_MODULUS
#define CKA_MODULUS
Definition pkcs11.h:409
CK_BYTE
unsigned char CK_BYTE
Definition pkcs11.h:1215
CKA_PRIVATE
#define CKA_PRIVATE
Definition pkcs11.h:376
NULL_PTR
#define NULL_PTR
Definition pkcs11.h:1282
CK_FUNCTION_LIST_PTR
struct ck_function_list * CK_FUNCTION_LIST_PTR
Definition pkcs11.h:1276
CKR_TOKEN_NOT_PRESENT
#define CKR_TOKEN_NOT_PRESENT
Definition pkcs11.h:1163
CKA_EC_POINT
#define CKA_EC_POINT
Definition pkcs11.h:433
CKR_CRYPTOKI_NOT_INITIALIZED
#define CKR_CRYPTOKI_NOT_INITIALIZED
Definition pkcs11.h:1187
CKA_SENSITIVE
#define CKA_SENSITIVE
Definition pkcs11.h:397
CKR_PIN_INCORRECT
#define CKR_PIN_INCORRECT
Definition pkcs11.h:1146
CKR_WRAPPED_KEY_INVALID
#define CKR_WRAPPED_KEY_INVALID
Definition pkcs11.h:1175
CKA_SIGN
#define CKA_SIGN
Definition pkcs11.h:402
CKR_WRAPPING_KEY_HANDLE_INVALID
#define CKR_WRAPPING_KEY_HANDLE_INVALID
Definition pkcs11.h:1177
CKR_MUTEX_NOT_LOCKED
#define CKR_MUTEX_NOT_LOCKED
Definition pkcs11.h:1190
CKR_SESSION_CLOSED
#define CKR_SESSION_CLOSED
Definition pkcs11.h:1151
CKM_EDDSA
#define CKM_EDDSA
Definition pkcs11.h:664
CK_TRUE
#define CK_TRUE
Definition pkcs11.h:1228
CKM_DSA_KEY_PAIR_GEN
#define CKM_DSA_KEY_PAIR_GEN
Definition pkcs11.h:496
CKA_VALUE
#define CKA_VALUE
Definition pkcs11.h:379
CKM_GOSTR3410
#define CKM_GOSTR3410
Definition pkcs11.h:679
CK_BYTE_PTR
CK_BYTE * CK_BYTE_PTR
Definition pkcs11.h:1221
value
#define value
Definition pkcs11.h:150
CKF_OS_LOCKING_OK
#define CKF_OS_LOCKING_OK
Definition pkcs11.h:1105
CKM_EC_EDWARDS_KEY_PAIR_GEN
#define CKM_EC_EDWARDS_KEY_PAIR_GEN
Definition pkcs11.h:663
CKR_OBJECT_HANDLE_INVALID
#define CKR_OBJECT_HANDLE_INVALID
Definition pkcs11.h:1143
CKA_VERIFY
#define CKA_VERIFY
Definition pkcs11.h:404
CKR_PIN_INVALID
#define CKR_PIN_INVALID
Definition pkcs11.h:1147
CKR_UNWRAPPING_KEY_SIZE_RANGE
#define CKR_UNWRAPPING_KEY_SIZE_RANGE
Definition pkcs11.h:1167
CKO_PRIVATE_KEY
#define CKO_PRIVATE_KEY
Definition pkcs11.h:316
CK_MECHANISM
struct ck_mechanism CK_MECHANISM
Definition pkcs11.h:1269
CKR_ENCRYPTED_DATA_INVALID
#define CKR_ENCRYPTED_DATA_INVALID
Definition pkcs11.h:1126
CKR_CRYPTOKI_ALREADY_INITIALIZED
#define CKR_CRYPTOKI_ALREADY_INITIALIZED
Definition pkcs11.h:1188
CKF_SERIAL_SESSION
#define CKF_SERIAL_SESSION
Definition pkcs11.h:305
CKR_FUNCTION_FAILED
#define CKR_FUNCTION_FAILED
Definition pkcs11.h:1112
CKR_OPERATION_NOT_INITIALIZED
#define CKR_OPERATION_NOT_INITIALIZED
Definition pkcs11.h:1145
CKM_EC_KEY_PAIR_GEN
#define CKM_EC_KEY_PAIR_GEN
Definition pkcs11.h:657
CKK_DSA
#define CKK_DSA
Definition pkcs11.h:335
CKR_KEY_SIZE_RANGE
#define CKR_KEY_SIZE_RANGE
Definition pkcs11.h:1132
CKR_TEMPLATE_INCONSISTENT
#define CKR_TEMPLATE_INCONSISTENT
Definition pkcs11.h:1162
CKR_OPERATION_ACTIVE
#define CKR_OPERATION_ACTIVE
Definition pkcs11.h:1144
CKR_DATA_LEN_RANGE
#define CKR_DATA_LEN_RANGE
Definition pkcs11.h:1122
CKA_UNWRAP
#define CKA_UNWRAP
Definition pkcs11.h:401
CK_FUNCTION_LIST_PTR_PTR
struct ck_function_list ** CK_FUNCTION_LIST_PTR_PTR
Definition pkcs11.h:1277
CKK_GOSTR3410
#define CKK_GOSTR3410
Definition pkcs11.h:359
CK_BBOOL
unsigned char CK_BBOOL
Definition pkcs11.h:1218
CKR_BUFFER_TOO_SMALL
#define CKR_BUFFER_TOO_SMALL
Definition pkcs11.h:1183
CKS_RW_USER_FUNCTIONS
#define CKS_RW_USER_FUNCTIONS
Definition pkcs11.h:292
CKA_DECRYPT
#define CKA_DECRYPT
Definition pkcs11.h:399
CKA_KEY_TYPE
#define CKA_KEY_TYPE
Definition pkcs11.h:394
CKR_USER_PIN_NOT_INITIALIZED
#define CKR_USER_PIN_NOT_INITIALIZED
Definition pkcs11.h:1171
CKR_USER_ALREADY_LOGGED_IN
#define CKR_USER_ALREADY_LOGGED_IN
Definition pkcs11.h:1169
CKR_STATE_UNSAVEABLE
#define CKR_STATE_UNSAVEABLE
Definition pkcs11.h:1186
CKK_EC_EDWARDS
#define CKK_EC_EDWARDS
Definition pkcs11.h:360
CKR_INFORMATION_SENSITIVE
#define CKR_INFORMATION_SENSITIVE
Definition pkcs11.h:1185
CKR_OK
#define CKR_OK
Definition pkcs11.h:1107
CKM_ECDSA
#define CKM_ECDSA
Definition pkcs11.h:658
CKA_SUBPRIME
#define CKA_SUBPRIME
Definition pkcs11.h:419
CK_ATTRIBUTE
struct ck_attribute CK_ATTRIBUTE
Definition pkcs11.h:1261
CKR_ATTRIBUTE_VALUE_INVALID
#define CKR_ATTRIBUTE_VALUE_INVALID
Definition pkcs11.h:1120
CKM_GOSTR3411
#define CKM_GOSTR3411
Definition pkcs11.h:681
CKR_FUNCTION_NOT_SUPPORTED
#define CKR_FUNCTION_NOT_SUPPORTED
Definition pkcs11.h:1130
CK_C_INITIALIZE_ARGS
struct ck_c_initialize_args CK_C_INITIALIZE_ARGS
Definition pkcs11.h:1279
slot_id
#define slot_id
Definition pkcs11.h:139
CKR_USER_NOT_LOGGED_IN
#define CKR_USER_NOT_LOGGED_IN
Definition pkcs11.h:1170
CKR_DEVICE_REMOVED
#define CKR_DEVICE_REMOVED
Definition pkcs11.h:1125
CKR_TOKEN_WRITE_PROTECTED
#define CKR_TOKEN_WRITE_PROTECTED
Definition pkcs11.h:1165
CKA_MODULUS_BITS
#define CKA_MODULUS_BITS
Definition pkcs11.h:410
CKA_LABEL
#define CKA_LABEL
Definition pkcs11.h:377
CKA_EXTRACTABLE
#define CKA_EXTRACTABLE
Definition pkcs11.h:425
CKR_TEMPLATE_INCOMPLETE
#define CKR_TEMPLATE_INCOMPLETE
Definition pkcs11.h:1161
CK_LONG
long int CK_LONG
Definition pkcs11.h:1220
CKA_ENCRYPT
#define CKA_ENCRYPT
Definition pkcs11.h:398
CKM_GOSTR3410_KEY_PAIR_GEN
#define CKM_GOSTR3410_KEY_PAIR_GEN
Definition pkcs11.h:678
CKR_HOST_MEMORY
#define CKR_HOST_MEMORY
Definition pkcs11.h:1109
CKR_FUNCTION_NOT_PARALLEL
#define CKR_FUNCTION_NOT_PARALLEL
Definition pkcs11.h:1129
CKR_SIGNATURE_LEN_RANGE
#define CKR_SIGNATURE_LEN_RANGE
Definition pkcs11.h:1160
value_len
#define value_len
Definition pkcs11.h:151
CKR_USER_TYPE_INVALID
#define CKR_USER_TYPE_INVALID
Definition pkcs11.h:1172
CKR_KEY_HANDLE_INVALID
#define CKR_KEY_HANDLE_INVALID
Definition pkcs11.h:1131
CKR_MUTEX_BAD
#define CKR_MUTEX_BAD
Definition pkcs11.h:1189
CKA_GOSTR3411PARAMS
#define CKA_GOSTR3411PARAMS
Definition pkcs11.h:439
CKR_SAVED_STATE_INVALID
#define CKR_SAVED_STATE_INVALID
Definition pkcs11.h:1184
CK_UTF8CHAR
unsigned char CK_UTF8CHAR
Definition pkcs11.h:1217
CKK_EC
#define CKK_EC
Definition pkcs11.h:338
CKR_WRAPPED_KEY_LEN_RANGE
#define CKR_WRAPPED_KEY_LEN_RANGE
Definition pkcs11.h:1176
CKA_PRIME_BITS
#define CKA_PRIME_BITS
Definition pkcs11.h:421
CKA_BASE
#define CKA_BASE
Definition pkcs11.h:420
CKR_KEY_TYPE_INCONSISTENT
#define CKR_KEY_TYPE_INCONSISTENT
Definition pkcs11.h:1133
CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
Definition pkcs11.h:1168
CKA_EC_PARAMS
#define CKA_EC_PARAMS
Definition pkcs11.h:432
CKA_WRAP
#define CKA_WRAP
Definition pkcs11.h:400
CKA_CLASS
#define CKA_CLASS
Definition pkcs11.h:374
ck_function_list::C_GetSlotList
CK_C_GetSlotList C_GetSlotList
Definition pkcs11.h:1020
ck_function_list::C_GetTokenInfo
CK_C_GetTokenInfo C_GetTokenInfo
Definition pkcs11.h:1022
ck_mechanism::mechanism
ck_mechanism_type_t mechanism
Definition pkcs11.h:690
ck_session_info::state
ck_state_t state
Definition pkcs11.h:299
ck_token_info::model
unsigned char model[16]
Definition pkcs11.h:233
ck_token_info::label
unsigned char label[32]
Definition pkcs11.h:231
hsm_config_t
Definition libhsm.h:79
hsm_config_t::allow_extract
unsigned int allow_extract
Definition libhsm.h:81
hsm_config_t::use_pubkey
unsigned int use_pubkey
Definition libhsm.h:80
hsm_ctx_t
Definition libhsm.h:130
hsm_ctx_t::keycache
ldns_rbtree_t * keycache
Definition libhsm.h:144
hsm_ctx_t::keycache_lock
pthread_mutex_t * keycache_lock
Definition libhsm.h:145
hsm_module_t
Definition libhsm.h:85
hsm_module_t::token_label
char * token_label
Definition libhsm.h:88
hsm_module_t::name
char * name
Definition libhsm.h:87
hsm_module_t::handle
void * handle
Definition libhsm.h:90
hsm_module_t::path
char * path
Definition libhsm.h:89
hsm_module_t::sym
void * sym
Definition libhsm.h:91
hsm_module_t::config
hsm_config_t * config
Definition libhsm.h:92
hsm_repository_struct::module
char * module
Definition libhsm.h:121
hsm_repository_struct::next
hsm_repository_t * next
Definition libhsm.h:119
hsm_repository_struct::name
char * name
Definition libhsm.h:120
hsm_repository_struct::tokenlabel
char * tokenlabel
Definition libhsm.h:122
hsm_repository_struct::allow_extract
unsigned int allow_extract
Definition libhsm.h:126
hsm_repository_struct::require_backup
uint8_t require_backup
Definition libhsm.h:124
hsm_repository_struct::use_pubkey
uint8_t use_pubkey
Definition libhsm.h:125
hsm_repository_struct::pin
char * pin
Definition libhsm.h:123
hsm_session_t
Definition libhsm.h:96
hsm_session_t::session
unsigned long session
Definition libhsm.h:98
hsm_session_t::module
hsm_module_t * module
Definition libhsm.h:97
hsm_sign_params_t
Definition libhsmdns.h:34
hsm_sign_params_t::inception
uint32_t inception
Definition libhsmdns.h:40
hsm_sign_params_t::algorithm
ldns_algorithm algorithm
Definition libhsmdns.h:36
hsm_sign_params_t::owner
ldns_rdf * owner
Definition libhsmdns.h:46
hsm_sign_params_t::flags
uint16_t flags
Definition libhsmdns.h:38
hsm_sign_params_t::keytag
uint16_t keytag
Definition libhsmdns.h:44
hsm_sign_params_t::expiration
uint32_t expiration
Definition libhsmdns.h:42
libhsm_key_info_t
Definition libhsm.h:109
libhsm_key_info_t::algorithm
unsigned long algorithm
Definition libhsm.h:111
libhsm_key_info_t::id
char * id
Definition libhsm.h:110
libhsm_key_info_t::algorithm_name
char * algorithm_name
Definition libhsm.h:112
libhsm_key_info_t::keysize
unsigned long keysize
Definition libhsm.h:113
libhsm_key_t
Definition libhsm.h:102
libhsm_key_t::public_key
unsigned long public_key
Definition libhsm.h:105
libhsm_key_t::private_key
unsigned long private_key
Definition libhsm.h:104
libhsm_key_t::modulename
char * modulename
Definition libhsm.h:103