[pkg-opensc-commit] [libp11] 23/86: Initial merge of engine_pkcs11

Eric Dorland eric at moszumanska.debian.org
Sun Jul 24 21:40:18 UTC 2016


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository libp11.

commit 41ceb71b3d102ff84027261071a030f26d3109b0
Author: Michał Trojnara <Michal.Trojnara at stunnel.org>
Date:   Wed Jan 27 22:31:15 2016 +0100

    Initial merge of engine_pkcs11
    
    Windows build and tests are not merged yet.
---
 configure.ac                            |   52 +-
 src/Makefile.am                         |   21 +-
 src/Makefile.mak                        |   12 +-
 src/eng_back.c                          | 1097 +++++++++++++++++++++++++++++++
 src/eng_front.c                         |  209 ++++++
 src/engine.h                            |   64 ++
 src/{versioninfo.rc => libp11.rc}       |    0
 src/{versioninfo.rc.in => libp11.rc.in} |    0
 src/pkcs11.exports                      |    2 +
 src/{versioninfo.rc => pkcs11.rc}       |    8 +-
 src/{versioninfo.rc.in => pkcs11.rc.in} |    8 +-
 11 files changed, 1454 insertions(+), 19 deletions(-)

diff --git a/configure.ac b/configure.ac
index 62fb787..a31c139 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,6 +97,41 @@ AC_ARG_WITH(
 	[apidocdir="\$(htmldir)/api"]
 )
 
+AC_ARG_WITH(
+	[enginesdir],
+	[AS_HELP_STRING([--with-enginesdir], [OpenSSL engines directory])],
+	[enginesdir="${withval}"],
+	[
+		libcryptodir="`$PKG_CONFIG --variable=libdir --silence-errors libcrypto || \
+			$PKG_CONFIG --variable=libdir openssl`"
+		case "`$PKG_CONFIG --modversion --silence-errors libcrypto || \
+			$PKG_CONFIG --modversion openssl`" in
+		1.1.*) # Predicted engines directory prefix for OpenSSL 1.1.x
+			debian_ssl_prefix="openssl-1.1.0";;
+		1.0.*) # Engines directory prefix for OpenSSL 1.0.x
+			debian_ssl_prefix="openssl-1.0.0";;
+		*) # Engines directory prefix for OpenSSL 0.9.x
+			debian_ssl_prefix="ssl";;
+		esac
+		if test -d "$libcryptodir/$debian_ssl_prefix/engines"; then
+			# Debian-based OpenSSL package (for example Ubuntu)
+			enginesdir="$libcryptodir/$debian_ssl_prefix/engines"
+		else # Default OpenSSL engines directory
+			enginesdir="$libcryptodir/engines"
+		fi
+		if test "${prefix}" != "NONE" -o "${exec_prefix}" != "NONE"; then
+			# Override the autodetected value with the default
+			enginesdir="${libdir}"
+		fi
+	]
+)
+
+AC_ARG_WITH(
+	[pkcs11-module],
+	[AS_HELP_STRING([--with-pkcs11-module], [default PKCS11 module])],
+	[pkcs11_module="${withval}"],
+	[pkcs11_module="`$PKG_CONFIG --variable=proxy_module --silence-errors p11-kit-1`"])
+
 dnl Checks for programs.
 AC_PROG_CPP
 AC_PROG_INSTALL
@@ -149,10 +184,18 @@ PKG_CHECK_MODULES(
 	[AC_MSG_ERROR([libcrypto >= 0.9.8 is required])]
 )
 
+if test -n "${pkcs11_module}"; then
+	AC_DEFINE_UNQUOTED(
+		[DEFAULT_PKCS11_MODULE],
+		"${pkcs11_module}",
+		[Default PKCS#11 module.])
+fi
+
 pkgconfigdir="\$(libdir)/pkgconfig"
 
 AC_SUBST([pkgconfigdir])
 AC_SUBST([apidocdir])
+AC_SUBST([enginesdir])
 AC_SUBST([LIBP11_VERSION_MAJOR])
 AC_SUBST([LIBP11_VERSION_MINOR])
 AC_SUBST([LIBP11_VERSION_FIX])
@@ -178,7 +221,8 @@ AC_CONFIG_FILES([
 	Makefile
 	src/Makefile
 	src/libp11.pc
-	src/versioninfo.rc
+	src/libp11.rc
+	src/pkcs11.rc
 	doc/Makefile
 	doc/doxygen.conf
 	examples/Makefile
@@ -191,8 +235,10 @@ cat <<EOF
 libp11 has been configured with the following options:
 
 Version:                 ${PACKAGE_VERSION}
-Libraries:               $(eval eval eval echo "${libdir}")
+libp11 directory:        $(eval eval eval echo "${libdir}")
+Engine directory:        ${enginesdir}
 API doc support:         ${enable_api_doc}
+Default PKCS11 module:   ${pkcs11_module}
 
 Host:                    ${host}
 Compiler:                ${CC}
@@ -201,6 +247,8 @@ Compiler flags:          ${CFLAGS}
 Linker flags:            ${LDFLAGS}
 Libraries:               ${LIBS}
 
+LIBP11_CFLAGS:           ${LIBP11_CFLAGS}
+LIBP11_LIBS:             ${LIBP11_LIBS}
 OPENSSL_CFLAGS:          ${OPENSSL_CFLAGS}
 OPENSSL_LIBS:            ${OPENSSL_LIBS}
 
diff --git a/src/Makefile.am b/src/Makefile.am
index fa8e1be..006860f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,20 +1,21 @@
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
 	$(srcdir)/config.h.in $(srcdir)/config.h.in~
 CLEANFILES = libp11.pc
-EXTRA_DIST = Makefile.mak versioninfo.rc.in
+EXTRA_DIST = Makefile.mak libp11.rc.in pkcs11.rc.in
 
 noinst_HEADERS= libp11-int.h pkcs11.h atfork.h
 include_HEADERS= libp11.h
 lib_LTLIBRARIES = libp11.la
+engines_LTLIBRARIES = libpkcs11.la
 pkgconfig_DATA = libp11.pc
 
 libp11_la_SOURCES = libpkcs11.c p11_attr.c p11_cert.c p11_err.c p11_key.c \
 	p11_load.c p11_misc.c p11_ops.c p11_rsa.c p11_ec.c p11_slot.c \
 	libp11.exports atfork.c
 if WIN32
-libp11_la_SOURCES += versioninfo.rc
+libp11_la_SOURCES += libp11.rc
 else
-dist_noinst_DATA = versioninfo.rc
+dist_noinst_DATA = libp11.rc
 endif
 libp11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS)
 libp11_la_LIBADD = $(OPENSSL_LIBS)
@@ -23,6 +24,20 @@ libp11_la_LDFLAGS = $(AM_LDFLAGS) \
 	-export-symbols "$(srcdir)/libp11.exports" \
 	-no-undefined
 
+libpkcs11_la_SOURCES = eng_front.c eng_back.c engine.h pkcs11.exports
+if WIN32
+libpkcs11_la_SOURCES += pkcs11.rc
+else
+dist_noinst_DATA += pkcs11.rc
+endif
+libpkcs11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_EXTRA_CFLAGS) $(OPENSSL_CFLAGS) \
+	$(LIBP11_CFLAGS)
+libpkcs11_la_LIBADD = $(OPENSSL_LIBS) $(LIBP11_LIBS)
+libpkcs11_la_LDFLAGS = $(AM_LDFLAGS) \
+	-module -shared -avoid-version \
+	-export-symbols "$(srcdir)/pkcs11.exports" \
+	-no-undefined
+
 if WIN32
 # def file required for MS users to build library
 mylibdir=$(libdir)
diff --git a/src/Makefile.mak b/src/Makefile.mak
index 81657d6..1d6bb8f 100644
--- a/src/Makefile.mak
+++ b/src/Makefile.mak
@@ -8,20 +8,20 @@ OBJECTS = libpkcs11.obj p11_attr.obj p11_cert.obj \
 	p11_err.obj p11_key.obj p11_load.obj p11_misc.obj p11_rsa.obj \
 	p11_ec.obj p11_slot.obj p11_ops.obj
 
-all: $(TARGET) versioninfo.res
+all: $(TARGET) libp11.res
 
-RSC_PROJ=/l 0x809 /r /fo"versioninfo.res"
+RSC_PROJ=/l 0x809 /r /fo"libp11.res"
 
-versioninfo.res: versioninfo.rc
-	rc $(RSC_PROJ) versioninfo.rc
+libp11.res: libp11.rc
+	rc $(RSC_PROJ) libp11.rc
  
 .c.obj::
 	cl $(CLFLAGS) /c $<
 
-$(TARGET): $(OBJECTS) versioninfo.res
+$(TARGET): $(OBJECTS) libp11.res
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type $*.exports >> $*.def
 	link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET) \
-		$(OBJECTS) $(LIBS) versioninfo.res
+		$(OBJECTS) $(LIBS) libp11.res
 	if EXIST $*.dll.manifest mt -manifest $*.dll.manifest -outputresource:$*.dll;2
diff --git a/src/eng_back.c b/src/eng_back.c
new file mode 100644
index 0000000..bfe8dc4
--- /dev/null
+++ b/src/eng_back.c
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (c) 2002 Juha Yrjölä.  All rights reserved.
+ * Copyright (c) 2001 Markus Friedl.
+ * Copyright (c) 2002 Olaf Kirch
+ * Copyright (c) 2003 Kevin Stefanik
+ *
+ * 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 "engine.h"
+#include "libp11.h"
+#include <stdio.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/objects.h>
+#include <openssl/engine.h>
+
+#ifdef _WIN32
+#define strncasecmp strnicmp
+#endif
+
+/** The maximum length of an internally-allocated PIN */
+#define MAX_PIN_LENGTH   32
+
+static PKCS11_CTX *ctx;
+
+/**
+ * The PIN used for login. Cache for the get_pin function.
+ * The memory for this PIN is always owned internally,
+ * and may be freed as necessary. Before freeing, the PIN
+ * must be whitened, to prevent security holes.
+ */
+static char *pin = NULL;
+static int pin_length = 0;
+
+static int verbose = 0;
+
+static char *module = NULL;
+
+static char *init_args = NULL;
+
+int set_module(const char *modulename)
+{
+	free (module);
+	module = modulename ? strdup(modulename) : NULL;
+	return 1;
+}
+
+/* Free PIN storage in secure way. */
+static void zero_pin(void)
+{
+	if (pin != NULL) {
+		OPENSSL_cleanse(pin, pin_length);
+		free(pin);
+		pin = NULL;
+		pin_length = 0;
+	}
+}
+
+/**
+ * Set the PIN used for login. A copy of the PIN shall be made.
+ *
+ * If the PIN cannot be assigned, the value 0 shall be returned
+ * and errno shall be set as follows:
+ *
+ *   EINVAL - a NULL PIN was supplied
+ *   ENOMEM - insufficient memory to copy the PIN
+ *
+ * @param _pin the pin to use for login. Must not be NULL.
+ *
+ * @return 1 on success, 0 on failure.
+ */
+int set_pin(const char *_pin)
+{
+	/* Pre-condition check */
+	if (_pin == NULL) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Copy the PIN. If the string cannot be copied, NULL
+	 * shall be returned and errno shall be set. */
+	zero_pin();
+	pin = strdup(_pin);
+	if (pin != NULL)
+		pin_length = strlen(pin);
+
+	return (pin != NULL);
+}
+
+int inc_verbose(void)
+{
+	verbose++;
+	return 1;
+}
+
+/* Get the PIN via asking user interface. The supplied call-back data are
+ * passed to the user interface implemented by an application. Only the
+ * application knows how to interpret the call-back data.
+ * A (strdup'ed) copy of the PIN code will be stored in the pin variable. */
+static int get_pin(UI_METHOD * ui_method, void *callback_data)
+{
+	UI *ui;
+
+	/* call ui to ask for a pin */
+	ui = UI_new();
+	if (ui == NULL) {
+		fprintf(stderr, "UI_new failed\n");
+		return 0;
+	}
+	if (ui_method != NULL)
+		UI_set_method(ui, ui_method);
+	if (callback_data != NULL)
+		UI_add_user_data(ui, callback_data);
+
+	zero_pin();
+	pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
+	if (pin == NULL)
+		return 0;
+	pin_length = MAX_PIN_LENGTH;
+	if (!UI_add_input_string(ui, "PKCS#11 token PIN: ",
+			UI_INPUT_FLAG_DEFAULT_PWD, pin, 1, MAX_PIN_LENGTH)) {
+		fprintf(stderr, "UI_add_input_string failed\n");
+		UI_free(ui);
+		return 0;
+	}
+	if (UI_process(ui)) {
+		fprintf(stderr, "UI_process failed\n");
+		UI_free(ui);
+		return 0;
+	}
+	UI_free(ui);
+	return 1;
+}
+
+int set_init_args(const char *init_args_orig)
+{
+	free(init_args);
+	init_args = init_args_orig ? strdup(init_args_orig) : NULL;
+	return 1;
+}
+
+int pkcs11_finish(ENGINE * engine)
+{
+	/*
+	 * TODO: Retrieve the libp11 context with:
+	 *   ctx = ENGINE_get_ex_data(e, pkcs11_idx);
+	 * , free it, and set to NULL with:
+	 *   ENGINE_set_ex_data(e, pkcs11_idx, NULL);
+	 * instead of using a global context
+	 */
+	(void)engine;
+
+	if (ctx) {
+		PKCS11_CTX_unload(ctx);
+		PKCS11_CTX_free(ctx);
+		ctx = NULL;
+	}
+	zero_pin();
+	return 1;
+}
+
+int pkcs11_init(ENGINE * engine)
+{
+	char *mod = module;
+
+	/*
+	 * TODO: Save the libp11 context with:
+	 *   ENGINE_set_ex_data(e, pkcs11_idx, ctx);
+	 * instead of using a global context
+	 */
+	(void)engine;
+
+#ifdef DEFAULT_PKCS11_MODULE
+	if (mod == NULL)
+		mod = DEFAULT_PKCS11_MODULE;
+#endif
+	if (verbose) {
+		fprintf(stderr, "Initializing engine\n");
+	}
+	ctx = PKCS11_CTX_new();
+        PKCS11_CTX_init_args(ctx, init_args);
+	if (PKCS11_CTX_load(ctx, mod) < 0) {
+		fprintf(stderr, "Unable to load module %s\n", mod);
+		return 0;
+	}
+	return 1;
+}
+
+static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen)
+{
+	size_t left, count = 0;
+
+	if (in == NULL || *in == '\0') {
+		*outlen = 0;
+		return 1;
+	}
+
+	left = *outlen;
+
+	while (*in != '\0') {
+		int byte = 0, nybbles = 2;
+
+		while (nybbles-- && *in && *in != ':') {
+			char c;
+			byte <<= 4;
+			c = *in++;
+			if ('0' <= c && c <= '9')
+				c -= '0';
+			else if ('a' <= c && c <= 'f')
+				c = c - 'a' + 10;
+			else if ('A' <= c && c <= 'F')
+				c = c - 'A' + 10;
+			else {
+				fprintf(stderr,
+					"hex_to_bin(): invalid char '%c' in hex string\n",
+					c);
+				*outlen = 0;
+				return 0;
+			}
+			byte |= c;
+		}
+		if (*in == ':')
+			in++;
+		if (left <= 0) {
+			fprintf(stderr, "hex_to_bin(): hex string too long\n");
+			*outlen = 0;
+			return 0;
+		}
+		out[count++] = (unsigned char)byte;
+		left--;
+	}
+
+	*outlen = count;
+	return 1;
+}
+
+/* parse string containing slot and id information */
+static int parse_slot_id_string(const char *slot_id, int *slot,
+				unsigned char *id, size_t * id_len,
+				char **label)
+{
+	int n, i;
+
+	if (slot_id == NULL)
+		return 0;
+
+	/* support for several formats */
+#define HEXDIGITS "01234567890ABCDEFabcdef"
+#define DIGITS "0123456789"
+
+	/* first: pure hex number (id, slot is undefined) */
+	if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) {
+		/* ah, easiest case: only hex. */
+		if ((strlen(slot_id) + 1) / 2 > *id_len) {
+			fprintf(stderr, "ID string too long!\n");
+			return 0;
+		}
+		*slot = -1;
+		return hex_to_bin(slot_id, id, id_len);
+	}
+
+	/* second: slot:id. slot is an digital int. */
+	if (sscanf(slot_id, "%d", &n) == 1) {
+		i = strspn(slot_id, DIGITS);
+
+		if (slot_id[i] != ':') {
+			fprintf(stderr, "Could not parse string!\n");
+			return 0;
+		}
+		i++;
+		if (slot_id[i] == 0) {
+			*slot = n;
+			*id_len = 0;
+			return 1;
+		}
+		if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) {
+			fprintf(stderr, "Could not parse string!\n");
+			return 0;
+		}
+		/* ah, rest is hex */
+		if ((strlen(slot_id) - i + 1) / 2 > *id_len) {
+			fprintf(stderr, "ID string too long!\n");
+			return 0;
+		}
+		*slot = n;
+		return hex_to_bin(slot_id + i, id, id_len);
+	}
+
+	/* third: id_<id>, slot is undefined */
+	if (strncmp(slot_id, "id_", 3) == 0) {
+		if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) {
+			fprintf(stderr, "Could not parse string!\n");
+			return 0;
+		}
+		/* ah, rest is hex */
+		if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) {
+			fprintf(stderr, "ID string too long!\n");
+			return 0;
+		}
+		*slot = -1;
+		return hex_to_bin(slot_id + 3, id, id_len);
+	}
+
+	/* label_<label>, slot is undefined */
+	if (strncmp(slot_id, "label_", 6) == 0) {
+		*slot = -1;
+		*label = strdup(slot_id + 6);
+		return *label != NULL;
+	}
+
+	/* last try: it has to be slot_<slot> and then "-id_<cert>" */
+
+	if (strncmp(slot_id, "slot_", 5) != 0) {
+		fprintf(stderr, "Format not recognized!\n");
+		return 0;
+	}
+
+	/* slot is an digital int. */
+	if (sscanf(slot_id + 5, "%d", &n) != 1) {
+		fprintf(stderr, "Could not decode slot number!\n");
+		return 0;
+	}
+
+	i = strspn(slot_id + 5, DIGITS);
+
+	if (slot_id[i + 5] == 0) {
+		*slot = n;
+		*id_len = 0;
+		return 1;
+	}
+
+	if (slot_id[i + 5] != '-') {
+		fprintf(stderr, "Could not parse string!\n");
+		return 0;
+	}
+
+	i = 5 + i + 1;
+
+	/* now followed by "id_" */
+	if (strncmp(slot_id + i, "id_", 3) == 0) {
+		if (strspn(slot_id + i + 3, HEXDIGITS) + 3 + i != strlen(slot_id)) {
+			fprintf(stderr, "Could not parse string!\n");
+			return 0;
+		}
+		/* ah, rest is hex */
+		if ((strlen(slot_id) - i - 3 + 1) / 2 > *id_len) {
+			fprintf(stderr, "ID string too long!\n");
+			return 0;
+		}
+		*slot = n;
+		return hex_to_bin(slot_id + i + 3, id, id_len);
+	}
+
+	/* ... or "label_" */
+	if (strncmp(slot_id + i, "label_", 6) == 0) {
+		*slot = n;
+		return (*label = strdup(slot_id + i + 6)) != NULL;
+	}
+
+	fprintf(stderr, "Could not parse string!\n");
+	return 0;
+}
+
+static int parse_uri_attr(const char *attr, int attrlen, unsigned char **field,
+		size_t *field_len)
+{
+	size_t max, outlen = 0;
+	unsigned char *out;
+	int ret = 1;
+
+	if (field_len) {
+		out = *field;
+		max = *field_len;
+	} else {
+		out = malloc(attrlen + 1);
+		if (out == NULL)
+			return 0;
+		max = attrlen + 1;
+	}
+
+	while (ret && attrlen && outlen < max) {
+		if (*attr == '%') {
+			if (attrlen < 3) {
+				ret = 0;
+			} else {
+				char tmp[3];
+				size_t l = 1;
+
+				tmp[0] = attr[1];
+				tmp[1] = attr[2];
+				tmp[2] = 0;
+				ret = hex_to_bin(tmp, &out[outlen++], &l);
+				attrlen -= 3;
+				attr += 3;
+			}
+
+		} else {
+			out[outlen++] = *(attr++);
+			attrlen--;
+		}
+	}
+	if (attrlen && outlen == max)
+		ret = 0;
+
+	if (ret) {
+		if (field_len) {
+			*field_len = outlen;
+		} else {
+			out[outlen] = 0;
+			*field = out;
+		}
+	} else {
+		if (field_len == NULL)
+			free(out);
+	}
+
+	return ret;
+}
+
+static int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok,
+		unsigned char *id, size_t *id_len, char *pin, size_t *pin_len,
+		char **label)
+{
+	PKCS11_TOKEN *tok;
+	char *newlabel = NULL;
+	const char *end, *p;
+	int rv = 1, pin_set = 0;
+
+	tok = calloc(1, sizeof(*tok));
+	if (tok == NULL) {
+		fprintf(stderr, "Could not allocate memory for token info\n");
+		return 0;
+	}
+
+	/* We are only ever invoked if the string starts with 'pkcs11:' */
+	end = uri + 6;
+	while (rv && end[0] && end[1]) {
+		p = end + 1;
+		end = strchr(p, ';');
+		if (end == NULL)
+			end = p + strlen(p);
+
+		if (!strncmp(p, "model=", 6)) {
+			p += 6;
+			rv = parse_uri_attr(p, end - p, (void *)&tok->model, NULL);
+		} else if (!strncmp(p, "manufacturer=", 13)) {
+			p += 13;
+			rv = parse_uri_attr(p, end - p, (void *)&tok->manufacturer, NULL);
+		} else if (!strncmp(p, "token=", 6)) {
+			p += 6;
+			rv = parse_uri_attr(p, end - p, (void *)&tok->label, NULL);
+		} else if (!strncmp(p, "serial=", 7)) {
+			p += 7;
+			rv = parse_uri_attr(p, end - p, (void *)&tok->serialnr, NULL);
+		} else if (!strncmp(p, "object=", 7)) {
+			p += 7;
+			rv = parse_uri_attr(p, end - p, (void *)&newlabel, NULL);
+		} else if (!strncmp(p, "id=", 3)) {
+			p += 3;
+			rv = parse_uri_attr(p, end - p, (void *)&id, id_len);
+		} else if (!strncmp(p, "pin-value=", 10)) {
+			p += 10;
+			rv = parse_uri_attr(p, end - p, (void *)&pin, pin_len);
+			pin_set = 1;
+		} else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) {
+			p = strchr(p, '=') + 1;
+
+			if ((end - p == 4 && !strncmp(p, "cert", 4)) ||
+					(end - p == 6 && !strncmp(p, "public", 6)) ||
+					(end - p == 7 && !strncmp(p, "private", 7))) {
+				/* Actually, just ignore it */
+			} else {
+				fprintf(stderr, "Unknown object type\n");
+				rv = 0;
+			}
+		} else {
+			rv = 0;
+		}
+	}
+
+	if (!pin_set)
+		*pin_len = 0;
+
+	if (rv) {
+		*label = newlabel;
+		*p_tok = tok;
+	} else {
+		free(tok);
+		tok = NULL;
+		free(newlabel);
+	}
+
+	return rv;
+}
+
+#define MAX_VALUE_LEN	200
+
+/* prototype for OpenSSL ENGINE_load_cert */
+/* used by load_cert_ctrl via ENGINE_ctrl for now */
+
+static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
+{
+	PKCS11_SLOT *slot_list, *slot;
+	PKCS11_SLOT *found_slot = NULL;
+	PKCS11_TOKEN *tok, *match_tok = NULL;
+	PKCS11_CERT *certs, *selected_cert = NULL;
+	X509 *x509;
+	unsigned int slot_count, cert_count, n, m;
+	unsigned char cert_id[MAX_VALUE_LEN / 2];
+	size_t cert_id_len = sizeof(cert_id);
+	char *cert_label = NULL;
+	char tmp_pin[MAX_PIN_LENGTH];
+	size_t tmp_pin_len = sizeof(tmp_pin);
+	int slot_nr = -1;
+	char flags[64];
+
+	/*
+	 * TODO: Retrieve the libp11 context with:
+	 *   ctx = ENGINE_get_ex_data(e, pkcs11_idx);
+	 * instead of using a global context
+	 */
+	(void)engine;
+
+	if (s_slot_cert_id && *s_slot_cert_id) {
+		if (!strncmp(s_slot_cert_id, "pkcs11:", 7)) {
+			n = parse_pkcs11_uri(s_slot_cert_id, &match_tok,
+				cert_id, &cert_id_len,
+				tmp_pin, &tmp_pin_len, &cert_label);
+			if (n && tmp_pin_len > 0 && tmp_pin[0] != 0) {
+				zero_pin();
+				pin = calloc(MAX_PIN_LENGTH, sizeof(char));
+				if (pin != NULL) {
+					memcpy(pin, tmp_pin, tmp_pin_len);
+					pin_length = tmp_pin_len;
+				}
+			}
+
+			if (!n) {
+				fprintf(stderr,
+					"The certificate ID is not a valid PKCS#11 URI\n"
+					"The PKCS#11 URI format is defined by RFC7512\n");
+				return NULL;
+			}
+		} else {
+			n = parse_slot_id_string(s_slot_cert_id, &slot_nr,
+				cert_id, &cert_id_len, &cert_label);
+
+			if (!n) {
+				fprintf(stderr,
+					"The certificate ID is not a valid PKCS#11 URI\n"
+					"The PKCS#11 URI format is defined by RFC7512\n"
+					"The legacy ENGINE_pkcs11 ID format is also "
+					"still accepted for now\n");
+				return NULL;
+			}
+		}
+		if (verbose) {
+			fprintf(stderr, "Looking in slot %d for certificate: ",
+				slot_nr);
+			if (cert_label == NULL) {
+				for (n = 0; n < cert_id_len; n++)
+					fprintf(stderr, "%02x", cert_id[n]);
+				fprintf(stderr, "\n");
+			} else
+				fprintf(stderr, "label: %s\n", cert_label);
+		}
+	}
+
+	if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
+		fprintf(stderr, "Failed to enumerate slots\n");
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found %u slot%s\n", slot_count,
+			(slot_count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < slot_count; n++) {
+		slot = slot_list + n;
+		flags[0] = '\0';
+		if (slot->token) {
+			if (!slot->token->initialized)
+				strcat(flags, "uninitialized, ");
+			else if (!slot->token->userPinSet)
+				strcat(flags, "no pin, ");
+			if (slot->token->loginRequired)
+				strcat(flags, "login, ");
+			if (slot->token->readOnly)
+				strcat(flags, "ro, ");
+		} else {
+			strcpy(flags, "no token");
+		}
+		if ((m = strlen(flags)) != 0) {
+			flags[m - 2] = '\0';
+		}
+
+		if (slot_nr != -1 &&
+			slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
+			found_slot = slot;
+		}
+		if (match_tok && slot->token &&
+				(match_tok->label == NULL ||
+					!strcmp(match_tok->label, slot->token->label)) &&
+				(match_tok->manufacturer == NULL ||
+					!strcmp(match_tok->manufacturer, slot->token->manufacturer)) &&
+				(match_tok->serialnr == NULL ||
+					!strcmp(match_tok->serialnr, slot->token->serialnr)) &&
+				(match_tok->model == NULL ||
+					!strcmp(match_tok->model, slot->token->model))) {
+			found_slot = slot;
+		}
+		if (verbose) {
+			fprintf(stderr, "[%lu] %-25.25s  %-16s",
+				PKCS11_get_slotid_from_slot(slot),
+				slot->description, flags);
+			if (slot->token) {
+				fprintf(stderr, "  (%s)",
+					slot->token->label[0] ?
+					slot->token->label : "no label");
+			}
+			fprintf(stderr, "\n");
+		}
+	}
+
+	if (match_tok) {
+		free(match_tok->model);
+		free(match_tok->manufacturer);
+		free(match_tok->serialnr);
+		free(match_tok->label);
+		free(match_tok);
+	}
+	if (found_slot) {
+		slot = found_slot;
+	} else if (match_tok) {
+		fprintf(stderr, "Specified object not found\n");
+		return NULL;
+	} else if (slot_nr == -1) {
+		if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count))) {
+			fprintf(stderr, "No tokens found\n");
+			return NULL;
+		}
+	} else {
+		fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+	tok = slot->token;
+
+	if (tok == NULL) {
+		fprintf(stderr, "Empty token found\n");
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found slot:  %s\n", slot->description);
+		fprintf(stderr, "Found token: %s\n", slot->token->label);
+	}
+
+	/* In several tokens certificates are marked as private. We use the pin-value */
+	if (tok->loginRequired && pin) {
+		/* Now login in with the (possibly NULL) pin */
+		if (PKCS11_login(slot, 0, pin)) {
+			/* Login failed, so free the PIN if present */
+			zero_pin();
+			fprintf(stderr, "Login failed\n");
+			return NULL;
+		}
+	}
+
+	if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
+		fprintf(stderr, "Unable to enumerate certificates\n");
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found %u cert%s:\n", cert_count,
+			(cert_count <= 1) ? "" : "s");
+	}
+	if ((s_slot_cert_id && *s_slot_cert_id) &&
+			(cert_id_len != 0 || cert_label != NULL)) {
+		for (n = 0; n < cert_count; n++) {
+			PKCS11_CERT *k = certs + n;
+
+			if (cert_label == NULL) {
+				if (cert_id_len != 0 && k->id_len == cert_id_len &&
+						memcmp(k->id, cert_id, cert_id_len) == 0)
+					selected_cert = k;
+			} else {
+				if (strcmp(k->label, cert_label) == 0)
+					selected_cert = k;
+			}
+		}
+	} else {
+		selected_cert = certs; /* Use the first certificate */
+	}
+
+	if (selected_cert == NULL) {
+		fprintf(stderr, "Certificate not found.\n");
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+
+	x509 = X509_dup(selected_cert->x509);
+	if (cert_label != NULL)
+		free(cert_label);
+	return x509;
+}
+
+int load_cert_ctrl(ENGINE * e, void *p)
+{
+	struct {
+		const char *s_slot_cert_id;
+		X509 *cert;
+	} *parms = p;
+
+	if (parms->cert != NULL)
+		return 0;
+
+	parms->cert = pkcs11_load_cert(e, parms->s_slot_cert_id);
+	if (parms->cert == NULL)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Log-into the token if necesary.
+ *
+ * @slot is PKCS11 slot to log in
+ * @tok is PKCS11 token to log in (??? could be derived as @slot->token)
+ * @ui_method is OpenSSL user inteface which is used to ask for a password
+ * @callback_data are application data to the user interface
+ * @return 1 on success, 0 on error.
+ */
+static int pkcs11_login(PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
+		UI_METHOD *ui_method, void *callback_data)
+{
+	if (tok->loginRequired) {
+		/* If the token has a secure login (i.e., an external keypad),
+		 * then use a NULL pin. Otherwise, check if a PIN exists. If
+		 * not, allocate and obtain a new PIN. */
+		if (tok->secureLogin) {
+			/* Free the PIN if it has already been
+			 * assigned (i.e, cached by get_pin) */
+			zero_pin();
+		} else if (pin == NULL) {
+			pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
+			pin_length = MAX_PIN_LENGTH;
+			if (pin == NULL) {
+				fprintf(stderr, "Could not allocate memory for PIN");
+				return 0;
+			}
+			if (!get_pin(ui_method, callback_data)) {
+				zero_pin();
+				fprintf(stderr, "No pin code was entered");
+				return 0;
+			}
+		}
+
+		/* Now login in with the (possibly NULL) pin */
+		if (PKCS11_login(slot, 0, pin)) {
+			/* Login failed, so free the PIN if present */
+			zero_pin();
+			fprintf(stderr, "Login failed\n");
+			return 0;
+		}
+		/* Login successful, PIN retained in case further logins are
+		 * required. This will occur on subsequent calls to the
+		 * pkcs11_load_key function. Subsequent login calls should be
+		 * relatively fast (the token should maintain its own login
+		 * state), although there may still be a slight performance
+		 * penalty. We could maintain state noting that successful
+		 * login has been performed, but this state may not be updated
+		 * if the token is removed and reinserted between calls. It
+		 * seems safer to retain the PIN and peform a login on each
+		 * call to pkcs11_load_key, even if this may not be strictly
+		 * necessary. */
+		/* TODO when does PIN get freed after successful login? */
+		/* TODO confirm that multiple login attempts do not introduce
+		 * significant performance penalties */
+	}
+	return 1;
+}
+
+static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
+		UI_METHOD * ui_method, void *callback_data, int isPrivate)
+{
+	PKCS11_SLOT *slot_list, *slot;
+	PKCS11_SLOT *found_slot = NULL;
+	PKCS11_TOKEN *tok, *match_tok = NULL;
+	PKCS11_KEY *keys, *selected_key = NULL;
+	PKCS11_CERT *certs;
+	EVP_PKEY *pk;
+	unsigned int slot_count, cert_count, key_count, n, m;
+	unsigned char key_id[MAX_VALUE_LEN / 2];
+	size_t key_id_len = sizeof(key_id);
+	char *key_label = NULL;
+	int slot_nr = -1;
+	char tmp_pin[MAX_PIN_LENGTH];
+	size_t tmp_pin_len = sizeof(tmp_pin);
+	char flags[64];
+
+	/*
+	 * TODO: Retrieve the libp11 context with:
+	 *   ctx = ENGINE_get_ex_data(e, pkcs11_idx);
+	 * instead of using a global context
+	 */
+	(void)engine;
+
+	if (verbose)
+		fprintf(stderr, "Loading %s key \"%s\"\n",
+			(char *)(isPrivate ? "private" : "public"),
+			s_slot_key_id);
+	if (s_slot_key_id && *s_slot_key_id) {
+		if (!strncmp(s_slot_key_id, "pkcs11:", 7)) {
+			n = parse_pkcs11_uri(s_slot_key_id, &match_tok,
+				key_id, &key_id_len,
+				tmp_pin, &tmp_pin_len, &key_label);
+
+			if (n && tmp_pin_len > 0 && tmp_pin[0] != 0) {
+				zero_pin();
+				pin = calloc(MAX_PIN_LENGTH, sizeof(char));
+				if (pin != NULL) {
+					memcpy(pin, tmp_pin, tmp_pin_len);
+					pin_length = tmp_pin_len;
+				}
+			}
+
+			if (!n) {
+				fprintf(stderr,
+					"The certificate ID is not a valid PKCS#11 URI\n"
+					"The PKCS#11 URI format is defined by RFC7512\n");
+				return NULL;
+			}
+		} else {
+			n = parse_slot_id_string(s_slot_key_id, &slot_nr,
+				key_id, &key_id_len, &key_label);
+
+			if (!n) {
+				fprintf(stderr,
+					"The certificate ID is not a valid PKCS#11 URI\n"
+					"The PKCS#11 URI format is defined by RFC7512\n"
+					"The legacy ENGINE_pkcs11 ID format is also "
+					"still accepted for now\n");
+				return NULL;
+			}
+		}
+		if (verbose) {
+			fprintf(stderr, "Looking in slot %d for key: ",
+				slot_nr);
+			if (key_label == NULL) {
+				for (n = 0; n < key_id_len; n++)
+					fprintf(stderr, "%02x", key_id[n]);
+				fprintf(stderr, "\n");
+			} else
+				fprintf(stderr, "label: %s\n", key_label);
+		}
+	}
+
+	if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
+		fprintf(stderr, "Failed to enumerate slots\n");
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found %u slot%s\n", slot_count,
+			(slot_count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < slot_count; n++) {
+		slot = slot_list + n;
+		flags[0] = '\0';
+		if (slot->token) {
+			if (!slot->token->initialized)
+				strcat(flags, "uninitialized, ");
+			else if (!slot->token->userPinSet)
+				strcat(flags, "no pin, ");
+			if (slot->token->loginRequired)
+				strcat(flags, "login, ");
+			if (slot->token->readOnly)
+				strcat(flags, "ro, ");
+		} else {
+			strcpy(flags, "no token");
+		}
+		if ((m = strlen(flags)) != 0) {
+			flags[m - 2] = '\0';
+		}
+
+		if (slot_nr != -1 &&
+			slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
+			found_slot = slot;
+		}
+		if (match_tok && slot->token &&
+				(match_tok->label == NULL ||
+					!strcmp(match_tok->label, slot->token->label)) &&
+				(match_tok->manufacturer == NULL ||
+					!strcmp(match_tok->manufacturer, slot->token->manufacturer)) &&
+				(match_tok->serialnr == NULL ||
+					!strcmp(match_tok->serialnr, slot->token->serialnr)) &&
+				(match_tok->model == NULL ||
+					!strcmp(match_tok->model, slot->token->model))) {
+			found_slot = slot;
+		}
+		if (verbose) {
+			fprintf(stderr, "[%lu] %-25.25s  %-16s",
+				PKCS11_get_slotid_from_slot(slot),
+				slot->description, flags);
+			if (slot->token) {
+				fprintf(stderr, "  (%s)",
+					slot->token->label[0] ?
+					slot->token->label : "no label");
+			}
+			fprintf(stderr, "\n");
+		}
+	}
+
+	if (match_tok) {
+		free(match_tok->model);
+		free(match_tok->manufacturer);
+		free(match_tok->serialnr);
+		free(match_tok->label);
+		free(match_tok);
+	}
+	if (found_slot) {
+		slot = found_slot;
+	} else if (match_tok) {
+		fprintf(stderr, "Specified object not found\n");
+		return NULL;
+	} else if (slot_nr == -1) {
+		if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count))) {
+			fprintf(stderr, "No tokens found\n");
+			return NULL;
+		}
+	} else {
+		fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+	tok = slot->token;
+
+	if (tok == NULL) {
+		fprintf(stderr, "Found empty token\n");
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+	/* The following check is non-critical to ensure interoperability
+	 * with some other (which ones?) PKCS#11 libraries */
+	if (!tok->initialized)
+		fprintf(stderr, "Found uninitialized token\n");
+	if (isPrivate && !tok->userPinSet && !tok->readOnly) {
+		fprintf(stderr, "Found slot without user PIN\n");
+		PKCS11_release_all_slots(ctx, slot_list, slot_count);
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found slot:  %s\n", slot->description);
+		fprintf(stderr, "Found token: %s\n", slot->token->label);
+	}
+
+	if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
+		fprintf(stderr, "Unable to enumerate certificates\n");
+		return NULL;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "Found %u certificate%s:\n", cert_count,
+			(cert_count <= 1) ? "" : "s");
+		for (n = 0; n < cert_count; n++) {
+			PKCS11_CERT *c = certs + n;
+			char *dn = NULL;
+
+			fprintf(stderr, "  %2u    %s", n + 1, c->label);
+			if (c->x509)
+				dn = X509_NAME_oneline(X509_get_subject_name(c->x509), NULL, 0);
+			if (dn) {
+				fprintf(stderr, " (%s)", dn);
+				OPENSSL_free(dn);
+			}
+			fprintf(stderr, "\n");
+		}
+	}
+
+	if (isPrivate) {
+		/* Perform login to the token if required */
+		if (!pkcs11_login(slot, tok, ui_method, callback_data)) {
+			fprintf(stderr, "login to token failed, returning NULL...\n");
+			return NULL;
+		}
+
+		/* Make sure there is at least one private key on the token */
+		if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
+			fprintf(stderr, "Unable to enumerate private keys\n");
+			return NULL;
+		}
+	} else {
+		/* Make sure there is at least one public key on the token */
+		if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
+			fprintf(stderr, "Unable to enumerate public keys\n");
+			return NULL;
+		}
+	}
+	if (key_count == 0) {
+		fprintf(stderr, "No %s keys found.\n",
+			(char *)(isPrivate ? "private" : "public"));
+		return NULL;
+	}
+	if (verbose)
+		fprintf(stderr, "Found %u %s key%s:\n", key_count,
+			(char *)(isPrivate ? "private" : "public"),
+			(key_count == 1) ? "" : "s");
+
+	if (s_slot_key_id && *s_slot_key_id &&
+			(key_id_len != 0 || key_label != NULL)) {
+		for (n = 0; n < key_count; n++) {
+			PKCS11_KEY *k = keys + n;
+
+			if (verbose) {
+				fprintf(stderr, "  %2u %c%c %s\n", n + 1,
+					k->isPrivate ? 'P' : ' ',
+					k->needLogin ? 'L' : ' ', k->label);
+			}
+			if (key_label == NULL) {
+				if (key_id_len != 0 && k->id_len == key_id_len
+						&& memcmp(k->id, key_id, key_id_len) == 0) {
+					selected_key = k;
+				}
+			} else {
+				if (strcmp(k->label, key_label) == 0) {
+					selected_key = k;
+				}
+			}
+		}
+	} else {
+		selected_key = keys; /* Use the first key */
+	}
+
+	if (selected_key == NULL) {
+		fprintf(stderr, "Key not found.\n");
+		return NULL;
+	}
+
+	pk = isPrivate ?
+		PKCS11_get_private_key(selected_key) :
+		PKCS11_get_public_key(selected_key);
+	if (key_label != NULL)
+		free(key_label);
+	return pk;
+}
+
+EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
+		UI_METHOD * ui_method, void *callback_data)
+{
+	EVP_PKEY *pk;
+
+	pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 0);
+	if (pk == NULL) {
+		fprintf(stderr, "PKCS11_load_public_key returned NULL\n");
+		return NULL;
+	}
+	return pk;
+}
+
+EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
+		UI_METHOD * ui_method, void *callback_data)
+{
+	EVP_PKEY *pk;
+
+	pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 1);
+	if (pk == NULL) {
+		fprintf(stderr, "PKCS11_get_private_key returned NULL\n");
+		return NULL;
+	}
+	return pk;
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/eng_front.c b/src/eng_front.c
new file mode 100644
index 0000000..ec0eee9
--- /dev/null
+++ b/src/eng_front.c
@@ -0,0 +1,209 @@
+/* crypto/engine/hw_pkcs11.c */
+/* Written by Geoff Thorpe (geoff at geoffthorpe.net) for the OpenSSL
+ * project 2000.
+ * Copied/modified by Kevin Stefanik (kstef at mtppi.org) for the OpenSC
+ * project 2003.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
+ * Portions Copyright (c) 2003 Kevin Stefanik (kstef at mtppi.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing at OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+#include "engine.h"
+#include "libp11.h"
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/opensslconf.h>
+#include <openssl/crypto.h>
+#include <openssl/objects.h>
+#include <openssl/engine.h>
+#include <openssl/dso.h>
+#ifndef ENGINE_CMD_BASE
+#error did not get engine.h
+#endif
+
+#define PKCS11_ENGINE_ID "pkcs11"
+#define PKCS11_ENGINE_NAME "pkcs11 engine"
+
+#define CMD_SO_PATH		ENGINE_CMD_BASE
+#define CMD_MODULE_PATH 	(ENGINE_CMD_BASE+1)
+#define CMD_PIN		(ENGINE_CMD_BASE+2)
+#define CMD_VERBOSE		(ENGINE_CMD_BASE+3)
+#define CMD_QUIET		(ENGINE_CMD_BASE+4)
+#define CMD_LOAD_CERT_CTRL	(ENGINE_CMD_BASE+5)
+#define CMD_INIT_ARGS	(ENGINE_CMD_BASE+6)
+
+static int pkcs11_engine_destroy(ENGINE * e);
+static int pkcs11_engine_ctrl(ENGINE * e, int cmd, long i, void *p,
+	void (*f) ());
+
+/* The definitions for control commands specific to this engine */
+
+/* need to add function to pass in reader id? or user reader:key as key id string? */
+
+static const ENGINE_CMD_DEFN pkcs11_cmd_defns[] = {
+	{CMD_SO_PATH,
+		"SO_PATH",
+		"Specifies the path to the 'pkcs11-engine' shared library",
+		ENGINE_CMD_FLAG_STRING},
+	{CMD_MODULE_PATH,
+		"MODULE_PATH",
+		"Specifies the path to the pkcs11 module shared library",
+		ENGINE_CMD_FLAG_STRING},
+	{CMD_PIN,
+		"PIN",
+		"Specifies the pin code",
+		ENGINE_CMD_FLAG_STRING},
+	{CMD_VERBOSE,
+		"VERBOSE",
+		"Print additional details",
+		ENGINE_CMD_FLAG_NO_INPUT},
+	{CMD_QUIET,
+		"QUIET",
+		"Remove additional details",
+		ENGINE_CMD_FLAG_NO_INPUT},
+	{CMD_LOAD_CERT_CTRL,
+		"LOAD_CERT_CTRL",
+		"Get the certificate from card",
+		ENGINE_CMD_FLAG_INTERNAL},
+	{CMD_INIT_ARGS,
+		"INIT_ARGS",
+		"Specifies additional initialization arguments to the pkcs11 module",
+		ENGINE_CMD_FLAG_STRING},
+	{0, NULL, NULL, 0}
+};
+
+/* Destructor */
+static int pkcs11_engine_destroy(ENGINE * e)
+{
+	(void)e;
+#ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_ECDSA
+	PKCS11_ecdsa_method_free();
+#endif
+#endif
+
+	return 1;
+}
+
+static int pkcs11_engine_ctrl(ENGINE * e, int cmd, long i, void *p,
+		void (*f) ())
+{
+	(void)i; /* We don't currently take integer parameters */
+	(void)f; /* We don't currently take callback parameters */
+	/*int initialised = ((pkcs11_dso == NULL) ? 0 : 1); */
+	switch (cmd) {
+	case CMD_MODULE_PATH:
+		return set_module((const char *)p);
+	case CMD_PIN:
+		return set_pin((const char *)p);
+	case CMD_VERBOSE:
+		return inc_verbose();
+	case CMD_LOAD_CERT_CTRL:
+		return load_cert_ctrl(e, p);
+	case CMD_INIT_ARGS:
+		return set_init_args((const char *)p);
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* This internal function is used by ENGINE_pkcs11() and possibly by the
+ * "dynamic" ENGINE support too */
+static int bind_helper(ENGINE * e)
+{
+	if (!ENGINE_set_id(e, PKCS11_ENGINE_ID) ||
+			!ENGINE_set_destroy_function(e, pkcs11_engine_destroy) ||
+			!ENGINE_set_init_function(e, pkcs11_init) ||
+			!ENGINE_set_finish_function(e, pkcs11_finish) ||
+			!ENGINE_set_ctrl_function(e, pkcs11_engine_ctrl) ||
+			!ENGINE_set_cmd_defns(e, pkcs11_cmd_defns) ||
+			!ENGINE_set_name(e, PKCS11_ENGINE_NAME) ||
+#ifndef OPENSSL_NO_RSA
+			!ENGINE_set_RSA(e, PKCS11_get_rsa_method()) ||
+#endif
+#ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_ECDSA
+			!ENGINE_set_ECDSA(e, PKCS11_get_ecdsa_method()) ||
+#endif
+/* TODO add ECDH
+			!ENGINE_set_ECDH(e, PKCS11_get_ecdh_method()) ||
+*/
+#endif
+			!ENGINE_set_load_pubkey_function(e, pkcs11_load_public_key) ||
+			!ENGINE_set_load_privkey_function(e, pkcs11_load_private_key)) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+static int bind_fn(ENGINE * e, const char *id)
+{
+	if (id && (strcmp(id, PKCS11_ENGINE_ID) != 0)) {
+		fprintf(stderr, "bad engine id\n");
+		return 0;
+	}
+	if (!bind_helper(e)) {
+		fprintf(stderr, "bind failed\n");
+		return 0;
+	}
+	return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
+
+/* vim: set noexpandtab: */
diff --git a/src/engine.h b/src/engine.h
new file mode 100644
index 0000000..3261a22
--- /dev/null
+++ b/src/engine.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Juha Yrjölä.  All rights reserved.
+ * Copyright (c) 2001 Markus Friedl.
+ * Copyright (c) 2003 Kevin Stefanik
+ *
+ * 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.
+ */
+
+#ifndef _ENGINE_PKCS11_H
+#define _ENGINE_PKCS11_H
+
+#ifndef _WIN32
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/objects.h>
+#include <openssl/engine.h>
+
+int set_module(const char *modulename);
+
+int set_pin(const char *pin);
+
+int set_init_args(const char *init_args_orig);
+
+int load_cert_ctrl(ENGINE * e, void *p);
+
+int inc_verbose(void);
+
+int pkcs11_finish(ENGINE * engine);
+
+int pkcs11_init(ENGINE * engine);
+
+int pkcs11_rsa_finish(RSA * rsa);
+
+EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
+	UI_METHOD * ui_method, void *callback_data);
+
+EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
+	UI_METHOD * ui_method, void *callback_data);
+
+#endif
+
+/* vim: set noexpandtab: */
diff --git a/src/versioninfo.rc b/src/libp11.rc
similarity index 100%
copy from src/versioninfo.rc
copy to src/libp11.rc
diff --git a/src/versioninfo.rc.in b/src/libp11.rc.in
similarity index 100%
copy from src/versioninfo.rc.in
copy to src/libp11.rc.in
diff --git a/src/pkcs11.exports b/src/pkcs11.exports
new file mode 100644
index 0000000..6b8b3a9
--- /dev/null
+++ b/src/pkcs11.exports
@@ -0,0 +1,2 @@
+v_check
+bind_engine
diff --git a/src/versioninfo.rc b/src/pkcs11.rc
similarity index 81%
rename from src/versioninfo.rc
rename to src/pkcs11.rc
index c01a3b2..ec1a897 100644
--- a/src/versioninfo.rc
+++ b/src/pkcs11.rc
@@ -1,7 +1,7 @@
 #include <winresrc.h>
 
 VS_VERSION_INFO VERSIONINFO
-	FILEVERSION 5,3,0,0
+	FILEVERSION 0,4,0,0
 	PRODUCTVERSION 0,4,0,0
 	FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
@@ -19,12 +19,12 @@ BEGIN
 		BEGIN
 			VALUE "Comments", "Provided under the terms of the GNU General Public License (LGPLv2.1+).\0"
 			VALUE "CompanyName", "OpenSC Project\0"
-			VALUE "FileDescription", "PKCS#11 access library\0"
-			VALUE "FileVersion", "5.3.0.0\0"
+			VALUE "FileDescription", "OpenSSL PKCS#11 engine\0"
+			VALUE "FileVersion", "0,4,0,0\0"
 			VALUE "InternalName", "libp11\0"
 			VALUE "LegalCopyright", "OpenSC Project\0"
 			VALUE "LegalTrademarks", "\0"
-			VALUE "OriginalFilename", "libp11-2.dll\0"
+			VALUE "OriginalFilename", "pkcs11.dll\0"
 			VALUE "PrivateBuild", "\0"
 			VALUE "ProductName", "libp11\0"
 			VALUE "ProductVersion", "0,4,0,0\0"
diff --git a/src/versioninfo.rc.in b/src/pkcs11.rc.in
similarity index 74%
rename from src/versioninfo.rc.in
rename to src/pkcs11.rc.in
index 0529ef8..3429881 100644
--- a/src/versioninfo.rc.in
+++ b/src/pkcs11.rc.in
@@ -1,7 +1,7 @@
 #include <winresrc.h>
 
 VS_VERSION_INFO VERSIONINFO
-	FILEVERSION @LIBP11_LT_CURRENT@, at LIBP11_LT_AGE@, at LIBP11_LT_REVISION@,0
+	FILEVERSION @LIBP11_VERSION_MAJOR@, at LIBP11_VERSION_MINOR@, at LIBP11_VERSION_FIX@,0
 	PRODUCTVERSION @LIBP11_VERSION_MAJOR@, at LIBP11_VERSION_MINOR@, at LIBP11_VERSION_FIX@,0
 	FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
@@ -19,12 +19,12 @@ BEGIN
 		BEGIN
 			VALUE "Comments", "Provided under the terms of the GNU General Public License (LGPLv2.1+).\0"
 			VALUE "CompanyName", "OpenSC Project\0"
-			VALUE "FileDescription", "PKCS#11 access library\0"
-			VALUE "FileVersion", "@LIBP11_LT_CURRENT at .@LIBP11_LT_AGE at .@LIBP11_LT_REVISION at .0\0"
+			VALUE "FileDescription", "OpenSSL PKCS#11 engine\0"
+			VALUE "FileVersion", "@LIBP11_VERSION_MAJOR@, at LIBP11_VERSION_MINOR@, at LIBP11_VERSION_FIX@,0\0"
 			VALUE "InternalName", "@PACKAGE_NAME@\0"
 			VALUE "LegalCopyright", "OpenSC Project\0"
 			VALUE "LegalTrademarks", "\0"
-			VALUE "OriginalFilename", "@PACKAGE_NAME at -@LIBP11_LT_OLDEST at .dll\0"
+			VALUE "OriginalFilename", "pkcs11.dll\0"
 			VALUE "PrivateBuild", "\0"
 			VALUE "ProductName", "@PACKAGE_NAME@\0"
 			VALUE "ProductVersion", "@LIBP11_VERSION_MAJOR@, at LIBP11_VERSION_MINOR@, at LIBP11_VERSION_FIX@,0\0"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/libp11.git



More information about the pkg-opensc-commit mailing list