Blame src/eng_front.c

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: */