[pkg-opensc-commit] [engine-pkcs11] 02/152: initial checkin of a standalone engine_pkcs11.

Eric Dorland eric at moszumanska.debian.org
Mon Oct 19 03:11:07 UTC 2015


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

eric pushed a commit to branch master
in repository engine-pkcs11.

commit b2455b097f8bd9b0a075df3820ce21c6bf33357a
Author: Andreas Jellinghaus <andreas at ionisiert.de>
Date:   Sun Aug 28 19:52:19 2005 +0000

    initial checkin of a standalone engine_pkcs11.
---
 Makefile.am           |  15 ++
 bootstrap             |  11 +
 configure.ac          | 282 +++++++++++++++++++++
 doc/Makefile.am       |   7 +
 doc/README            |  10 +
 doc/export-wiki.sh    |  34 +++
 doc/export-wiki.xsl   |  58 +++++
 libtool-bundle        | 104 ++++++++
 src/Makefile.am       |  32 +++
 src/Makefile.mak      |  12 +
 src/engine_pkcs11.c   | 671 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/engine_pkcs11.def |   4 +
 src/engine_pkcs11.h   |  59 +++++
 src/hw_opensc.c       | 215 ++++++++++++++++
 src/hw_pkcs11.c       | 204 +++++++++++++++
 15 files changed, 1718 insertions(+)

diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f86a689
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,15 @@
+# Process this file with automake to create Makefile.in
+
+SUBDIRS = . doc src 
+
+EXTRA_DIST = bootstrap depcomp 
+
+MAINTAINERCLEANFILES = \
+	Makefile.in config.h.in configure \
+	install-sh ltmain.sh missing mkinstalldirs \
+	compile depcomp config.log config.status \
+	config.guess config.sub acinclude.m4 aclocal.m4
+
+DEPCLEANFILES = config.log configure
+
+AUTOMAKE_OPTIONS = foreign 1.5
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..4e964bd
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+set -x
+if test -f Makefile; then
+  make distclean
+fi
+rm -rf *.cache *.m4 config.guess config.log \
+config.status config.sub depcomp ltmain.sh
+(cat aclocal/*.m4 > acinclude.m4 2> /dev/null)
+autoreconf --verbose --install
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..52d46f8
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,282 @@
+dnl -*- mode: m4; -*-
+dnl Process this file with autoconf to produce a configure script.
+
+# Require autoconf 2.52
+AC_PREREQ(2.52)
+
+AC_INIT(engine_pkcs11, WIP)
+AM_INIT_AUTOMAKE
+AM_CONFIG_HEADER(config.h)
+
+AC_CONFIG_SRCDIR(src/engine_pkcs11.c)
+
+
+AC_CANONICAL_HOST
+AC_PROG_CC
+AC_C_BIGENDIAN
+
+dnl Options
+AM_MAINTAINER_MODE
+
+dnl Checks for programs.
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+dnl Add libtool support.
+AM_PROG_LIBTOOL
+dnl Automatically update the libtool script if it becomes out-of-date.
+#AC_SUBST(LIBTOOL_DEPS)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([errno.h fcntl.h malloc.h stdlib.h inttypes.h string.h strings.h sys/time.h unistd.h locale.h getopt.h dlfcn.h utmp.h])
+
+PKG_CHECK_MODULES([LIBP11], [libp11])
+
+dnl The big mess with OpenSSL
+saved_LIBS="$LIBS"
+saved_LDFLAGS="$LDFLAGS"
+saved_CPPFLAGS="$CPPFLAGS"
+
+SSL_MSG="no"
+ssldir=""
+
+AC_ARG_WITH(openssl,
+	AC_HELP_STRING([--with-openssl=PATH], [use OpenSSL in PATH]),
+	[
+		# Disable OpenSSL support
+		if test "x$withval" = "xno" ; then
+			SSL_MSG="no (disabled)"
+			break;
+		fi
+
+		# ok we got a directory, so only check in that dir.
+		LIBCRYPTO="-lcrypto"
+		CPPFLAGS="$saved_CPPFLAGS"
+		LDFLAGS="$saved_LDFLAGS"
+		LIBS="$LIBCRYPTO $saved_LIBS"
+		LDFLAGS="-L$withval/lib $saved_LDFLAGS"
+		if test ! -z "$need_dash_r" ; then
+			LDFLAGS="-R$withval/lib $LDFLAGS"
+		fi
+		CPPFLAGS="-I$withval/include $saved_CPPFLAGS"
+
+		AC_TRY_RUN(
+			[
+#include <string.h>
+#include <openssl/rand.h>
+int main(void)
+{
+	char a[2048];
+	memset(a, 0, sizeof(a));
+	RAND_add(a, sizeof(a), sizeof(a));
+	return(RAND_status() <= 0);
+}
+			],
+			[
+				SSL_MSG="yes"
+				ssldir="$withval"
+				break
+			])
+			],[
+
+	# we didn't get a directory, so we start searching for openssl
+	for tryssldir in $commondir /usr /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl; do
+		# Skip directories if they don't exist
+		if test ! -d "$tryssldir/" ; then
+			continue;
+		fi
+
+		LIBCRYPTO="-lcrypto"
+		CPPFLAGS="$saved_CPPFLAGS"
+		LDFLAGS="$saved_LDFLAGS"
+		LIBS="$saved_LIBS $LIBCRYPTO"
+
+		if test "x$tryssldir" != "x/usr"; then
+			LDFLAGS="-L$tryssldir/lib $saved_LDFLAGS"
+			if test ! -z "$need_dash_r" ; then
+				LDFLAGS="-R$tryssldir/lib $LDFLAGS"
+			fi
+			CPPFLAGS="-I$tryssldir/include $saved_CPPFLAGS"
+		fi
+
+		# Basic test to check for compatible version and correct linking
+		# *does not* test for RSA - that comes later.
+		AC_TRY_RUN(
+			[
+#include <string.h>
+#include <openssl/rand.h>
+int main(void)
+{
+	char a[2048];
+	memset(a, 0, sizeof(a));
+	RAND_add(a, sizeof(a), sizeof(a));
+	return(RAND_status() <= 0);
+}
+			],
+			[
+				SSL_MSG="yes"
+				ssldir=$tryssldir
+				break;
+			],
+			[
+				SSL_MSG="no"
+				LIBS="$saved_LIBS"
+				LDFLAGS="$saved_LDFLAGS"
+				CPPFLAGS="$saved_CPPFLAGS"
+			])
+	done
+	])
+LIBS="$saved_LIBS"
+AC_SUBST(LIBCRYPTO)
+AM_CONDITIONAL(HAVE_SSL, test "x$SSL_MSG" = "xyes")
+
+if test "x$SSL_MSG" = "xyes" ; then
+  AC_DEFINE(HAVE_OPENSSL, 1, [Have OpenSSL libraries])
+else
+  LIBCRYPTO=""
+fi
+
+# ok, we checked for basic ssl support.
+# if it is not available, we can skip the rest of
+# the test. also we have $ssldir set to the location
+# of the openssl libs.
+
+ENGINE_MSG="no"
+if test "x$SSL_MSG" = "xyes"; then
+	# engine has to be there and working
+	LIBS="$saved_LIBS $LIBCRYPTO $LIBDL"
+	AC_TRY_RUN(
+	[
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+int main(void)
+{
+	char a[2048];
+	ENGINE *e;
+
+	e = ENGINE_new();
+	ENGINE_load_dynamic();
+	if (!e) return 1;
+	memset(a, 0, sizeof(a));
+	RAND_add(a, sizeof(a), sizeof(a));
+	return(RAND_status() <= 0);
+}
+	],
+	[
+		ENGINE_MSG=yes
+		ENGINE_LINK="$LIBCRYPTO"
+	],
+	[
+		ENGINE_MSG=no
+	]);
+fi
+LIBS="$saved_LIBS"
+AC_SUBST(ENGINE_LINK)
+AM_CONDITIONAL(HAVE_ENGINE, test "x$ENGINE_MSG" = "xyes")
+
+# ok, now we might (or not) have ssl and an engine.
+# still room for "improvements", i.e. hacks to work
+# with old engines.
+
+SSLHACK_MSG=no
+if test "x$SSL_MSG" = "xyes" -a "x$ENGINE_MSG" = "xyes"; then
+	# latest openssl version with engine
+	# properly integrated?
+	AC_MSG_CHECKING([for openssl version])
+	AC_TRY_RUN(
+	[
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+
+int main(void)
+{
+	if(OPENSSL_VERSION_NUMBER >= 0x0090704fL) {
+		exit(0);
+	} else {
+		exit(1);
+	}
+}
+	],
+	[
+		AC_MSG_RESULT([good, 0.9.7d or later])
+		OLD_OPENSSL=no
+	],
+	[
+		AC_MSG_RESULT([not so good, 0.9.7d or later would be better])
+		OLD_OPENSSL=yes
+	])
+
+	if test "x$OLD_OPENSSL" = "xyes"; then
+		# openssl found, but version less than 0.9.7d
+		# linking libcrypto.a statically possible?
+
+		LIBS="$saved_LIBS $ssldir/lib/libcrypto.a $LIBDL"
+		AC_TRY_RUN(
+		[
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+int main(void)
+{
+	char a[2048];
+	ENGINE *e;
+
+	e = ENGINE_new();
+	ENGINE_load_dynamic();
+	if (!e) return 1;
+	memset(a, 0, sizeof(a));
+	RAND_add(a, sizeof(a), sizeof(a));
+	return(RAND_status() <= 0);
+}
+		],
+		[
+			SSLHACK_MSG=yes
+			ENGINE_LINK="$ssldir/lib/libcrypto.a"
+		])
+		LIBS="$saved_LIBS"
+	fi
+fi
+
+# now - last part to do: check if we gain anything from
+# funny parameters to link openssl with.
+
+saved_LDFLAGS="$LDFLAGS"
+if test "x$ENGINE_MSG" = "xyes" ; then
+  for openssl_ldflag in "-Wl,-Bsymbolic" "-G -Wl,-Bsymbolic" "-shared -G -Wl,-Bsymbolic" "-Wl,-all_load"; do
+	AC_MSG_CHECKING([whether we can use $openssl_ldflag])
+	LDFLAGS="$saved_LDFLAGS $openssl_ldflag"
+	AC_TRY_LINK(,[return 1],ac_cv_use_openssl_flag="yes",ac_cv_use_openssl_flag="no")
+	AC_MSG_RESULT($ac_cv_use_openssl_flag)
+	if test "$ac_cv_use_openssl_flag" = "yes"; then
+		OPENSSL_LDFLAGS="$openssl_ldflag"
+		break;
+	fi
+  done
+fi
+LDFLAGS="$saved_LDFLAGS"
+AC_SUBST(OPENSSL_LDFLAGS)
+
+AM_CONDITIONAL(HAVE_BUNDLES, test "x$with_bundles" = "xyes")
+
+AC_OUTPUT([
+Makefile
+doc/Makefile
+src/Makefile
+])
+
+echo ""
+echo "Engine_pkcs11 has been configured with the following options"
+
+echo ""
+echo "OpenSSL support:          ${SSL_MSG}"
+echo "        with engine:      ${ENGINE_MSG}"
+echo "        with sslhack:     ${SSLHACK_MSG}"
+echo ""
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..2a63710
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,7 @@
+# Process this file with automake to create Makefile.in
+
+MAINTAINERCLEANFILES = Makefile.in
+
+EXTRA_DIST = README export-wiki.sh export-wiki.xsl $(HTML)
+
+HTML= 
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..2c3ff75
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,10 @@
+This directory contains a snapshot of the engine_pkcs11 Wiki
+============================================================
+
+The original wiki page is at http://www.opensc.org/engine_pkcs11/
+and includes a bug tracker and source browser.
+
+The wiki was transformed to html using the export-wiki shell
+script and xsl style sheet. The original version is at 
+	http://www.twdata.org/trac-howto/
+
diff --git a/doc/export-wiki.sh b/doc/export-wiki.sh
new file mode 100644
index 0000000..ea7f5ec
--- /dev/null
+++ b/doc/export-wiki.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+set -e
+
+export SERVER=http://www.opensc.org
+export WIKI=engine_pkcs11/wiki
+export XSL=export-wiki.xsl
+
+test -f `basename $0`
+
+rm -rf *.html *.css
+
+wget $SERVER/$WIKI/TitleIndex -O TitleIndex.tmp
+
+grep "\"/$WIKI/[^\"]*\"" TitleIndex.tmp \
+        |sed -e "s#.*\"/$WIKI/\([^\"]*\)\".*#\1#g" \
+	> WikiWords.tmp
+sed -e /^Trac/d -e /^Wiki/d -e /^TitleIndex/d -e /^RecentChanges/d \
+	-e /^CamelCase/d -e /^SandBox/d -i WikiWords.tmp
+
+for A in WikiStart `cat WikiWords.tmp`
+do
+	F=`echo $A|sed -e 's/\//_/g'`
+	wget $SERVER/$WIKI/$A  -O $F.tmp
+	xsltproc --output $F.html $XSL $F.tmp
+	sed -e "s#<a href=\"/$WIKI/\([^\"]*\)\"#<a href=\"\1.html\"#g" \
+		-i $F.html
+done
+
+mv WikiStart.html index.html
+
+wget http://www.opensc.org/trac/css/trac.css
+
+rm *.tmp
diff --git a/doc/export-wiki.xsl b/doc/export-wiki.xsl
new file mode 100644
index 0000000..145befb
--- /dev/null
+++ b/doc/export-wiki.xsl
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+xmlns="http://www.w3.org/1999/xhtml"
+xmlns:html="http://www.w3.org/1999/xhtml">
+	<xsl:output method="html" indent="yes"/>
+  
+  <xsl:template match="/">
+    <xsl:apply-templates />
+  </xsl:template>
+  
+  <xsl:template match="/html:html">
+      <html>
+        <head>
+          <title><xsl:value-of select="/html:html/html:head/html:title" /></title>
+          <style type="text/css">
+           @import url(trac.css);
+          </style>
+        </head>
+        <body>
+          <xsl:apply-templates select="//html:div[@class='wikipage']" />
+          <div class="footer">
+            <hr />
+            <p><a href="index.html">Back to Index</a></p>
+          </div>
+        </body>
+      </html>
+  </xsl:template>
+  
+  <xsl:template match="/pages">
+      <html>
+        <head>
+          <title>Wiki Index</title>
+          <style type="text/css">
+           @import url(trac.css);
+          </style>
+        </head>
+        <body>
+          <h1>Index of Wiki Pages</h1>
+          <ul>
+          <xsl:apply-templates select="page" />
+          </ul>
+        </body>
+      </html>
+  </xsl:template>
+  
+  <xsl:template match="page">
+    <li><a href="{.}.html"><xsl:value-of select="." /></a></li>
+  </xsl:template>
+  
+  <xsl:template match="node()|@*" priority="-1">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+ 
+</xsl:stylesheet>
+
diff --git a/libtool-bundle b/libtool-bundle
new file mode 100755
index 0000000..96f094d
--- /dev/null
+++ b/libtool-bundle
@@ -0,0 +1,104 @@
+#!/bin/sh
+# A shell script to create MacOS X bundles
+# from files created by GNU libtool.
+# Incomplete, but works.
+#
+# $Id: libtool-bundle 1533 2003-10-16 20:41:34Z aet $
+# <aet at cc.hut.fi>
+#
+
+set -e
+verbose=0
+
+verbose_msg ()
+{
+  if [ $verbose -ne 0 ]; then
+    echo "libtool-bundle: $@"
+  fi
+}
+
+error_msg ()
+{
+  echo 1>&2 "libtool-bundle: $@"
+}
+
+usage ()
+{
+  error_msg "Usage: $0 [-e extra XML data] [Mach-O bundle file] [destination directory] <bundle name>"
+  exit 1
+}
+
+case $1 in
+  -e) shift; if [ "$1" ]; then extradata=$1; shift; else usage; fi; ;;
+esac
+
+[ $# -le 1 -o $# -ge 4 ] && usage
+
+sofile=$1
+[ ! -f $sofile ] && error_msg "Not a file or file not found: $sofile" && exit 1
+case "$sofile" in
+*.so*)
+  # Assume it's ok
+  ;;
+*)
+  error_msg "Invalid bundle: $sofile"
+  exit 1
+  ;;
+esac
+
+destdir=$2
+[ ! -d $destdir -o ! -w $destdir ] && error_msg "Not a directory or no write access: $destdir" && exit 1
+
+name="$sofile"
+[ $# -eq 3 ] && name=$3
+name=`echo $name | sed -e "s at .*/@@" -e "s@\.so.*@@"`
+root="$destdir/${name}.bundle"
+
+verbose_msg "sofile: $sofile"
+verbose_msg "destdir: $destdir"
+verbose_msg "name: $name"
+verbose_msg "root: $root"
+
+arch=`uname`
+[ x$arch = xDarwin ] && arch=MacOS
+type="BNDL"
+creator="????"
+
+# Overwrite existing bundle
+[ -d "$root" ] && rm -rf "$root"
+
+mkdir -p "$root"/Contents/$arch
+cp "$sofile" "$root"/Contents/$arch/"$name"
+echo "$type$creator" > "$root"/Contents/PkgInfo
+
+create_info_plist ()
+{
+  echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+  echo "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+  echo "<plist version=\"1.0\">"
+  echo "<dict>"
+  echo "	<key>CFBundleDevelopmentRegion</key>"
+  echo "	<string>English</string>"
+  echo "	<key>CFBundleExecutable</key>"
+  echo "	<string>$name</string>"
+  echo "	<key>CFBundleInfoDictionaryVersion</key>"
+  echo "	<string>6.0</string>"
+  echo "	<key>CFBundleName</key>"
+  echo "	<string>$name</string>"
+  echo "	<key>CFBundlePackageType</key>"
+  echo "	<string>$type</string>"
+  echo "	<key>CFBundleSignature</key>"
+  echo "	<string>$creator</string>"
+  echo "	<key>CFBundleVersion</key>"
+  echo "	<string>0.0.1d1</string>"
+  if [ "$extradata" ]; then
+    echo ""
+    [ -f "$extradata" ]; cat $extradata
+  fi
+  echo "</dict>"
+  echo "</plist>"
+}
+
+create_info_plist > "$root"/Contents/Info.plist
+
+echo "Installed $sofile as $root"
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..608103e
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,32 @@
+# Process this file with automake to create Makefile.in
+
+bundledir = @BUNDLEDIR@/opensc
+enginedir = @libdir@/openssl
+
+MAINTAINERCLEANFILES = Makefile.in
+
+EXTRA_DIST = Makefile.mak engine_pkcs11.def 
+
+engine_LTLIBRARIES = engine_pkcs11.la
+
+OPENSSL_CFLAGS = \
+	-DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H \
+	-DOPENSSL_NO_KRB5 -DL_ENDIAN -DTERMIO -DENGINE_DYNAMIC_SUPPORT \
+	-DSHA1_ASM -DMD5_ASM -DRMD160_ASM
+
+engine_pkcs11_la_SOURCES = \
+	hw_pkcs11.c engine_pkcs11.c engine_pkcs11.h 
+engine_pkcs11_la_CFLAGS = $(OPENSSL_CFLAGS) -I$(srcdir)/../libp11 @LIBP11_CFLAGS@
+engine_pkcs11_la_LIBADD = @ENGINE_LINK@ @LIBP11_LIBS@
+engine_pkcs11_la_LDFLAGS = @OPENSSL_LDFLAGS@ -module -avoid-version
+
+install-exec-local: install-engineLTLIBRARIES
+if HAVE_BUNDLES
+	-${top_srcdir}/libtool-bundle $(DESTDIR)$(enginedir)/engine_pkcs11.so \
+		$(DESTDIR)$(bundledir)/
+endif
+
+uninstall-local: uninstall-engineLTLIBRARIES
+if HAVE_BUNDLES
+	rm -rf $(DESTDIR)$(bundledir)/engine_pkcs11.bundle/
+endif
diff --git a/src/Makefile.mak b/src/Makefile.mak
new file mode 100644
index 0000000..c67124e
--- /dev/null
+++ b/src/Makefile.mak
@@ -0,0 +1,12 @@
+TOPDIR = ..\..
+
+TARGET                  = engine_pkcs11.dll
+
+OBJECTS			= engine_pkcs11.obj hw_pkcs11.obj
+
+all: $(TARGET)
+
+!INCLUDE $(TOPDIR)\win32\Make.rules.mak
+
+$(TARGET): $(OBJECTS) ..\libp11\libp11.lib ..\scconf\scconf.lib
+	link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET) $(OBJECTS) ..\libp11\libp11.lib ..\scconf\scconf.lib winscard.lib $(OPENSSL_LIB) gdi32.lib
diff --git a/src/engine_pkcs11.c b/src/engine_pkcs11.c
new file mode 100644
index 0000000..5becc83
--- /dev/null
+++ b/src/engine_pkcs11.c
@@ -0,0 +1,671 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/objects.h>
+#include <libp11.h>
+#include "engine_pkcs11.h"
+
+#ifdef _WIN32
+#define strncasecmp strnicmp
+#endif
+
+#define fail(msg) { fprintf(stderr,msg); return NULL;}
+
+/** The maximum length of an internally-allocated PIN */
+#define MAX_PIN_LENGTH   12
+
+PKCS11_CTX *ctx;
+
+/** 
+ * The PIN used for login. May be assigend by set_pin function, or by the
+ * get_pin function (using an external UI). 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;
+
+int verbose = 0;
+
+#if defined(_WIN32)
+#define PKCS11_DEFAULT_MODULE_NAME	"opensc-pkcs11"
+#elif defined(HAVE_DLFCN_H) && defined(__APPLE__)
+#define PKCS11_DEFAULT_MODULE_NAME	"opensc-pkcs11.so"
+#elif defined(__APPLE__)
+#define PKCS11_DEFAULT_MODULE_NAME	"opensc-pkcs11.bundle"
+#else
+#define PKCS11_DEFAULT_MODULE_NAME	"opensc-pkcs11.so"
+#endif
+
+char *module = PKCS11_DEFAULT_MODULE_NAME;
+int default_module = 1;
+
+int set_module(const char *modulename)
+{
+	module = strdup (modulename);
+	default_module = 0;
+	return 1;
+}
+
+/**
+ * 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. */
+	pin = strdup(_pin);
+
+	return (pin != NULL);
+}
+
+int inc_verbose()
+{
+	verbose++;
+	return 1;
+}
+
+static char *get_pin(UI_METHOD * ui_method, void *callback_data, char *sc_pin, int maxlen)
+{
+	UI *ui;
+
+	ui = UI_new();
+	if (ui_method != NULL)
+		UI_set_method(ui, ui_method);
+	if (callback_data != NULL)
+		UI_set_app_data(ui, callback_data);
+
+	if (!UI_add_input_string(ui, "PKCS#11 token PIN: ", 0, sc_pin, 1, maxlen)) {
+		fprintf(stderr, "UI_add_input_string failed\n");
+		UI_free(ui);
+		return NULL;
+	}
+	if (UI_process(ui)) {
+		fprintf(stderr, "UI_process failed\n");
+		UI_free(ui);
+		return NULL;
+	}
+	UI_free(ui);
+	return sc_pin;
+}
+
+int pkcs11_finish(ENGINE * engine)
+{
+	if (ctx) {
+		PKCS11_CTX_free(ctx);
+	}
+	if (pin != NULL) {
+		OPENSSL_cleanse(pin, strlen(pin));
+		free(pin);
+		pin = NULL;
+	}
+	return 1;
+}
+
+int pkcs11_init(ENGINE * engine)
+{
+	if (verbose) {
+		fprintf(stderr, "initializing engine\n");
+	}
+	ctx = PKCS11_CTX_new();
+	if (PKCS11_CTX_load(ctx, module) < 0) {
+		fprintf(stderr, "unable to load module %s\n", module);
+		return 0;
+	}
+	return 1;
+}
+
+int pkcs11_rsa_finish(RSA * rsa)
+{
+	if (pin) {
+		free(pin);
+		pin = NULL;
+	}
+	if (!default_module && module) {
+		free(module);
+	}
+	/* need to free RSA_ex_data? */
+	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;
+		char c;
+
+		while (nybbles-- && *in && *in != ':') {
+			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--;
+		c++;
+	}
+
+	*outlen = count;
+	return 1;
+}
+
+#define MAX_VALUE_LEN	200
+
+/* prototype for OpenSSL ENGINE_load_cert */
+/* used by load_cert_ctrl via ENGINE_ctrl for now */
+
+X509 *pkcs11_load_cert(ENGINE * e, const char *s_slot_cert_id)
+{
+	PKCS11_SLOT *slot_list, *slot;
+	PKCS11_TOKEN *tok;
+	PKCS11_CERT *certs, *selected_cert = NULL;
+	X509 *x509;
+	unsigned int count, n, m;
+	unsigned char cert_id[MAX_VALUE_LEN / 2];
+	char *s_cert_id = NULL, buf[MAX_VALUE_LEN];
+	size_t cert_id_len = sizeof(cert_id);
+	int slot_nr = -1;
+	char flags[64];
+
+	/* Parse s_slot_cert_id: [slot_<slotNr>][-][id_<certID>] or NULL,
+	   with slotNr in decimal (0 = first slot, ...), and certID in hex.
+	    E.g."slot_1" or "id_46" or "slot_1-id_46 */
+	while (s_slot_cert_id != NULL && *s_slot_cert_id != '\0') {
+		char *p_sep1, *p_sep2;
+		char val[MAX_VALUE_LEN];
+		int val_len;;
+
+		p_sep1 = strchr(s_slot_cert_id, '_');
+		if (p_sep1 == NULL) {
+			fprintf(stderr,"No \'_\' found in \"-cert\" option \"%s\"\n", s_slot_cert_id);
+			fprintf(stderr,"Format: [slot_<slotNr>][-][id_<certID>]\n");
+			fprintf(stderr,"  with slotNr = 0, 1, ... and certID = a hex string\n");
+			return NULL;
+		}
+
+		p_sep2 = strchr(p_sep1, '-');
+		if (p_sep2 == NULL)
+			p_sep2 = p_sep1 + strlen(p_sep1);
+
+		/* val = the string between the _ and the - (or '\0') */
+		val_len = p_sep2 - p_sep1 - 1;
+		if (val_len >= MAX_VALUE_LEN || val_len == 0)
+			fail("Too long or empty value after the \'-\' sign\n");
+		memcpy(val, p_sep1 + 1, val_len);
+		val[val_len] = '\0';
+ 		if (strncasecmp(s_slot_cert_id, "slot", p_sep1 - s_slot_cert_id) == 0) {
+			if (val_len >= 3) {
+				fprintf(stderr,"Slot number \"%s\" should be a small integer\n", val);
+				return NULL;
+			}
+			slot_nr = atoi(val);
+			if (slot_nr == 0 && val[0] != '0') {
+				fprintf(stderr,"Slot number \"%s\" should be an integer\n", val);
+				return NULL;
+			}
+		} else if (strncasecmp(s_slot_cert_id, "id", p_sep1 - s_slot_cert_id)
+			   == 0) {
+			if (!hex_to_bin(val, cert_id, &cert_id_len)) {
+				fprintf(stderr,"cert id \"%s\" should be a hex string\n", val);
+				return NULL;
+			}
+			strcpy(buf, val);
+			s_cert_id = buf;
+		} else {
+			memcpy(val, s_slot_cert_id, p_sep1 - s_slot_cert_id);
+			val[p_sep1 - s_slot_cert_id] = '\0';
+			fprintf(stderr,"Now allowed in -cert: \"%s\"\n", val);
+			return NULL;
+		}
+		s_slot_cert_id = (*p_sep2 == '\0' ? p_sep2 : p_sep2 + 1);
+	}
+
+	if (PKCS11_enumerate_slots(ctx, &slot_list, &count) < 0)
+		fail("failed to enumerate slots\n");
+
+	if(verbose) {
+		fprintf(stderr,"Found %u slot%s\n", count, (count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < 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(verbose) {
+			fprintf(stderr,"[%u] %-25.25s  %-16s", n, slot->description, flags);
+			if (slot->token) {
+				fprintf(stderr,"  (%s)",
+				       slot->token->label[0] ?
+				       slot->token->label : "no label");
+			}
+			fprintf(stderr,"\n");
+		}
+	}
+
+	if (slot_nr == -1) {
+		if (!(slot = PKCS11_find_token(ctx)))
+			fail("didn't find any tokens\n");
+	} else if (slot_nr >= 0 && slot_nr < count)
+		slot = slot_list + slot_nr;
+	else {
+		fprintf(stderr,"Invalid slot number: %d\n", slot_nr);
+		return NULL;
+	}
+	tok = slot->token;
+
+	if (tok == NULL) {
+		fprintf(stderr,"Found empty token; \n");
+		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, &count)) {
+		fail("unable to enumerate certificates\n");
+
+		return NULL;
+	}
+
+	if(verbose) {
+		fprintf(stderr,"Found %u cert%s:\n", count, (count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < count; n++) {
+		PKCS11_CERT *k = certs + n;
+
+		if (cert_id_len != 0 && k->id_len == cert_id_len &&
+		    memcmp(k->id, cert_id, cert_id_len) == 0) {
+			if(verbose) {
+				fprintf(stderr,"        ID = %s\n", s_cert_id);
+			}
+			selected_cert = k;
+		}
+	}
+
+	if (selected_cert == NULL) {
+		if (s_cert_id != NULL) {
+			fprintf(stderr,"No cert with ID \"%s\" found.\n", s_cert_id);
+			return NULL;
+		} else		/* Take the first cert that was found */
+			selected_cert = &certs[0];
+	}
+
+	x509 = X509_dup(selected_cert->x509);
+
+	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;
+}
+
+
+EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
+			  UI_METHOD * ui_method, void *callback_data, int isPrivate)
+{
+	PKCS11_SLOT *slot_list, *slot;
+	PKCS11_TOKEN *tok;
+	PKCS11_KEY *keys, *selected_key = NULL;
+	PKCS11_CERT *certs;
+	EVP_PKEY *pk;
+	unsigned int count, n, m;
+	unsigned char key_id[MAX_VALUE_LEN / 2];
+	char *s_key_id = NULL, buf[MAX_VALUE_LEN];
+	size_t key_id_len = sizeof(key_id);
+	int slot_nr = -1;
+	char flags[64];
+
+	/* Parse s_slot_key_id: [slot_<slotNr>][-][id_<keyID>] or NULL,
+	   with slotNr in decimal (0 = first slot, ...), and keyID in hex.
+	   E.g. "slot_1" or "id_46" or "slot_1-id_46 */
+	while (s_slot_key_id != NULL && *s_slot_key_id != '\0') {
+		char *p_sep1, *p_sep2;
+		char val[MAX_VALUE_LEN];
+		int val_len;;
+
+		p_sep1 = strchr(s_slot_key_id, '_');
+		if (p_sep1 == NULL) {
+			fprintf(stderr,"No \'_\' found in \"-key\" option \"%s\"\n", s_slot_key_id);
+			fprintf(stderr,"Format: [slot_<slotNr>][-][id_<keyID>]\n");
+			fprintf(stderr,"  with slotNr = 0, 1, ... and keyID = a hex string\n");
+			return NULL;
+		}
+
+		p_sep2 = strchr(p_sep1, '-');
+		if (p_sep2 == NULL)
+			p_sep2 = p_sep1 + strlen(p_sep1);
+
+		/* val = the string between the _ and the - (or '\0') */
+		val_len = p_sep2 - p_sep1 - 1;
+		if (val_len >= MAX_VALUE_LEN || val_len == 0)
+			fail("Too long or empty value after the \'-\' sign\n");
+		memcpy(val, p_sep1 + 1, val_len);
+		val[val_len] = '\0';
+
+		if (strncasecmp(s_slot_key_id, "slot", p_sep1 - s_slot_key_id) == 0) {
+			if (val_len >= 3) {
+				fprintf(stderr,"Slot number \"%s\" should be a small integer\n", val);
+				return NULL;
+			}
+			slot_nr = atoi(val);
+			if (slot_nr == 0 && val[0] != '0') {
+				fprintf(stderr,"Slot number \"%s\" should be an integer\n", val);
+				return NULL;
+			}
+		} else if (strncasecmp(s_slot_key_id, "id", p_sep1 - s_slot_key_id)
+			   == 0) {
+			if (!hex_to_bin(val, key_id, &key_id_len)) {
+				fprintf(stderr,"Key id \"%s\" should be a hex string\n", val);
+				return NULL;
+			}
+			strcpy(buf, val);
+			s_key_id = buf;
+		} else {
+			memcpy(val, s_slot_key_id, p_sep1 - s_slot_key_id);
+			val[p_sep1 - s_slot_key_id] = '\0';
+			fprintf(stderr,"Now allowed in -key: \"%s\"\n", val);
+			return NULL;
+		}
+		s_slot_key_id = (*p_sep2 == '\0' ? p_sep2 : p_sep2 + 1);
+	}
+
+	if (PKCS11_enumerate_slots(ctx, &slot_list, &count) < 0)
+		fail("failed to enumerate slots\n");
+
+	if(verbose) {
+		fprintf(stderr,"Found %u slot%s\n", count, (count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < 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(verbose) {
+			fprintf(stderr,"[%u] %-25.25s  %-16s", n, slot->description, flags);
+			if (slot->token) {
+				fprintf(stderr,"  (%s)",
+				       slot->token->label[0] ?
+				       slot->token->label : "no label");
+			}
+			fprintf(stderr,"\n");
+		}
+	}
+
+	if (slot_nr == -1) {
+		if (!(slot = PKCS11_find_token(ctx)))
+			fail("didn't find any tokens\n");
+	} else if (slot_nr >= 0 && slot_nr < count)
+		slot = slot_list + slot_nr;
+	else {
+		fprintf(stderr,"Invalid slot number: %d\n", slot_nr);
+		return NULL;
+	}
+	tok = slot->token;
+
+	if (tok == NULL) {
+		fprintf(stderr,"Found empty token; \n");
+		return NULL;
+	}
+/* Removed for interop with some other pkcs11 libs. */
+#if 0
+	if (!tok->initialized) {
+		fprintf(stderr,"Found uninitialized token; \n");
+		return NULL;
+	}
+#endif
+	if (isPrivate && !tok->userPinSet && !tok->readOnly) {
+		fprintf(stderr,"Found slot without user PIN\n");
+		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, &count))
+		fail("unable to enumerate certificates\n");
+
+	if(verbose) {
+		fprintf(stderr,"Found %u certificate%s:\n", count, (count <= 1) ? "" : "s");
+		for (n = 0; n < 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");
+		}
+	}
+
+        /* Perform login to the token if required */
+        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, via set_pin */
+			if (pin != NULL) {
+				OPENSSL_cleanse(pin, strlen(pin));
+				free (pin);
+				pin = NULL;
+			}
+                }
+                else if (pin == NULL) {
+                        pin = (char *) calloc(MAX_PIN_LENGTH, sizeof(char));
+                        if (pin == NULL) {
+                                fail("Could not allocate memory for PIN");
+                        }        
+                        get_pin(ui_method, callback_data, pin, MAX_PIN_LENGTH);
+                }
+                
+                /* Now login in with the (possibly NULL) pin */
+                if (PKCS11_login(slot, 0, pin)) {
+                        /* Login failed, so free the PIN if present */
+                        if(pin != NULL) {
+				OPENSSL_cleanse(pin, strlen(pin));
+                                free(pin);
+                                pin = NULL;
+                        }
+                        fail("Login failed\n");
+                }
+                /* 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 */
+        }
+        
+        /* Make sure there is at least one private key on the token */
+        if (PKCS11_enumerate_keys(tok, &keys, &count)) {
+                fail("unable to enumerate keys\n");
+        }
+	if (count == 0) {
+		fail("No keys found.\n");
+	}
+
+	if(verbose) {
+		fprintf(stderr,"Found %u key%s:\n", count, (count <= 1) ? "" : "s");
+	}
+	for (n = 0; n < 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_id_len != 0 && k->id_len == key_id_len &&
+		    memcmp(k->id, key_id, key_id_len) == 0) {
+			if(verbose) {
+				fprintf(stderr,"        ID = %s\n", s_key_id);
+			}
+			selected_key = k;
+		}
+	}
+
+	if (selected_key == NULL) {
+		if (s_key_id != NULL) {
+			fprintf(stderr,"No key with ID \"%s\" found.\n", s_key_id);
+			return NULL;
+		} else		/* Take the first key that was found */
+			selected_key = &keys[0];
+	}
+
+	if (isPrivate) {
+		pk = PKCS11_get_private_key(selected_key);
+	} else {
+		/*pk = PKCS11_get_public_key(&keys[0]);
+		   need a get_public_key? */
+		pk = PKCS11_get_private_key(selected_key);
+	}
+
+	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)
+		fail("PKCS11_load_public_key returned NULL\n");
+	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)
+		fail("PKCS11_get_private_key returned NULL\n");
+	return pk;
+}
diff --git a/src/engine_pkcs11.def b/src/engine_pkcs11.def
new file mode 100644
index 0000000..2a38483
--- /dev/null
+++ b/src/engine_pkcs11.def
@@ -0,0 +1,4 @@
+LIBRARY engine_pkcs11
+EXPORTS
+    v_check
+    bind_engine
diff --git a/src/engine_pkcs11.h b/src/engine_pkcs11.h
new file mode 100644
index 0000000..4b03998
--- /dev/null
+++ b/src/engine_pkcs11.h
@@ -0,0 +1,59 @@
+/*
+ * 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
+
+#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 load_cert_ctrl(ENGINE *e, void *p);
+
+int inc_verbose();
+
+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);
+
+/* defined in p11_rsa.c */
+RSA_METHOD *pkcs11_get_rsa_method(void);
+
+#endif
diff --git a/src/hw_opensc.c b/src/hw_opensc.c
new file mode 100644
index 0000000..a05d239
--- /dev/null
+++ b/src/hw_opensc.c
@@ -0,0 +1,215 @@
+/* crypto/engine/hw_opensc.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).
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <openssl/engine.h>
+#ifndef ENGINE_CMD_BASE
+#error did not get engine.h
+#endif
+#include <openssl/crypto.h>
+#include <openssl/dso.h>
+#include <opensc/opensc.h>
+#include <opensc/pkcs15.h>
+#include "engine_opensc.h"
+
+#define OPENSC_ENGINE_ID "opensc"
+#define OPENSC_ENGINE_NAME "opensc engine"
+
+#define CMD_SO_PATH		ENGINE_CMD_BASE
+#define CMD_PIN			(ENGINE_CMD_BASE+1)
+
+static int opensc_engine_destroy(ENGINE * e);
+static int opensc_engine_init(ENGINE * e);
+static int opensc_engine_finish(ENGINE * e);
+static int opensc_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 opensc_cmd_defns[] = {
+	{CMD_SO_PATH,
+	 "SO_PATH",
+	 "Specifies the path to the 'opensc-engine' shared library",
+	 ENGINE_CMD_FLAG_STRING},
+	{CMD_PIN,
+	 "PIN",
+	 "Specifies the pin code",
+	 ENGINE_CMD_FLAG_STRING},
+	{0, NULL, NULL, 0}
+};
+
+static int opensc_engine_finish(ENGINE * e)
+{
+	return opensc_finish();
+}
+
+static int opensc_engine_init(ENGINE * e)
+{
+	return opensc_init();
+}
+
+/* Destructor */
+static int opensc_engine_destroy(ENGINE * e)
+{
+	return 1;
+}
+
+static int opensc_engine_ctrl(ENGINE * e, int cmd, long i, void *p, void (*f) ())
+{
+	switch (cmd) {
+	case CMD_PIN:
+		return set_pin((const char *) p);
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* set up default rsa_meth_st with overloaded rsa functions */
+/* the actual implementation needs to be in another object */
+
+static int (*orig_finish) (RSA * rsa);
+
+static int opensc_engine_rsa_finish(RSA * rsa)
+{
+	opensc_rsa_finish(rsa);
+
+	if (orig_finish)
+		orig_finish(rsa);
+	return 1;
+}
+
+static RSA_METHOD *sc_get_rsa_method(void)
+{
+	static RSA_METHOD smart_rsa;
+	const RSA_METHOD *def = RSA_get_default_method();
+
+	/* use the OpenSSL version */
+	memcpy(&smart_rsa, def, sizeof(smart_rsa));
+
+	smart_rsa.name = "opensc";
+
+	/* overload */
+	smart_rsa.rsa_priv_enc = sc_private_encrypt;
+	smart_rsa.rsa_priv_dec = sc_private_decrypt;
+	smart_rsa.rsa_sign = sc_sign;
+
+	/* save original */
+	orig_finish = def->finish;
+	smart_rsa.finish = opensc_engine_rsa_finish;
+
+	/* set flags for sign version */
+	smart_rsa.flags |= RSA_FLAG_SIGN_VER;
+	return &smart_rsa;
+}
+
+/* This internal function is used by ENGINE_opensc() and possibly by the
+ * "dynamic" ENGINE support too */
+static int bind_helper(ENGINE * e)
+{
+	if (!ENGINE_set_id(e, OPENSC_ENGINE_ID) ||
+	    !ENGINE_set_destroy_function(e, opensc_engine_destroy) ||
+	    !ENGINE_set_init_function(e, opensc_engine_init) ||
+	    !ENGINE_set_finish_function(e, opensc_engine_finish) ||
+	    !ENGINE_set_ctrl_function(e, opensc_engine_ctrl) ||
+	    !ENGINE_set_cmd_defns(e, opensc_cmd_defns) ||
+	    !ENGINE_set_name(e, OPENSC_ENGINE_NAME) ||
+#ifndef OPENSSL_NO_RSA
+	    !ENGINE_set_RSA(e, sc_get_rsa_method()) ||
+#endif
+#ifndef OPENSSL_NO_DSA
+	    !ENGINE_set_DSA(e, DSA_get_default_method()) ||
+#endif
+#ifndef OPENSSL_NO_DH
+	    !ENGINE_set_DH(e, DH_get_default_method()) ||
+#endif
+	    !ENGINE_set_RAND(e, RAND_SSLeay()) ||
+#if 0
+	    !ENGINE_set_BN_mod_exp(e, BN_mod_exp) ||
+#endif
+	    !ENGINE_set_load_pubkey_function(e, opensc_load_public_key) ||
+	    !ENGINE_set_load_privkey_function(e, opensc_load_private_key)) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+static int bind_fn(ENGINE * e, const char *id)
+{
+	if (id && (strcmp(id, OPENSC_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);
diff --git a/src/hw_pkcs11.c b/src/hw_pkcs11.c
new file mode 100644
index 0000000..9da606c
--- /dev/null
+++ b/src/hw_pkcs11.c
@@ -0,0 +1,204 @@
+/* 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 <libp11.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/engine.h>
+#ifndef ENGINE_CMD_BASE
+#error did not get engine.h
+#endif
+#include <openssl/crypto.h>
+#include <openssl/dso.h>
+#include "engine_pkcs11.h"
+
+#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)
+
+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},
+	{0, NULL, NULL, 0}
+};
+
+/* Destructor */
+static int pkcs11_engine_destroy(ENGINE * e)
+{
+	return 1;
+}
+
+static int pkcs11_engine_ctrl(ENGINE * e, int cmd, long i, void *p, void (*f) ())
+{
+	/*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);
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* set up default rsa_meth_st with overloaded rsa functions */
+/* the actual implementation needs to be in another object */
+
+static int (*orig_finish) (RSA * rsa);
+
+static int pkcs11_engine_rsa_finish(RSA * rsa)
+{
+
+	pkcs11_rsa_finish(rsa);
+
+	if (orig_finish)
+		orig_finish(rsa);
+	return 1;
+
+}
+
+/* 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_DSA
+	    !ENGINE_set_DSA(e, DSA_get_default_method()) ||
+#endif
+#ifndef OPENSSL_NO_DH
+	    !ENGINE_set_DH(e, DH_get_default_method()) ||
+#endif
+	    !ENGINE_set_RAND(e, RAND_SSLeay()) ||
+#if 0
+	    !ENGINE_set_BN_mod_exp(e, BN_mod_exp) ||
+#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);

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



More information about the pkg-opensc-commit mailing list