|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Copyright (c) 2001 Markus Friedl
|
|
Packit Service |
2ea82d |
* Copyright (c) 2002 Juha Yrjölä
|
|
Packit Service |
2ea82d |
* Copyright (c) 2002 Olaf Kirch
|
|
Packit Service |
2ea82d |
* Copyright (c) 2003 Kevin Stefanik
|
|
Packit Service |
2ea82d |
* Copyright (c) 2016-2018 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
2ea82d |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
2ea82d |
* are met:
|
|
Packit Service |
2ea82d |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit Service |
2ea82d |
* notice, this list of conditions and the following disclaimer.
|
|
Packit Service |
2ea82d |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit Service |
2ea82d |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit Service |
2ea82d |
* documentation and/or other materials provided with the distribution.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
Packit Service |
2ea82d |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
Packit Service |
2ea82d |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
Packit Service |
2ea82d |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
Packit Service |
2ea82d |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
Packit Service |
2ea82d |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit Service |
2ea82d |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit Service |
2ea82d |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit Service |
2ea82d |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
Packit Service |
2ea82d |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
#include "engine.h"
|
|
Packit Service |
2ea82d |
#include <stdio.h>
|
|
Packit Service |
2ea82d |
#include <string.h>
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
#if defined(_WIN32) || defined(_WIN64)
|
|
Packit Service |
2ea82d |
#define strncasecmp _strnicmp
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* The maximum length of an internally-allocated PIN */
|
|
Packit Service |
2ea82d |
#define MAX_PIN_LENGTH 32
|
|
Packit Service |
2ea82d |
#define MAX_VALUE_LEN 200
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
struct st_engine_ctx {
|
|
Packit Service |
2ea82d |
/* Engine configuration */
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* The PIN used for login. Cache for the ctx_get_pin function.
|
|
Packit Service |
2ea82d |
* The memory for this PIN is always owned internally,
|
|
Packit Service |
2ea82d |
* and may be freed as necessary. Before freeing, the PIN
|
|
Packit Service |
2ea82d |
* must be whitened, to prevent security holes.
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
char *pin;
|
|
Packit Service |
2ea82d |
size_t pin_length;
|
|
Packit Service |
2ea82d |
int verbose;
|
|
Packit Service |
2ea82d |
char *module;
|
|
Packit Service |
2ea82d |
char *init_args;
|
|
Packit Service |
2ea82d |
UI_METHOD *ui_method;
|
|
Packit Service |
2ea82d |
void *callback_data;
|
|
Packit Service |
2ea82d |
int force_login;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Engine initialization mutex */
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
CRYPTO_RWLOCK *rwlock;
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
int rwlock;
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Current operations */
|
|
Packit Service |
2ea82d |
PKCS11_CTX *pkcs11_ctx;
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot_list;
|
|
Packit Service |
2ea82d |
unsigned int slot_count;
|
|
Packit Service |
2ea82d |
};
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* Utility functions */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
void ctx_log(ENGINE_CTX *ctx, int level, const char *format, ...)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
va_list ap;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (level > ctx->verbose)
|
|
Packit Service |
2ea82d |
return;
|
|
Packit Service |
2ea82d |
va_start(ap, format);
|
|
Packit Service |
2ea82d |
vfprintf(stderr, format, ap);
|
|
Packit Service |
2ea82d |
va_end(ap);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static void dump_hex(ENGINE_CTX *ctx, int level,
|
|
Packit Service |
2ea82d |
const unsigned char *val, const size_t len)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
size_t n;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
for (n = 0; n < len; n++)
|
|
Packit Service |
2ea82d |
ctx_log(ctx, level, "%02x", val[n]);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* PIN handling */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Free PIN storage in secure way. */
|
|
Packit Service |
2ea82d |
static void ctx_destroy_pin(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
if (ctx->pin != NULL) {
|
|
Packit Service |
2ea82d |
OPENSSL_cleanse(ctx->pin, ctx->pin_length);
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx->pin);
|
|
Packit Service |
2ea82d |
ctx->pin = NULL;
|
|
Packit Service |
2ea82d |
ctx->pin_length = 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Get the PIN via asking user interface. The supplied call-back data are
|
|
Packit Service |
2ea82d |
* passed to the user interface implemented by an application. Only the
|
|
Packit Service |
2ea82d |
* application knows how to interpret the call-back data.
|
|
Packit Service |
2ea82d |
* A (strdup'ed) copy of the PIN code will be stored in the pin variable. */
|
|
Packit Service |
2ea82d |
static int ctx_get_pin(ENGINE_CTX *ctx, const char* token_label, UI_METHOD *ui_method, void *callback_data)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
UI *ui;
|
|
Packit Service |
2ea82d |
char* prompt;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* call ui to ask for a pin */
|
|
Packit Service |
2ea82d |
ui = UI_new_method(ui_method);
|
|
Packit Service |
2ea82d |
if (ui == NULL) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "UI_new failed\n");
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (callback_data != NULL)
|
|
Packit Service |
2ea82d |
UI_add_user_data(ui, callback_data);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
if (ctx->pin == NULL)
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
ctx->pin_length = MAX_PIN_LENGTH;
|
|
Packit Service |
2ea82d |
prompt = UI_construct_prompt(ui, "PKCS#11 token PIN", token_label);
|
|
Packit Service |
2ea82d |
if (!prompt) {
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (!UI_dup_input_string(ui, prompt,
|
|
Packit Service |
2ea82d |
UI_INPUT_FLAG_DEFAULT_PWD, ctx->pin, 4, MAX_PIN_LENGTH)) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "UI_dup_input_string failed\n");
|
|
Packit Service |
2ea82d |
UI_free(ui);
|
|
Packit Service |
2ea82d |
OPENSSL_free(prompt);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
OPENSSL_free(prompt);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (UI_process(ui)) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "UI_process failed\n");
|
|
Packit Service |
2ea82d |
UI_free(ui);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
UI_free(ui);
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Return 1 if the user has already logged in */
|
|
Packit Service |
2ea82d |
static int slot_logged_in(ENGINE_CTX *ctx, PKCS11_SLOT *slot) {
|
|
Packit Service |
2ea82d |
int logged_in = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Check if already logged in to avoid resetting state */
|
|
Packit Service |
2ea82d |
if (PKCS11_is_logged_in(slot, 0, &logged_in) != 0) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Unable to check if already logged in\n");
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return logged_in;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Log-into the token if necessary.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* @slot is PKCS11 slot to log in
|
|
Packit Service |
2ea82d |
* @tok is PKCS11 token to log in (??? could be derived as @slot->token)
|
|
Packit Service |
2ea82d |
* @ui_method is OpenSSL user interface which is used to ask for a password
|
|
Packit Service |
2ea82d |
* @callback_data are application data to the user interface
|
|
Packit Service |
2ea82d |
* @return 1 on success, 0 on error.
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
static int ctx_login(ENGINE_CTX *ctx, PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
|
|
Packit Service |
2ea82d |
UI_METHOD *ui_method, void *callback_data)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
if (!(ctx->force_login || tok->loginRequired) || slot_logged_in(ctx, slot))
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* If the token has a secure login (i.e., an external keypad),
|
|
Packit Service |
2ea82d |
* then use a NULL PIN. Otherwise, obtain a new PIN if needed. */
|
|
Packit Service |
2ea82d |
if (tok->secureLogin) {
|
|
Packit Service |
2ea82d |
/* Free the PIN if it has already been
|
|
Packit Service |
2ea82d |
* assigned (i.e, cached by ctx_get_pin) */
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
} else if (ctx->pin == NULL) {
|
|
Packit Service |
2ea82d |
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
ctx->pin_length = MAX_PIN_LENGTH;
|
|
Packit Service |
2ea82d |
if (ctx->pin == NULL) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Could not allocate memory for PIN\n");
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
if (!ctx_get_pin(ctx, tok->label, ui_method, callback_data)) {
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "No PIN code was entered\n");
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Now login in with the (possibly NULL) PIN */
|
|
Packit Service |
2ea82d |
if (PKCS11_login(slot, 0, ctx->pin)) {
|
|
Packit Service |
2ea82d |
/* Login failed, so free the PIN if present */
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Login failed\n");
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* Initialization and cleanup */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ENGINE_CTX *ctx_new()
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ENGINE_CTX *ctx;
|
|
Packit Service |
2ea82d |
char *mod;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx = OPENSSL_malloc(sizeof(ENGINE_CTX));
|
|
Packit Service |
2ea82d |
if (ctx == NULL)
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
memset(ctx, 0, sizeof(ENGINE_CTX));
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
mod = getenv("PKCS11_MODULE_PATH");
|
|
Packit Service |
2ea82d |
if (mod) {
|
|
Packit Service |
2ea82d |
ctx->module = OPENSSL_strdup(mod);
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
#ifdef DEFAULT_PKCS11_MODULE
|
|
Packit Service |
2ea82d |
ctx->module = OPENSSL_strdup(DEFAULT_PKCS11_MODULE);
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
ctx->module = NULL;
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
ctx->rwlock = CRYPTO_THREAD_lock_new();
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
ctx->rwlock = CRYPTO_get_dynlock_create_callback() ?
|
|
Packit Service |
2ea82d |
CRYPTO_get_new_dynlockid() : 0;
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return ctx;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Destroy the context allocated with ctx_new() */
|
|
Packit Service |
2ea82d |
int ctx_destroy(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
if (ctx) {
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx->module);
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx->init_args);
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
CRYPTO_THREAD_lock_free(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
if (ctx->rwlock)
|
|
Packit Service |
2ea82d |
CRYPTO_destroy_dynlockid(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Initialize libp11 data: ctx->pkcs11_ctx and ctx->slot_list */
|
|
Packit Service |
2ea82d |
static void ctx_init_libp11_unlocked(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *pkcs11_ctx;
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot_list = NULL;
|
|
Packit Service |
2ea82d |
unsigned int slot_count = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "PKCS#11: Initializing the engine\n");
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
pkcs11_ctx = PKCS11_CTX_new();
|
|
Packit Service |
2ea82d |
PKCS11_CTX_init_args(pkcs11_ctx, ctx->init_args);
|
|
Packit Service |
2ea82d |
PKCS11_set_ui_method(pkcs11_ctx, ctx->ui_method, ctx->callback_data);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* PKCS11_CTX_load() uses C_GetSlotList() via p11-kit */
|
|
Packit Service |
2ea82d |
if (PKCS11_CTX_load(pkcs11_ctx, ctx->module) < 0) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Unable to load module %s\n", ctx->module);
|
|
Packit Service |
2ea82d |
PKCS11_CTX_free(pkcs11_ctx);
|
|
Packit Service |
2ea82d |
return;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* PKCS11_enumerate_slots() uses C_GetSlotList() via libp11 */
|
|
Packit Service |
2ea82d |
if (PKCS11_enumerate_slots(pkcs11_ctx, &slot_list, &slot_count) < 0) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Failed to enumerate slots\n");
|
|
Packit Service |
2ea82d |
PKCS11_CTX_unload(pkcs11_ctx);
|
|
Packit Service |
2ea82d |
PKCS11_CTX_free(pkcs11_ctx);
|
|
Packit Service |
2ea82d |
return;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "Found %u slot%s\n", slot_count,
|
|
Packit Service |
2ea82d |
slot_count <= 1 ? "" : "s");
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx->pkcs11_ctx = pkcs11_ctx;
|
|
Packit Service |
2ea82d |
ctx->slot_list = slot_list;
|
|
Packit Service |
2ea82d |
ctx->slot_count = slot_count;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_init_libp11(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
CRYPTO_THREAD_write_lock(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
if (ctx->rwlock)
|
|
Packit Service |
2ea82d |
CRYPTO_w_lock(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
if (ctx->pkcs11_ctx == NULL || ctx->slot_list == NULL)
|
|
Packit Service |
2ea82d |
ctx_init_libp11_unlocked(ctx);
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
CRYPTO_THREAD_unlock(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
if (ctx->rwlock)
|
|
Packit Service |
2ea82d |
CRYPTO_w_unlock(ctx->rwlock);
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
return ctx->pkcs11_ctx && ctx->slot_list ? 0 : -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Function called from ENGINE_init() */
|
|
Packit Service |
2ea82d |
int ctx_init(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
/* OpenSC implicitly locks CRYPTO_LOCK_ENGINE during C_GetSlotList().
|
|
Packit Service |
2ea82d |
* OpenSSL also locks CRYPTO_LOCK_ENGINE in ENGINE_init().
|
|
Packit Service |
2ea82d |
* Double-locking a non-recursive rwlock causes the application to
|
|
Packit Service |
2ea82d |
* crash or hang, depending on the locking library implementation. */
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Only attempt initialization when dynamic locks are unavailable.
|
|
Packit Service |
2ea82d |
* This likely also indicates a single-threaded application,
|
|
Packit Service |
2ea82d |
* so temporarily unlocking CRYPTO_LOCK_ENGINE should be safe. */
|
|
Packit Service |
2ea82d |
#if OPENSSL_VERSION_NUMBER < 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit Service |
2ea82d |
if (CRYPTO_get_dynlock_create_callback() == NULL ||
|
|
Packit Service |
2ea82d |
CRYPTO_get_dynlock_lock_callback() == NULL ||
|
|
Packit Service |
2ea82d |
CRYPTO_get_dynlock_destroy_callback() == NULL) {
|
|
Packit Service |
2ea82d |
CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
|
|
Packit Service |
2ea82d |
ctx_init_libp11_unlocked(ctx);
|
|
Packit Service |
2ea82d |
CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
|
|
Packit Service |
2ea82d |
return ctx->pkcs11_ctx && ctx->slot_list ? 1 : 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
#else
|
|
Packit Service |
2ea82d |
(void)ctx; /* squash the unused parameter warning */
|
|
Packit Service |
2ea82d |
#endif
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Finish engine operations initialized with ctx_init() */
|
|
Packit Service |
2ea82d |
int ctx_finish(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
if (ctx) {
|
|
Packit Service |
2ea82d |
if (ctx->slot_list) {
|
|
Packit Service |
2ea82d |
PKCS11_release_all_slots(ctx->pkcs11_ctx,
|
|
Packit Service |
2ea82d |
ctx->slot_list, ctx->slot_count);
|
|
Packit Service |
2ea82d |
ctx->slot_list = NULL;
|
|
Packit Service |
2ea82d |
ctx->slot_count = 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (ctx->pkcs11_ctx) {
|
|
Packit Service |
2ea82d |
PKCS11_CTX_unload(ctx->pkcs11_ctx);
|
|
Packit Service |
2ea82d |
PKCS11_CTX_free(ctx->pkcs11_ctx);
|
|
Packit Service |
2ea82d |
ctx->pkcs11_ctx = NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* Certificate handling */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* prototype for OpenSSL ENGINE_load_cert */
|
|
Packit Service |
2ea82d |
/* used by load_cert_ctrl via ENGINE_ctrl for now */
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
|
|
Packit Service |
2ea82d |
const int login)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot;
|
|
Packit Service |
a0c135 |
PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
|
|
Packit Service |
2ea82d |
PKCS11_TOKEN *tok, *match_tok = NULL;
|
|
Packit Service |
2ea82d |
PKCS11_CERT *certs, *selected_cert = NULL;
|
|
Packit Service |
a0c135 |
X509 *x509 = NULL;
|
|
Packit Service |
2ea82d |
unsigned int cert_count, n, m;
|
|
Packit Service |
2ea82d |
unsigned char cert_id[MAX_VALUE_LEN / 2];
|
|
Packit Service |
2ea82d |
size_t cert_id_len = sizeof(cert_id);
|
|
Packit Service |
2ea82d |
char *cert_label = NULL;
|
|
Packit Service |
2ea82d |
char tmp_pin[MAX_PIN_LENGTH+1];
|
|
Packit Service |
2ea82d |
size_t tmp_pin_len = MAX_PIN_LENGTH;
|
|
Packit Service |
2ea82d |
int slot_nr = -1;
|
|
Packit Service |
2ea82d |
char flags[64];
|
|
Packit Service |
a0c135 |
size_t matched_count = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (s_slot_cert_id && *s_slot_cert_id) {
|
|
Packit Service |
2ea82d |
if (!strncasecmp(s_slot_cert_id, "pkcs11:", 7)) {
|
|
Packit Service |
2ea82d |
n = parse_pkcs11_uri(ctx, s_slot_cert_id, &match_tok,
|
|
Packit Service |
2ea82d |
cert_id, &cert_id_len,
|
|
Packit Service |
2ea82d |
tmp_pin, &tmp_pin_len, &cert_label);
|
|
Packit Service |
2ea82d |
if (!n) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0,
|
|
Packit Service |
2ea82d |
"The certificate ID is not a valid PKCS#11 URI\n"
|
|
Packit Service |
2ea82d |
"The PKCS#11 URI format is defined by RFC7512\n");
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
if (ctx->pin != NULL) {
|
|
Packit Service |
2ea82d |
memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
memcpy(ctx->pin, tmp_pin, tmp_pin_len);
|
|
Packit Service |
2ea82d |
ctx->pin_length = tmp_pin_len;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
n = parse_slot_id_string(ctx, s_slot_cert_id, &slot_nr,
|
|
Packit Service |
2ea82d |
cert_id, &cert_id_len, &cert_label);
|
|
Packit Service |
2ea82d |
if (!n) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0,
|
|
Packit Service |
2ea82d |
"The certificate ID is not a valid PKCS#11 URI\n"
|
|
Packit Service |
2ea82d |
"The PKCS#11 URI format is defined by RFC7512\n"
|
|
Packit Service |
2ea82d |
"The legacy ENGINE_pkcs11 ID format is also "
|
|
Packit Service |
2ea82d |
"still accepted for now\n");
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "Looking in slot %d for certificate: ",
|
|
Packit Service |
2ea82d |
slot_nr);
|
|
Packit Service |
2ea82d |
if (cert_id_len != 0) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "id=");
|
|
Packit Service |
2ea82d |
dump_hex(ctx, 1, cert_id, cert_id_len);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (cert_id_len != 0 && cert_label != NULL)
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, " ");
|
|
Packit Service |
2ea82d |
if (cert_label != NULL)
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "label=%s", cert_label);
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "\n");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count,
|
|
Packit Service |
a0c135 |
sizeof(PKCS11_SLOT *));
|
|
Packit Service |
a0c135 |
if (matched_slots == NULL) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Could not allocate memory for matched slots\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
for (n = 0; n < ctx->slot_count; n++) {
|
|
Packit Service |
2ea82d |
slot = ctx->slot_list + n;
|
|
Packit Service |
2ea82d |
flags[0] = '\0';
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
if (!slot->token->initialized)
|
|
Packit Service |
2ea82d |
strcat(flags, "uninitialized, ");
|
|
Packit Service |
2ea82d |
else if (!slot->token->userPinSet)
|
|
Packit Service |
2ea82d |
strcat(flags, "no pin, ");
|
|
Packit Service |
2ea82d |
if (slot->token->loginRequired)
|
|
Packit Service |
2ea82d |
strcat(flags, "login, ");
|
|
Packit Service |
2ea82d |
if (slot->token->readOnly)
|
|
Packit Service |
2ea82d |
strcat(flags, "ro, ");
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
strcpy(flags, "no token");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if ((m = strlen(flags)) != 0) {
|
|
Packit Service |
2ea82d |
flags[m - 2] = '\0';
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slot_nr != -1 &&
|
|
Packit Service |
2ea82d |
slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
|
|
Packit Service |
2ea82d |
found_slot = slot;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
if (match_tok && slot->token &&
|
|
Packit Service |
2ea82d |
(match_tok->label == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->label, slot->token->label)) &&
|
|
Packit Service |
2ea82d |
(match_tok->manufacturer == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->manufacturer, slot->token->manufacturer)) &&
|
|
Packit Service |
2ea82d |
(match_tok->serialnr == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->serialnr, slot->token->serialnr)) &&
|
|
Packit Service |
2ea82d |
(match_tok->model == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->model, slot->token->model))) {
|
|
Packit Service |
2ea82d |
found_slot = slot;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "[%lu] %-25.25s %-16s",
|
|
Packit Service |
2ea82d |
PKCS11_get_slotid_from_slot(slot),
|
|
Packit Service |
2ea82d |
slot->description, flags);
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, " (%s)",
|
|
Packit Service |
2ea82d |
slot->token->label[0] ?
|
|
Packit Service |
2ea82d |
slot->token->label : "no label");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "\n");
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token && !found_slot->token->initialized)
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Found uninitialized token\n");
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
/* Ignore slots without tokens or with uninitialized token */
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token && found_slot->token->initialized) {
|
|
Packit Service |
a0c135 |
matched_slots[matched_count] = found_slot;
|
|
Packit Service |
a0c135 |
matched_count++;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
found_slot = NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
if (matched_count == 0) {
|
|
Packit Service |
a0c135 |
if (match_tok) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Specified object not found\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
/* If the legacy slot ID format was used */
|
|
Packit Service |
a0c135 |
if (slot_nr != -1) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
found_slot = PKCS11_find_token(ctx->pkcs11_ctx,
|
|
Packit Service |
a0c135 |
ctx->slot_list, ctx->slot_count);
|
|
Packit Service |
a0c135 |
/* Ignore if the the token is not initialized */
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token &&
|
|
Packit Service |
a0c135 |
found_slot->token->initialized) {
|
|
Packit Service |
a0c135 |
matched_slots[matched_count] = found_slot;
|
|
Packit Service |
a0c135 |
matched_count++;
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "No tokens found\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
for (n = 0; n < matched_count; n++) {
|
|
Packit Service |
a0c135 |
slot = matched_slots[n];
|
|
Packit Service |
a0c135 |
tok = slot->token;
|
|
Packit Service |
a0c135 |
if (tok == NULL) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Empty token found\n");
|
|
Packit Service |
a0c135 |
break;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
/* In several tokens certificates are marked as private */
|
|
Packit Service |
a0c135 |
if (login) {
|
|
Packit Service |
a0c135 |
/* Only try to login if login is required */
|
|
Packit Service |
a0c135 |
if (tok->loginRequired) {
|
|
Packit Service |
a0c135 |
/* Only try to login if a single slot matched to avoiding trying
|
|
Packit Service |
a0c135 |
* the PIN against all matching slots */
|
|
Packit Service |
a0c135 |
if (matched_count == 1) {
|
|
Packit Service |
a0c135 |
if (!ctx_login(ctx, slot, tok,
|
|
Packit Service |
a0c135 |
ctx->ui_method, ctx->callback_data)) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Multiple matching slots (%lu); will not try to"
|
|
Packit Service |
a0c135 |
" login\n", matched_count);
|
|
Packit Service |
a0c135 |
for (m = 0; m < matched_count; m++){
|
|
Packit Service |
a0c135 |
slot = matched_slots[m];
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "[%u] %s: %s\n", m + 1,
|
|
Packit Service |
a0c135 |
slot->description? slot->description:
|
|
Packit Service |
a0c135 |
"(no description)",
|
|
Packit Service |
a0c135 |
(slot->token && slot->token->label)?
|
|
Packit Service |
a0c135 |
slot->token->label: "no label");
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Unable to enumerate certificates\n");
|
|
Packit Service |
a0c135 |
continue;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found %u cert%s:\n", cert_count,
|
|
Packit Service |
a0c135 |
(cert_count <= 1) ? "" : "s");
|
|
Packit Service |
a0c135 |
if ((s_slot_cert_id && *s_slot_cert_id) &&
|
|
Packit Service |
a0c135 |
(cert_id_len != 0 || cert_label != NULL)) {
|
|
Packit Service |
a0c135 |
for (m = 0; m < cert_count; m++) {
|
|
Packit Service |
a0c135 |
PKCS11_CERT *k = certs + m;
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
if (cert_label != NULL && strcmp(k->label, cert_label) == 0)
|
|
Packit Service |
a0c135 |
selected_cert = k;
|
|
Packit Service |
a0c135 |
if (cert_id_len != 0 && k->id_len == cert_id_len &&
|
|
Packit Service |
a0c135 |
memcmp(k->id, cert_id, cert_id_len) == 0)
|
|
Packit Service |
a0c135 |
selected_cert = k;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
for (m = 0; m < cert_count; m++) {
|
|
Packit Service |
a0c135 |
PKCS11_CERT *k = certs + m;
|
|
Packit Service |
a0c135 |
if (k->id && *(k->id)) {
|
|
Packit Service |
a0c135 |
selected_cert = k; /* Use the first certificate with nonempty id */
|
|
Packit Service |
a0c135 |
break;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
if (!selected_cert)
|
|
Packit Service |
a0c135 |
selected_cert = certs; /* Use the first certificate */
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
if (selected_cert) {
|
|
Packit Service |
a0c135 |
break;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (selected_cert != NULL) {
|
|
Packit Service |
2ea82d |
x509 = X509_dup(selected_cert->x509);
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
if (login) /* Only print the error on the second attempt */
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Certificate not found.\n");
|
|
Packit Service |
2ea82d |
x509 = NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
error:
|
|
Packit Service |
a0c135 |
/* Free the searched token data */
|
|
Packit Service |
a0c135 |
if (match_tok) {
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->model);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->manufacturer);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->serialnr);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->label);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok);
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
if (cert_label != NULL)
|
|
Packit Service |
2ea82d |
OPENSSL_free(cert_label);
|
|
Packit Service |
a0c135 |
if (matched_slots != NULL)
|
|
Packit Service |
a0c135 |
free(matched_slots);
|
|
Packit Service |
2ea82d |
return x509;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_load_cert(ENGINE_CTX *ctx, void *p)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
struct {
|
|
Packit Service |
2ea82d |
const char *s_slot_cert_id;
|
|
Packit Service |
2ea82d |
X509 *cert;
|
|
Packit Service |
2ea82d |
} *parms = p;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (parms == NULL) {
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ERR_R_PASSED_NULL_PARAMETER);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (parms->cert != NULL) {
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_INVALID_PARAMETER);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
if (!ctx->force_login)
|
|
Packit Service |
2ea82d |
parms->cert = ctx_load_cert(ctx, parms->s_slot_cert_id, 0);
|
|
Packit Service |
2ea82d |
if (parms->cert == NULL) { /* Try again with login */
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
parms->cert = ctx_load_cert(ctx, parms->s_slot_cert_id, 1);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (parms->cert == NULL) {
|
|
Packit Service |
2ea82d |
if (!ERR_peek_last_error())
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_OBJECT_NOT_FOUND);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* Private and public key handling */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
|
|
Packit Service |
2ea82d |
UI_METHOD *ui_method, void *callback_data,
|
|
Packit Service |
2ea82d |
const int isPrivate, const int login)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot;
|
|
Packit Service |
a0c135 |
PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
|
|
Packit Service |
2ea82d |
PKCS11_TOKEN *tok, *match_tok = NULL;
|
|
Packit Service |
2ea82d |
PKCS11_KEY *keys, *selected_key = NULL;
|
|
Packit Service |
2ea82d |
EVP_PKEY *pk = NULL;
|
|
Packit Service |
2ea82d |
unsigned int key_count, n, m;
|
|
Packit Service |
2ea82d |
unsigned char key_id[MAX_VALUE_LEN / 2];
|
|
Packit Service |
2ea82d |
size_t key_id_len = sizeof(key_id);
|
|
Packit Service |
2ea82d |
char *key_label = NULL;
|
|
Packit Service |
2ea82d |
int slot_nr = -1;
|
|
Packit Service |
2ea82d |
char tmp_pin[MAX_PIN_LENGTH+1];
|
|
Packit Service |
2ea82d |
size_t tmp_pin_len = MAX_PIN_LENGTH;
|
|
Packit Service |
2ea82d |
char flags[64];
|
|
Packit Service |
a0c135 |
size_t matched_count = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
|
|
Packit Service |
2ea82d |
goto error;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "Loading %s key \"%s\"\n",
|
|
Packit Service |
2ea82d |
(char *)(isPrivate ? "private" : "public"),
|
|
Packit Service |
2ea82d |
s_slot_key_id);
|
|
Packit Service |
2ea82d |
if (s_slot_key_id && *s_slot_key_id) {
|
|
Packit Service |
2ea82d |
if (!strncasecmp(s_slot_key_id, "pkcs11:", 7)) {
|
|
Packit Service |
2ea82d |
n = parse_pkcs11_uri(ctx, s_slot_key_id, &match_tok,
|
|
Packit Service |
2ea82d |
key_id, &key_id_len,
|
|
Packit Service |
2ea82d |
tmp_pin, &tmp_pin_len, &key_label);
|
|
Packit Service |
2ea82d |
if (!n) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0,
|
|
Packit Service |
2ea82d |
"The key ID is not a valid PKCS#11 URI\n"
|
|
Packit Service |
2ea82d |
"The PKCS#11 URI format is defined by RFC7512\n");
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_KEY, ENG_R_INVALID_ID);
|
|
Packit Service |
2ea82d |
goto error;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
|
|
Packit Service |
a0c135 |
/* If the searched key is public, try without login once even
|
|
Packit Service |
a0c135 |
* when the PIN is provided */
|
|
Packit Service |
a0c135 |
if (!login && isPrivate)
|
|
Packit Service |
2ea82d |
goto error; /* Process on second attempt */
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
if (ctx->pin != NULL) {
|
|
Packit Service |
2ea82d |
memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
|
|
Packit Service |
2ea82d |
memcpy(ctx->pin, tmp_pin, tmp_pin_len);
|
|
Packit Service |
2ea82d |
ctx->pin_length = tmp_pin_len;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
n = parse_slot_id_string(ctx, s_slot_key_id, &slot_nr,
|
|
Packit Service |
2ea82d |
key_id, &key_id_len, &key_label);
|
|
Packit Service |
2ea82d |
if (!n) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0,
|
|
Packit Service |
2ea82d |
"The key ID is not a valid PKCS#11 URI\n"
|
|
Packit Service |
2ea82d |
"The PKCS#11 URI format is defined by RFC7512\n"
|
|
Packit Service |
2ea82d |
"The legacy ENGINE_pkcs11 ID format is also "
|
|
Packit Service |
2ea82d |
"still accepted for now\n");
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_KEY, ENG_R_INVALID_ID);
|
|
Packit Service |
2ea82d |
goto error;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "Looking in slot %d for key: ",
|
|
Packit Service |
2ea82d |
slot_nr);
|
|
Packit Service |
2ea82d |
if (key_id_len != 0) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "id=");
|
|
Packit Service |
2ea82d |
dump_hex(ctx, 1, key_id, key_id_len);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (key_id_len != 0 && key_label != NULL)
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, " ");
|
|
Packit Service |
2ea82d |
if (key_label != NULL)
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "label=%s", key_label);
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "\n");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count,
|
|
Packit Service |
a0c135 |
sizeof(PKCS11_SLOT *));
|
|
Packit Service |
a0c135 |
if (matched_slots == NULL) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Could not allocate memory for matched slots\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
for (n = 0; n < ctx->slot_count; n++) {
|
|
Packit Service |
2ea82d |
slot = ctx->slot_list + n;
|
|
Packit Service |
2ea82d |
flags[0] = '\0';
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
if (!slot->token->initialized)
|
|
Packit Service |
2ea82d |
strcat(flags, "uninitialized, ");
|
|
Packit Service |
2ea82d |
else if (!slot->token->userPinSet)
|
|
Packit Service |
2ea82d |
strcat(flags, "no pin, ");
|
|
Packit Service |
2ea82d |
if (slot->token->loginRequired)
|
|
Packit Service |
2ea82d |
strcat(flags, "login, ");
|
|
Packit Service |
2ea82d |
if (slot->token->readOnly)
|
|
Packit Service |
2ea82d |
strcat(flags, "ro, ");
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
strcpy(flags, "no token");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if ((m = strlen(flags)) != 0) {
|
|
Packit Service |
2ea82d |
flags[m - 2] = '\0';
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slot_nr != -1 &&
|
|
Packit Service |
2ea82d |
slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
|
|
Packit Service |
2ea82d |
found_slot = slot;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
if (match_tok && slot->token &&
|
|
Packit Service |
2ea82d |
(match_tok->label == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->label, slot->token->label)) &&
|
|
Packit Service |
2ea82d |
(match_tok->manufacturer == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->manufacturer, slot->token->manufacturer)) &&
|
|
Packit Service |
2ea82d |
(match_tok->serialnr == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->serialnr, slot->token->serialnr)) &&
|
|
Packit Service |
2ea82d |
(match_tok->model == NULL ||
|
|
Packit Service |
2ea82d |
!strcmp(match_tok->model, slot->token->model))) {
|
|
Packit Service |
2ea82d |
found_slot = slot;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "[%lu] %-25.25s %-16s",
|
|
Packit Service |
2ea82d |
PKCS11_get_slotid_from_slot(slot),
|
|
Packit Service |
2ea82d |
slot->description, flags);
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, " (%s)",
|
|
Packit Service |
2ea82d |
slot->token->label[0] ?
|
|
Packit Service |
2ea82d |
slot->token->label : "no label");
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 1, "\n");
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token && !found_slot->token->initialized)
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Found uninitialized token\n");
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
/* Ignore slots without tokens or with uninitialized token */
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token && found_slot->token->initialized) {
|
|
Packit Service |
a0c135 |
matched_slots[matched_count] = found_slot;
|
|
Packit Service |
a0c135 |
matched_count++;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
found_slot = NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
if (matched_count == 0) {
|
|
Packit Service |
a0c135 |
if (match_tok) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Specified object not found\n");
|
|
Packit Service |
2ea82d |
goto error;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
/* If the legacy slot ID format was used */
|
|
Packit Service |
a0c135 |
if (slot_nr != -1) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
found_slot = PKCS11_find_token(ctx->pkcs11_ctx,
|
|
Packit Service |
a0c135 |
ctx->slot_list, ctx->slot_count);
|
|
Packit Service |
a0c135 |
/* Ignore if the the token is not initialized */
|
|
Packit Service |
a0c135 |
if (found_slot && found_slot->token &&
|
|
Packit Service |
a0c135 |
found_slot->token->initialized) {
|
|
Packit Service |
a0c135 |
matched_slots[matched_count] = found_slot;
|
|
Packit Service |
a0c135 |
matched_count++;
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "No tokens found\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
for (n = 0; n < matched_count; n++) {
|
|
Packit Service |
a0c135 |
slot = matched_slots[n];
|
|
Packit Service |
a0c135 |
tok = slot->token;
|
|
Packit Service |
a0c135 |
if (tok == NULL) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Found empty token\n");
|
|
Packit Service |
a0c135 |
break;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
/* Both private and public keys can have the CKA_PRIVATE attribute
|
|
Packit Service |
a0c135 |
* set and thus require login (even to retrieve attributes!) */
|
|
Packit Service |
a0c135 |
if (login) {
|
|
Packit Service |
a0c135 |
/* Try to login only if login is required */
|
|
Packit Service |
a0c135 |
if (tok->loginRequired) {
|
|
Packit Service |
a0c135 |
/* Try to login only if a single slot matched to avoiding trying
|
|
Packit Service |
a0c135 |
* the PIN against all matching slots */
|
|
Packit Service |
a0c135 |
if (matched_count == 1) {
|
|
Packit Service |
a0c135 |
if (!ctx_login(ctx, slot, tok, ui_method, callback_data)) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Multiple matching slots (%lu); will not try to"
|
|
Packit Service |
a0c135 |
" login\n", matched_count);
|
|
Packit Service |
a0c135 |
for (m = 0; m < matched_count; m++){
|
|
Packit Service |
a0c135 |
slot = matched_slots[m];
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "[%u] %s: %s\n", m + 1,
|
|
Packit Service |
a0c135 |
slot->description? slot->description:
|
|
Packit Service |
a0c135 |
"(no description)",
|
|
Packit Service |
a0c135 |
(slot->token && slot->token->label)?
|
|
Packit Service |
a0c135 |
slot->token->label: "no label");
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
goto error;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
a0c135 |
if (isPrivate) {
|
|
Packit Service |
a0c135 |
/* Make sure there is at least one private key on the token */
|
|
Packit Service |
a0c135 |
if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Unable to enumerate private keys\n");
|
|
Packit Service |
a0c135 |
continue;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
/* Make sure there is at least one public key on the token */
|
|
Packit Service |
a0c135 |
if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "Unable to enumerate public keys\n");
|
|
Packit Service |
a0c135 |
continue;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
if (key_count == 0) {
|
|
Packit Service |
a0c135 |
if (login) /* Only print the error on the second attempt */
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 0, "No %s keys found.\n",
|
|
Packit Service |
a0c135 |
(char *)(isPrivate ? "private" : "public"));
|
|
Packit Service |
a0c135 |
continue;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, "Found %u %s key%s:\n", key_count,
|
|
Packit Service |
a0c135 |
(char *)(isPrivate ? "private" : "public"),
|
|
Packit Service |
a0c135 |
(key_count == 1) ? "" : "s");
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
if (s_slot_key_id && *s_slot_key_id &&
|
|
Packit Service |
a0c135 |
(key_id_len != 0 || key_label != NULL)) {
|
|
Packit Service |
a0c135 |
for (m = 0; m < key_count; m++) {
|
|
Packit Service |
a0c135 |
PKCS11_KEY *k = keys + m;
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, " %2u %c%c id=", m + 1,
|
|
Packit Service |
a0c135 |
k->isPrivate ? 'P' : ' ',
|
|
Packit Service |
a0c135 |
k->needLogin ? 'L' : ' ');
|
|
Packit Service |
a0c135 |
dump_hex(ctx, 1, k->id, k->id_len);
|
|
Packit Service |
a0c135 |
ctx_log(ctx, 1, " label=%s\n", k->label);
|
|
Packit Service |
a0c135 |
if (key_label != NULL && strcmp(k->label, key_label) == 0)
|
|
Packit Service |
a0c135 |
selected_key = k;
|
|
Packit Service |
a0c135 |
if (key_id_len != 0 && k->id_len == key_id_len
|
|
Packit Service |
a0c135 |
&& memcmp(k->id, key_id, key_id_len) == 0)
|
|
Packit Service |
a0c135 |
selected_key = k;
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
} else {
|
|
Packit Service |
a0c135 |
selected_key = keys; /* Use the first key */
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
a0c135 |
if (selected_key) {
|
|
Packit Service |
a0c135 |
break;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (selected_key != NULL) {
|
|
Packit Service |
2ea82d |
pk = isPrivate ?
|
|
Packit Service |
2ea82d |
PKCS11_get_private_key(selected_key) :
|
|
Packit Service |
2ea82d |
PKCS11_get_public_key(selected_key);
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
if (login) /* Only print the error on the second attempt */
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "Key not found.\n");
|
|
Packit Service |
2ea82d |
pk = NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
a0c135 |
|
|
Packit Service |
2ea82d |
error:
|
|
Packit Service |
a0c135 |
/* Free the searched token data */
|
|
Packit Service |
a0c135 |
if (match_tok) {
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->model);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->manufacturer);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->serialnr);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok->label);
|
|
Packit Service |
a0c135 |
OPENSSL_free(match_tok);
|
|
Packit Service |
a0c135 |
}
|
|
Packit Service |
2ea82d |
if (key_label != NULL)
|
|
Packit Service |
2ea82d |
OPENSSL_free(key_label);
|
|
Packit Service |
a0c135 |
if (matched_slots != NULL)
|
|
Packit Service |
a0c135 |
free(matched_slots);
|
|
Packit Service |
2ea82d |
return pk;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
EVP_PKEY *ctx_load_pubkey(ENGINE_CTX *ctx, const char *s_key_id,
|
|
Packit Service |
2ea82d |
UI_METHOD *ui_method, void *callback_data)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
EVP_PKEY *pk = NULL;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
if (!ctx->force_login)
|
|
Packit Service |
2ea82d |
pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 0, 0);
|
|
Packit Service |
2ea82d |
if (pk == NULL) { /* Try again with login */
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 0, 1);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (pk == NULL) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "PKCS11_load_public_key returned NULL\n");
|
|
Packit Service |
2ea82d |
if (!ERR_peek_last_error())
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_PUBKEY, ENG_R_OBJECT_NOT_FOUND);
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return pk;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
EVP_PKEY *ctx_load_privkey(ENGINE_CTX *ctx, const char *s_key_id,
|
|
Packit Service |
2ea82d |
UI_METHOD *ui_method, void *callback_data)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
EVP_PKEY *pk = NULL;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
if (!ctx->force_login)
|
|
Packit Service |
2ea82d |
pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 1, 0);
|
|
Packit Service |
2ea82d |
if (pk == NULL) { /* Try again with login */
|
|
Packit Service |
2ea82d |
ERR_clear_error();
|
|
Packit Service |
2ea82d |
pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 1, 1);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (pk == NULL) {
|
|
Packit Service |
2ea82d |
ctx_log(ctx, 0, "PKCS11_get_private_key returned NULL\n");
|
|
Packit Service |
2ea82d |
if (!ERR_peek_last_error())
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_LOAD_PRIVKEY, ENG_R_OBJECT_NOT_FOUND);
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return pk;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
/* Engine ctrl request handling */
|
|
Packit Service |
2ea82d |
/******************************************************************************/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_module(ENGINE_CTX *ctx, const char *modulename)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx->module);
|
|
Packit Service |
2ea82d |
ctx->module = modulename ? OPENSSL_strdup(modulename) : NULL;
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/**
|
|
Packit Service |
2ea82d |
* Set the PIN used for login. A copy of the PIN shall be made.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* If the PIN cannot be assigned, the value 0 shall be returned
|
|
Packit Service |
2ea82d |
* and errno shall be set as follows:
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* EINVAL - a NULL PIN was supplied
|
|
Packit Service |
2ea82d |
* ENOMEM - insufficient memory to copy the PIN
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* @param pin the pin to use for login. Must not be NULL.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* @return 1 on success, 0 on failure.
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_pin(ENGINE_CTX *ctx, const char *pin)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
/* Pre-condition check */
|
|
Packit Service |
2ea82d |
if (pin == NULL) {
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_CTRL_SET_PIN, ERR_R_PASSED_NULL_PARAMETER);
|
|
Packit Service |
2ea82d |
errno = EINVAL;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Copy the PIN. If the string cannot be copied, NULL
|
|
Packit Service |
2ea82d |
* shall be returned and errno shall be set. */
|
|
Packit Service |
2ea82d |
ctx_destroy_pin(ctx);
|
|
Packit Service |
2ea82d |
ctx->pin = OPENSSL_strdup(pin);
|
|
Packit Service |
2ea82d |
if (ctx->pin == NULL) {
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_CTRL_SET_PIN, ERR_R_MALLOC_FAILURE);
|
|
Packit Service |
2ea82d |
errno = ENOMEM;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
ctx->pin_length = strlen(ctx->pin);
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_inc_verbose(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ctx->verbose++;
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_quiet(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ctx->verbose = -1;
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_init_args(ENGINE_CTX *ctx, const char *init_args_orig)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
OPENSSL_free(ctx->init_args);
|
|
Packit Service |
2ea82d |
ctx->init_args = init_args_orig ? OPENSSL_strdup(init_args_orig) : NULL;
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_user_interface(ENGINE_CTX *ctx, UI_METHOD *ui_method)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ctx->ui_method = ui_method;
|
|
Packit Service |
2ea82d |
if (ctx->pkcs11_ctx != NULL) /* libp11 is already initialized */
|
|
Packit Service |
2ea82d |
PKCS11_set_ui_method(ctx->pkcs11_ctx,
|
|
Packit Service |
2ea82d |
ctx->ui_method, ctx->callback_data);
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_set_callback_data(ENGINE_CTX *ctx, void *callback_data)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ctx->callback_data = callback_data;
|
|
Packit Service |
2ea82d |
if (ctx->pkcs11_ctx != NULL) /* libp11 is already initialized */
|
|
Packit Service |
2ea82d |
PKCS11_set_ui_method(ctx->pkcs11_ctx,
|
|
Packit Service |
2ea82d |
ctx->ui_method, ctx->callback_data);
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int ctx_ctrl_force_login(ENGINE_CTX *ctx)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
ctx->force_login = 1;
|
|
Packit Service |
2ea82d |
return 1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
int ctx_engine_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)())
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
(void)i; /* We don't currently take integer parameters */
|
|
Packit Service |
2ea82d |
(void)f; /* We don't currently take callback parameters */
|
|
Packit Service |
2ea82d |
/*int initialised = ((pkcs11_dso == NULL) ? 0 : 1); */
|
|
Packit Service |
2ea82d |
switch (cmd) {
|
|
Packit Service |
2ea82d |
case CMD_MODULE_PATH:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_module(ctx, (const char *)p);
|
|
Packit Service |
2ea82d |
case CMD_PIN:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_pin(ctx, (const char *)p);
|
|
Packit Service |
2ea82d |
case CMD_VERBOSE:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_inc_verbose(ctx);
|
|
Packit Service |
2ea82d |
case CMD_QUIET:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_quiet(ctx);
|
|
Packit Service |
2ea82d |
case CMD_LOAD_CERT_CTRL:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_load_cert(ctx, p);
|
|
Packit Service |
2ea82d |
case CMD_INIT_ARGS:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_init_args(ctx, (const char *)p);
|
|
Packit Service |
2ea82d |
case ENGINE_CTRL_SET_USER_INTERFACE:
|
|
Packit Service |
2ea82d |
case CMD_SET_USER_INTERFACE:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_user_interface(ctx, (UI_METHOD *)p);
|
|
Packit Service |
2ea82d |
case ENGINE_CTRL_SET_CALLBACK_DATA:
|
|
Packit Service |
2ea82d |
case CMD_SET_CALLBACK_DATA:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_set_callback_data(ctx, p);
|
|
Packit Service |
2ea82d |
case CMD_FORCE_LOGIN:
|
|
Packit Service |
2ea82d |
return ctx_ctrl_force_login(ctx);
|
|
Packit Service |
2ea82d |
default:
|
|
Packit Service |
2ea82d |
ENGerr(ENG_F_CTX_ENGINE_CTRL, ENG_R_UNKNOWN_COMMAND);
|
|
Packit Service |
2ea82d |
break;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* vim: set noexpandtab: */
|