|
Packit |
6b81fa |
/*
|
|
Packit |
6b81fa |
* Copyright 1999-2001 The OpenSSL Project Authors. All Rights Reserved.
|
|
Packit |
6b81fa |
* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
|
|
Packit |
6b81fa |
* project 2000.
|
|
Packit |
6b81fa |
* Portions Copyright (c) 2003 Kevin Stefanik (kstef@mtppi.org)
|
|
Packit |
6b81fa |
* Copied/modified by Kevin Stefanik (kstef@mtppi.org) for the OpenSC
|
|
Packit |
6b81fa |
* project 2003.
|
|
Packit |
6b81fa |
* Copyright (c) 2016-2018 MichaĆ Trojnara <Michal.Trojnara@stunnel.org>
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
Packit |
6b81fa |
* this file except in compliance with the License. You can obtain a copy
|
|
Packit |
6b81fa |
* in the file LICENSE in the source distribution or at
|
|
Packit |
6b81fa |
* https://www.openssl.org/source/license.html
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include "engine.h"
|
|
Packit |
6b81fa |
#include <stdio.h>
|
|
Packit |
6b81fa |
#include <string.h>
|
|
Packit |
6b81fa |
#include <openssl/opensslconf.h>
|
|
Packit |
6b81fa |
#include <openssl/opensslv.h>
|
|
Packit |
6b81fa |
#include <openssl/crypto.h>
|
|
Packit |
6b81fa |
#include <openssl/objects.h>
|
|
Packit |
6b81fa |
#include <openssl/engine.h>
|
|
Packit |
6b81fa |
#ifndef ENGINE_CMD_BASE
|
|
Packit |
6b81fa |
#error did not get engine.h
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#define PKCS11_ENGINE_ID "pkcs11"
|
|
Packit |
6b81fa |
#define PKCS11_ENGINE_NAME "pkcs11 engine"
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int pkcs11_idx = -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* The definitions for control commands specific to this engine */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* need to add function to pass in reader id? or user reader:key as key id string? */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static const ENGINE_CMD_DEFN engine_cmd_defns[] = {
|
|
Packit |
6b81fa |
{CMD_SO_PATH,
|
|
Packit |
6b81fa |
"SO_PATH",
|
|
Packit |
6b81fa |
"Specifies the path to the 'pkcs11' engine shared library",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_STRING},
|
|
Packit |
6b81fa |
{CMD_MODULE_PATH,
|
|
Packit |
6b81fa |
"MODULE_PATH",
|
|
Packit |
6b81fa |
"Specifies the path to the PKCS#11 module shared library",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_STRING},
|
|
Packit |
6b81fa |
{CMD_PIN,
|
|
Packit |
6b81fa |
"PIN",
|
|
Packit |
6b81fa |
"Specifies the pin code",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_STRING},
|
|
Packit |
6b81fa |
{CMD_VERBOSE,
|
|
Packit |
6b81fa |
"VERBOSE",
|
|
Packit |
6b81fa |
"Print additional details",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_NO_INPUT},
|
|
Packit |
6b81fa |
{CMD_QUIET,
|
|
Packit |
6b81fa |
"QUIET",
|
|
Packit |
6b81fa |
"Remove additional details",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_NO_INPUT},
|
|
Packit |
6b81fa |
{CMD_LOAD_CERT_CTRL,
|
|
Packit |
6b81fa |
"LOAD_CERT_CTRL",
|
|
Packit |
6b81fa |
"Get the certificate from card",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_INTERNAL},
|
|
Packit |
6b81fa |
{CMD_INIT_ARGS,
|
|
Packit |
6b81fa |
"INIT_ARGS",
|
|
Packit |
6b81fa |
"Specifies additional initialization arguments to the PKCS#11 module",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_STRING},
|
|
Packit |
6b81fa |
{CMD_SET_USER_INTERFACE,
|
|
Packit |
6b81fa |
"SET_USER_INTERFACE",
|
|
Packit |
6b81fa |
"Set the global user interface (internal)",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_INTERNAL},
|
|
Packit |
6b81fa |
{CMD_SET_CALLBACK_DATA,
|
|
Packit |
6b81fa |
"SET_CALLBACK_DATA",
|
|
Packit |
6b81fa |
"Set the global user interface extra data (internal)",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_INTERNAL},
|
|
Packit |
6b81fa |
{CMD_FORCE_LOGIN,
|
|
Packit |
6b81fa |
"FORCE_LOGIN",
|
|
Packit |
6b81fa |
"Force login to the PKCS#11 module",
|
|
Packit |
6b81fa |
ENGINE_CMD_FLAG_NO_INPUT},
|
|
Packit |
6b81fa |
{0, NULL, NULL, 0}
|
|
Packit |
6b81fa |
};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static ENGINE_CTX *get_ctx(ENGINE *engine)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (pkcs11_idx < 0) {
|
|
Packit |
6b81fa |
pkcs11_idx = ENGINE_get_ex_new_index(0, "pkcs11", NULL, NULL, 0);
|
|
Packit |
6b81fa |
if (pkcs11_idx < 0)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
ctx = NULL;
|
|
Packit |
6b81fa |
} else {
|
|
Packit |
6b81fa |
ctx = ENGINE_get_ex_data(engine, pkcs11_idx);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (ctx == NULL) {
|
|
Packit |
6b81fa |
ctx = ctx_new();
|
|
Packit |
6b81fa |
ENGINE_set_ex_data(engine, pkcs11_idx, ctx);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
return ctx;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Destroy the context allocated with ctx_new() */
|
|
Packit |
6b81fa |
static int engine_destroy(ENGINE *engine)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
int rv = 1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* ENGINE_remove() invokes our engine_destroy() function with
|
|
Packit |
6b81fa |
* CRYPTO_LOCK_ENGINE / global_engine_lock acquired.
|
|
Packit |
6b81fa |
* Any attempt to re-acquire the lock either by directly
|
|
Packit |
6b81fa |
* invoking OpenSSL functions, or indirectly via PKCS#11 modules
|
|
Packit |
6b81fa |
* that use OpenSSL engines, causes a deadlock. */
|
|
Packit |
6b81fa |
/* Our workaround is to skip ctx_finish() entirely, as a memory
|
|
Packit |
6b81fa |
* leak is better than a deadlock. */
|
|
Packit |
6b81fa |
#if 0
|
|
Packit |
6b81fa |
rv &= ctx_finish(ctx);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rv &= ctx_destroy(ctx);
|
|
Packit |
6b81fa |
ENGINE_set_ex_data(engine, pkcs11_idx, NULL);
|
|
Packit |
6b81fa |
ERR_unload_ENG_strings();
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int engine_init(ENGINE *engine)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
return ctx_init(ctx);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Finish engine operations initialized with ctx_init() */
|
|
Packit |
6b81fa |
static int engine_finish(ENGINE *engine)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
int rv = 1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* ENGINE_cleanup() used by OpenSSL versions before 1.1.0 invokes
|
|
Packit |
6b81fa |
* our engine_finish() function with CRYPTO_LOCK_ENGINE acquired.
|
|
Packit |
6b81fa |
* Any attempt to re-acquire CRYPTO_LOCK_ENGINE either by directly
|
|
Packit |
6b81fa |
* invoking OpenSSL functions, or indirectly via PKCS#11 modules
|
|
Packit |
6b81fa |
* that use OpenSSL engines, causes a deadlock. */
|
|
Packit |
6b81fa |
/* Our workaround is to skip ctx_finish() for the affected OpenSSL
|
|
Packit |
6b81fa |
* versions, as a memory leak is better than a deadlock. */
|
|
Packit |
6b81fa |
/* We cannot simply temporarily release CRYPTO_LOCK_ENGINE here, as
|
|
Packit |
6b81fa |
* engine_finish() is also executed from ENGINE_finish() without
|
|
Packit |
6b81fa |
* acquired CRYPTO_LOCK_ENGINE, and there is no way with to check
|
|
Packit |
6b81fa |
* whether a lock is already acquired with OpenSSL < 1.1.0 API. */
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
rv &= ctx_finish(ctx);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static EVP_PKEY *load_pubkey(ENGINE *engine, const char *s_key_id,
|
|
Packit |
6b81fa |
UI_METHOD *ui_method, void *callback_data)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
return ctx_load_pubkey(ctx, s_key_id, ui_method, callback_data);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static EVP_PKEY *load_privkey(ENGINE *engine, const char *s_key_id,
|
|
Packit |
6b81fa |
UI_METHOD *ui_method, void *callback_data)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
EVP_PKEY *pkey;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
pkey = ctx_load_privkey(ctx, s_key_id, ui_method, callback_data);
|
|
Packit |
6b81fa |
#ifdef EVP_F_EVP_PKEY_SET1_ENGINE
|
|
Packit |
6b81fa |
/* EVP_PKEY_set1_engine() is required for OpenSSL 1.1.x,
|
|
Packit |
6b81fa |
* but otherwise setting pkey->engine breaks OpenSSL 1.0.2 */
|
|
Packit |
6b81fa |
if (pkey && !EVP_PKEY_set1_engine(pkey, engine)) {
|
|
Packit |
6b81fa |
EVP_PKEY_free(pkey);
|
|
Packit |
6b81fa |
pkey = NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
#endif /* EVP_F_EVP_PKEY_SET1_ENGINE */
|
|
Packit |
6b81fa |
return pkey;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int engine_ctrl(ENGINE *engine, int cmd, long i, void *p, void (*f) ())
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ENGINE_CTX *ctx;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = get_ctx(engine);
|
|
Packit |
6b81fa |
if (ctx == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
return ctx_engine_ctrl(ctx, cmd, i, p, f);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* This internal function is used by ENGINE_pkcs11() and possibly by the
|
|
Packit |
6b81fa |
* "dynamic" ENGINE support too */
|
|
Packit |
6b81fa |
static int bind_helper(ENGINE *e)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
if (!ENGINE_set_id(e, PKCS11_ENGINE_ID) ||
|
|
Packit |
6b81fa |
!ENGINE_set_destroy_function(e, engine_destroy) ||
|
|
Packit |
6b81fa |
!ENGINE_set_init_function(e, engine_init) ||
|
|
Packit |
6b81fa |
!ENGINE_set_finish_function(e, engine_finish) ||
|
|
Packit |
6b81fa |
!ENGINE_set_ctrl_function(e, engine_ctrl) ||
|
|
Packit |
6b81fa |
!ENGINE_set_cmd_defns(e, engine_cmd_defns) ||
|
|
Packit |
6b81fa |
!ENGINE_set_name(e, PKCS11_ENGINE_NAME) ||
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_RSA
|
|
Packit |
6b81fa |
!ENGINE_set_RSA(e, PKCS11_get_rsa_method()) ||
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100002L
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_EC
|
|
Packit |
6b81fa |
/* PKCS11_get_ec_key_method combines ECDSA and ECDH */
|
|
Packit |
6b81fa |
!ENGINE_set_EC(e, PKCS11_get_ec_key_method()) ||
|
|
Packit |
6b81fa |
#endif /* OPENSSL_NO_EC */
|
|
Packit |
6b81fa |
#else /* OPENSSL_VERSION_NUMBER */
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_ECDSA
|
|
Packit |
6b81fa |
!ENGINE_set_ECDSA(e, PKCS11_get_ecdsa_method()) ||
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_ECDH
|
|
Packit |
6b81fa |
!ENGINE_set_ECDH(e, PKCS11_get_ecdh_method()) ||
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#endif /* OPENSSL_VERSION_NUMBER */
|
|
Packit |
6b81fa |
!ENGINE_set_pkey_meths(e, PKCS11_pkey_meths) ||
|
|
Packit |
6b81fa |
!ENGINE_set_load_pubkey_function(e, load_pubkey) ||
|
|
Packit |
6b81fa |
!ENGINE_set_load_privkey_function(e, load_privkey)) {
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
} else {
|
|
Packit |
6b81fa |
ERR_load_ENG_strings();
|
|
Packit |
6b81fa |
return 1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int bind_fn(ENGINE *e, const char *id)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
if (id && (strcmp(id, PKCS11_ENGINE_ID) != 0)) {
|
|
Packit |
6b81fa |
fprintf(stderr, "bad engine id\n");
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (!bind_helper(e)) {
|
|
Packit |
6b81fa |
fprintf(stderr, "bind failed\n");
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
return 1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
IMPLEMENT_DYNAMIC_CHECK_FN()
|
|
Packit |
6b81fa |
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* vim: set noexpandtab: */
|