[pkg-opensc-commit] [opensc] 256/295: sc-hsm: Add support for SoC

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:37 UTC 2017


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

eric pushed a commit to branch master
in repository opensc.

commit 74ec7b04ffda539819eb8bfd6a0e766e69d8c946
Author: Frank Morgner <frankmorgner at gmail.com>
Date:   Thu Mar 23 16:45:31 2017 +0100

    sc-hsm: Add support for SoC
    
    - eac: allow CA without EF.CardSecurity
    - sc-hsm: implemented CA based on document PKI
    - sc-hsm: adds receive limit for SoC card
    - introduces dedicated card type for SoC card
    - md: integrate card's PIN pad capabilities
    - installer: added SC-HSM SoC card to registry
    - pkcs15-tool: Added support for PIN entry on card
    - change/unblock PIN: add support for PIN entry on card
    - added OpenPACE to macOS build
    - travis-ci: install gengetopt/help2man via brew
    - sc-hsm: Cache EF.C_DevAut
    - sc-hsm: Prevent unnecessary applet selection and state resets
    - sc-hsm: added support for session pin
    - sc-hsm: avoid multiple AID selection
    - sc-hsm: Use the information from match_card for all subsequent selections of the applet
    - sc-hsm: cache optional files as empty files (Decoding the files will reveal that they were not existing prior caching. This avoids selecting the file though we have already tried to cache the file before.)
    - use dedicated directory for CVC trust anchors
    - appveyor: added OpenPACE to windows build
---
 .travis.yml                   |   3 +-
 MacOSX/build-package.in       |  15 ++
 appveyor.yml                  |  15 +-
 configure.ac                  |  22 +-
 etc/DESRCACC100001            | Bin 0 -> 441 bytes
 etc/Makefile.am               |  13 +-
 etc/UTSRCACC100001            | Bin 0 -> 441 bytes
 src/libopensc/Makefile.am     |   4 +-
 src/libopensc/Makefile.mak    |   1 +
 src/libopensc/card-sc-hsm.c   | 604 ++++++++++++++++++++++++++++++++++++++----
 src/libopensc/card-sc-hsm.h   |   3 +
 src/libopensc/cards.h         |   1 +
 src/libopensc/ctx.c           |   2 +-
 src/libopensc/iso7816.c       |   2 +
 src/libopensc/opensc.h        |   7 +
 src/libopensc/pkcs15-pin.c    |  17 +-
 src/libopensc/pkcs15-sc-hsm.c |  88 ++++--
 src/libopensc/pkcs15-syn.c    |   1 +
 src/libopensc/types.h         |   1 +
 src/minidriver/Makefile.mak   |   2 +-
 src/minidriver/minidriver.c   |  21 +-
 src/pkcs11/Makefile.mak       |   6 +-
 src/pkcs11/framework-pkcs15.c |   8 +-
 src/sm/sm-eac.c               |  63 ++++-
 src/sm/sm-eac.h               |   2 +
 src/smm/Makefile.mak          |   2 +-
 src/tools/npa-tool.c          |   2 +-
 src/tools/pkcs15-tool.c       |   6 +-
 win32/Make.rules.mak          |   7 +-
 win32/OpenSC.wxs.in           |  14 +
 win32/customactions.cpp       |   2 +
 win32/winconfig.h.in          |   4 +
 32 files changed, 822 insertions(+), 116 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 9942ca5..2873491 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,7 @@ addons:
     - wine
     - xsltproc
     - gengetopt
+    - help2man
   coverity_scan:
     project:
       name: "OpenSC/OpenSC"
@@ -51,7 +52,7 @@ before_install:
         brew update;
         brew uninstall libtool;
         brew install libtool;
-        brew install gengetopt;
+        brew install gengetopt help2man;
     fi
 
 before_script:
diff --git a/MacOSX/build-package.in b/MacOSX/build-package.in
index 551d6ca..e0ab9fb 100755
--- a/MacOSX/build-package.in
+++ b/MacOSX/build-package.in
@@ -40,9 +40,24 @@ if ! pkg-config libcrypto --atleast-version=1.0.1; then
 	export OPENSSL_LIBS="`  env PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openssl_bin pkg-config --static --libs   libcrypto`"
 fi
 
+if ! test -e $BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig; then
+	if ! test -e openpace; then
+		git clone --depth=1 https://github.com/frankmorgner/openpace.git
+	fi
+	cd openpace
+	autoreconf -vis
+	./configure --disable-shared --prefix=$PREFIX CRYPTO_CFLAGS="$OPENSSL_CFLAGS" CRYPTO_LIBS="$OPENSSL_LIBS"
+	make DESTDIR=$BUILDPATH/openpace_bin install
+	cd ..
+	export OPENPACE_CFLAGS="`env PKG_CONFIG_PATH=$BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openpace_bin pkg-config --static --cflags libeac` $OPENSSL_CFLAGS"
+	export OPENPACE_LIBS="`  env PKG_CONFIG_PATH=$BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openpace_bin pkg-config --static --libs   libeac` $OPENSSL_LIBS"
+fi
+
 if ! test -e ${BUILDPATH}/target/$PREFIX/lib/pkgconfig; then
 	./configure --prefix=$PREFIX \
 		--sysconfdir=$PREFIX/etc \
+		--enable-cvcdir=$PREFIX/etc/cvc \
+		--enable-x509dir=$PREFIX/etc/x509 \
 		--disable-dependency-tracking \
 		--enable-shared \
 		--disable-static \
diff --git a/appveyor.yml b/appveyor.yml
index a599e52..ae8c330 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -30,6 +30,7 @@ install:
   - date /T & time /T
   - set PATH=C:\cygwin\bin;%PATH%
   - set OPENSSL_VER=1_0_2e
+  - set OPENPACE_VER=1.0.1
   - set ZLIB_VER_DOT=1.2.8
   - ps: $env:PACKAGE_NAME=(git describe --tags)
   - ps: >-
@@ -62,6 +63,11 @@ install:
         }
         7z x zlib.zip -oC:\
         Rename-Item -path "c:\zlib-${env:ZLIB_VER_DOT}" -newName "zlib"
+        If (!(Test-Path openpace.zip )) {
+          appveyor DownloadFile "https://github.com/frankmorgner/openpace/archive/${env:OPENPACE_VER}.zip" -FileName openpace.zip
+        }
+        7z x openpace.zip -oC:\
+        Rename-Item -path "c:\openpace-${env:OPENPACE_VER}" -newName "openpace"
       }
   - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
   - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%"
@@ -72,9 +78,9 @@ install:
   - set
 
 build_script:
-  # build zlib.lib as a static library
   - ps: >-
       if (!($env:Configuration -Like "*Light*")) {
+          # build zlib.lib as a static library
           cd C:\zlib
           (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc
           If ($env:Platform -Match "x86") {
@@ -83,7 +89,12 @@ build_script:
              nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" zlib.lib
           }
           $env:NMAKE_EXTRA="ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ${env:NMAKE_EXTRA}"
-          cd c:\projects\Opensc
+          # build libeac.lib as a static library
+          cd C:\openpace\src
+          cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c
+          lib /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj
+          $env:NMAKE_EXTRA="OPENPACE_DEF=/DENABLE_OPENPACE ${env:NMAKE_EXTRA}"
+          cd C:\projects\OpenSC
       }
   - bash -c "exec 0</dev/null && ./bootstrap"
   # disable features to speed up the script
diff --git a/configure.ac b/configure.ac
index 182bb69..d574e75 100644
--- a/configure.ac
+++ b/configure.ac
@@ -609,10 +609,18 @@ if test "${cvcdir}" = false ; then
     cvcdir="`$PKG_CONFIG libeac --variable=cvcdir`"
 fi
 if test "${cvcdir}" = "" ; then
-    AC_MSG_WARN([use --enable-cvcdir=DIR])
+	case "${host}" in
+		*-mingw*|*-winnt*|*-cygwin*)
+			cvcdir="%PROGRAMFILES%\\\OpenSC Project\\\OpenSC\\\cvc"
+			;;
+		*)
+			AC_MSG_WARN([use --enable-cvcdir=DIR])
+			;;
+	esac
 fi
 CVCDIR="${cvcdir}"
 AC_SUBST(CVCDIR)
+AC_DEFINE_UNQUOTED([CVCDIR], ["${CVCDIR}"], [CVC directory])
 
 AC_ARG_ENABLE(x509dir,
               AC_HELP_STRING([--enable-x509dir=DIR],
@@ -628,10 +636,18 @@ then
 fi
 if test -z "${x509dir}"
 then
-    AC_MSG_WARN([use --enable-x509dir=DIR])
+	case "${host}" in
+		*-mingw*|*-winnt*|*-cygwin*)
+			x509dir="%PROGRAMFILES%\\\OpenSC Project\\\OpenSC\\\x509"
+			;;
+		*)
+			AC_MSG_WARN([use --enable-x509dir=DIR])
+			;;
+	esac
 fi
 X509DIR="${x509dir}"
 AC_SUBST(X509DIR)
+AC_DEFINE_UNQUOTED([X509DIR], ["${X509DIR}"], [CVC directory])
 
 case "${enable_openpace}" in
 	no)
@@ -905,7 +921,9 @@ AM_CONDITIONAL([ENABLE_THREAD_LOCKING], [test "${enable_thread_locking}" = "yes"
 AM_CONDITIONAL([ENABLE_ZLIB], [test "${enable_zlib}" = "yes"])
 AM_CONDITIONAL([ENABLE_READLINE], [test "${enable_readline}" = "yes"])
 AM_CONDITIONAL([ENABLE_OPENSSL], [test "${enable_openssl}" = "yes"])
+AM_CONDITIONAL([ENABLE_OPENPACE], [test "${enable_openpace}" = "yes"])
 AM_CONDITIONAL([ENABLE_CRYPTOTOKENKIT], [test "${enable_cryptotokenkit}" = "yes"])
+AM_CONDITIONAL([ENABLE_OPENCT], [test "${enable_openct}" = "yes"])
 AM_CONDITIONAL([ENABLE_DOC], [test "${enable_doc}" = "yes"])
 AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"])
 AM_CONDITIONAL([CYGWIN], [test "${CYGWIN}" = "yes"])
diff --git a/etc/DESRCACC100001 b/etc/DESRCACC100001
new file mode 100644
index 0000000..50c2ed9
Binary files /dev/null and b/etc/DESRCACC100001 differ
diff --git a/etc/Makefile.am b/etc/Makefile.am
index fcd2286..e4183e6 100644
--- a/etc/Makefile.am
+++ b/etc/Makefile.am
@@ -1,7 +1,9 @@
+CV_CERTS = UTSRCACC100001 DESRCACC100001
+
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
 DISTCLEANFILES = opensc.conf
 
-EXTRA_DIST = Makefile.mak
+EXTRA_DIST = $(CV_CERTS) Makefile.mak
 
 SUFFIXES = .in
 
@@ -38,3 +40,12 @@ install-exec-hook: opensc.conf
 
 uninstall-hook: opensc.conf
 	rm -f "$(DESTDIR)$(sysconfdir)/opensc.conf.new" "$(DESTDIR)$(sysconfdir)/opensc.conf"
+
+if ENABLE_OPENPACE
+install-data-local:
+	$(MKDIR_P) "$(DESTDIR)$(CVCDIR)"
+	for cert in $(CV_CERTS);   do $(INSTALL_DATA) $(srcdir)/$${cert} "$(DESTDIR)$(CVCDIR)";  done
+
+uninstall-local:
+	for cert in $(CV_CERTS);   do rm -f "$(DESTDIR)$(CVCDIR)/$${cert}";  done
+endif
diff --git a/etc/UTSRCACC100001 b/etc/UTSRCACC100001
new file mode 100644
index 0000000..4f0621a
Binary files /dev/null and b/etc/UTSRCACC100001 differ
diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am
index 269cbf0..6dc37c3 100644
--- a/src/libopensc/Makefile.am
+++ b/src/libopensc/Makefile.am
@@ -73,8 +73,8 @@ libopensc_static_la_SOURCES = $(libopensc_la_SOURCES_BASE)
 if WIN32
 libopensc_la_SOURCES += $(top_builddir)/win32/versioninfo.rc
 endif
-libopensc_la_LIBADD = $(OPENPACE_LIBS) $(OPTIONAL_OPENSSL_LIBS) $(OPTIONAL_OPENCT_LIBS) \
-	$(OPTIONAL_ZLIB_LIBS) \
+libopensc_la_LIBADD = $(OPENPACE_LIBS) $(OPTIONAL_OPENSSL_LIBS) \
+	$(OPTIONAL_OPENCT_LIBS) $(OPTIONAL_ZLIB_LIBS) \
 	$(top_builddir)/src/pkcs15init/libpkcs15init.la \
 	$(top_builddir)/src/scconf/libscconf.la \
 	$(top_builddir)/src/common/libscdl.la \
diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak
index 4059536..00c2917 100644
--- a/src/libopensc/Makefile.mak
+++ b/src/libopensc/Makefile.mak
@@ -41,6 +41,7 @@ OBJECTS			= \
 LIBS = $(TOPDIR)\src\scconf\scconf.lib \
 	   $(TOPDIR)\src\common\common.lib \
 	   $(TOPDIR)\src\common\libscdl.lib \
+	   $(TOPDIR)\src\sm\libsmiso.lib \
 	   $(TOPDIR)\src\sm\libsmeac.lib \
 	   $(TOPDIR)\src\pkcs15init\pkcs15init.lib
 
diff --git a/src/libopensc/card-sc-hsm.c b/src/libopensc/card-sc-hsm.c
index a469abd..0ff9358 100644
--- a/src/libopensc/card-sc-hsm.c
+++ b/src/libopensc/card-sc-hsm.c
@@ -72,44 +72,108 @@ static struct sc_atr_table sc_hsm_jc_atrs[] = {
 	/* standard version */
 	{"3b:f8:13:00:00:81:31:fe:45:4a:43:4f:50:76:32:34:31:b7", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},	// JCOP 2.4.1 Default ATR contact based
 	{"3b:88:80:01:4a:43:4f:50:76:32:34:31:5e", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},	// JCOP 2.4.1 Default ATR contactless
+	{"3B:80:80:01:01", NULL, NULL, SC_CARD_TYPE_SC_HSM_SOC, 0, NULL},	// SoC Sample Card
 	{NULL, NULL, NULL, 0, 0, NULL}
 };
 
 
 
-static int sc_hsm_select_file(sc_card_t *card,
-			       const sc_path_t *in_path,
+static int sc_hsm_select_file_ex(sc_card_t *card,
+			       const sc_path_t *in_path, int forceselect,
 			       sc_file_t **file_out)
 {
 	int rv;
+	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
 	sc_file_t *file = NULL;
+	sc_path_t cpath;
 
 	if (file_out == NULL) {				// Versions before 0.16 of the SmartCard-HSM do not support P2='0C'
-		rv = sc_hsm_select_file(card, in_path, &file);
-		sc_file_free(file);
+		rv = sc_hsm_select_file_ex(card, in_path, forceselect, &file);
+		if (file != NULL) {
+			sc_file_free(file);
+		}
 		return rv;
 	}
 
-	if ((in_path->len == 2) && (in_path->value[0] == 0x3F) && (in_path->value[1] == 0x00)) {
-		// The SmartCard-HSM is an applet that is not default selected. Simulate selection of the MF
-		file = sc_file_new();
-		if (file == NULL)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
-		file->path = *in_path;
-		file->id = 0x3F00;
-		file->type = SC_FILE_TYPE_DF;
-		file->magic = SC_FILE_MAGIC;
+	if ((in_path->type == SC_PATH_TYPE_FILE_ID) && in_path->aid.len) {
+		// Split applet selection and file selection into two separate calls
+		cpath = *in_path;
+		cpath.len = 0;
+		cpath.type = SC_PATH_TYPE_DF_NAME;
+		rv = sc_hsm_select_file_ex(card, &cpath, forceselect, NULL);
+		LOG_TEST_RET(card->ctx, rv, "Could not select SmartCard-HSM application");
+
+		if (in_path->len) {
+			cpath = *in_path;
+			cpath.aid.len = 0;
+			rv = sc_hsm_select_file_ex(card, &cpath, forceselect, file_out);
+		}
+		return rv;
+	}
+
+	// Prevent selection of applet unless this is the first time, selection is forced or the device is not authenticated
+	if (in_path->type == SC_PATH_TYPE_DF_NAME
+			|| (in_path->type == SC_PATH_TYPE_PATH
+				&& in_path->len == sc_hsm_aid.len
+				&& !memcmp(in_path->value, sc_hsm_aid.value, sc_hsm_aid.len))
+			|| (in_path->type == SC_PATH_TYPE_PATH
+				&& in_path->len == 0
+				&& in_path->aid.len == sc_hsm_aid.len
+				&& !memcmp(in_path->aid.value, sc_hsm_aid.value, sc_hsm_aid.len))) {
+		if ((priv->dffcp == NULL) || forceselect) {
+			rv = (*iso_ops->select_file)(card, in_path, file_out);
+			LOG_TEST_RET(card->ctx, rv, "Could not select SmartCard-HSM application");
+
+			if (priv->dffcp != NULL) {
+				sc_file_free(priv->dffcp);
+			}
+			// Cache the FCP returned when selecting the applet
+			sc_file_dup(&priv->dffcp, *file_out);
+		} else {
+			sc_file_dup(file_out, priv->dffcp);
+			rv = SC_SUCCESS;
+		}
+		return rv;
+	}
 
-		*file_out = file;
-		return SC_SUCCESS;
+	if ((in_path->value[0] == 0x3F) && (in_path->value[1] == 0x00)) {
+		// The SmartCard-HSM is an applet that is not default selected. Simulate selection of the MF
+		if (in_path->len == 2) {
+			file = sc_file_new();
+			if (file == NULL)
+				LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+			file->path = *in_path;
+			file->id = 0x3F00;
+			file->type = SC_FILE_TYPE_DF;
+			file->magic = SC_FILE_MAGIC;
+
+			*file_out = file;
+			return SC_SUCCESS;
+		} else {
+			sc_path_t truncated;
+			memcpy(&truncated, in_path, sizeof truncated);
+			truncated.len = in_path->len - 2;
+			memcpy(truncated.value, in_path->value+2, truncated.len);
+			return (*iso_ops->select_file)(card, &truncated, file_out);
+		}
 	}
 	return (*iso_ops->select_file)(card, in_path, file_out);
 }
 
 
 
+static int sc_hsm_select_file(sc_card_t *card,
+			       const sc_path_t *in_path,
+			       sc_file_t **file_out)
+{
+	return sc_hsm_select_file_ex(card, in_path, 0, file_out);
+}
+
+
+
 static int sc_hsm_match_card(struct sc_card *card)
 {
+	sc_hsm_private_data_t *priv;
 	sc_path_t path;
 	int i, r;
 
@@ -121,10 +185,44 @@ static int sc_hsm_match_card(struct sc_card *card)
 	if (i < 0)
 		return 0;
 
+	priv = calloc(1, sizeof(sc_hsm_private_data_t));
+	if (!priv)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+
+	card->drv_data = priv;
+
 	sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
-	r = sc_hsm_select_file(card, &path, NULL);
+	r = (*iso_ops->select_file)(card, &path, &priv->dffcp);
 	LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application");
 
+	if (priv->dffcp) {
+		if (priv->dffcp->prop_attr && priv->dffcp->prop_attr_len >= 5) {
+			static char card_name[SC_MAX_APDU_BUFFER_SIZE];
+			u8 type = priv->dffcp->prop_attr[2];
+			u8 major = priv->dffcp->prop_attr[3];
+			u8 minor = priv->dffcp->prop_attr[4];
+			char p00[] = "SmartCard-HSM Applet for JCOP";
+			char p01[] = "SmartCard-HSM Demo Applet for JCOP";
+			char *p = "SmartCard-HSM";
+			switch (type) {
+				case 0x00:
+					p = p00;
+					break;
+				case 0x01:
+					p = p01;
+					break;
+				default:
+					break;
+			}
+			snprintf(card_name, sizeof card_name, "%s version %u.%u", p, major, minor);
+			card->name = card_name;
+
+			if (priv->dffcp->prop_attr[1] & 0x04) {
+				card->caps |= SC_CARD_CAP_SESSION_PIN;
+			}
+		}
+	}
+
 	// Select Applet to be sure
 	return 1;
 }
@@ -162,6 +260,258 @@ static int sc_hsm_encode_sopin(const u8 *sopin, u8 *sopinbin)
 }
 
 
+static int sc_hsm_soc_select_minbioclient(sc_card_t *card)
+{
+	sc_apdu_t apdu;
+	struct sc_aid minBioClient_aid = {
+		{ 0xFF,'m','i','n','B','i','o','C','l','i','e','n','t',0x01 }, 14
+	};
+
+	/* Select MinBioClient */
+	sc_sm_stop(card);
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
+	apdu.data = minBioClient_aid.value;
+	apdu.datalen = minBioClient_aid.len;
+	apdu.lc = minBioClient_aid.len;
+	LOG_TEST_RET(card->ctx,
+			sc_transmit_apdu(card, &apdu),
+			"APDU transmit failed");
+
+	return sc_check_sw(card, apdu.sw1, apdu.sw2);
+}
+
+static int sc_hsm_soc_change(sc_card_t *card, struct sc_pin_cmd_data *data,
+			   int *tries_left)
+{
+	sc_apdu_t apdu;
+	sc_path_t path;
+	int r;
+
+	/* Select MinBioClient */
+	r = sc_hsm_soc_select_minbioclient(card);
+	LOG_TEST_RET(card->ctx, r, "Could not select MinBioClient application");
+
+	/* verify PIN */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x80);
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Could not verify PIN");
+
+	/* change PIN */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x24, 0x01, 0x80);
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Could not change PIN");
+
+err:
+	/* Select SC-HSM */
+	sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
+	LOG_TEST_RET(card->ctx,
+			sc_hsm_select_file_ex(card, &path, 1, NULL),
+			"Could not select SmartCard-HSM application");
+
+	return r;
+}
+
+static int sc_hsm_soc_unblock(sc_card_t *card, struct sc_pin_cmd_data *data,
+			   int *tries_left)
+{
+	sc_apdu_t apdu;
+	sc_path_t path;
+	int r;
+
+	/* Select MinBioClient */
+	r = sc_hsm_soc_select_minbioclient(card);
+	LOG_TEST_RET(card->ctx, r, "Could not select MinBioClient application");
+
+	/* verify PUK */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x81);
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Could not verify PUK");
+
+	/* reset retry counter */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, 0x00);
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Could not unblock PIN");
+
+err:
+	/* Select SC-HSM */
+	sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
+	LOG_TEST_RET(card->ctx,
+			sc_hsm_select_file_ex(card, &path, 1, NULL),
+			"Could not select SmartCard-HSM application");
+
+	return r;
+}
+
+static int sc_hsm_soc_biomatch(sc_card_t *card, struct sc_pin_cmd_data *data,
+			   int *tries_left)
+{
+	sc_apdu_t apdu;
+	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
+	int r;
+
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, 0x85);
+	apdu.cla = 0x80;
+	apdu.data = (unsigned char*)"\x7F\x24\x00";
+	apdu.datalen = 3;
+	apdu.lc = 3;
+	apdu.resplen = 0;
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+	/* ignore the actual status bytes */
+
+	/* JCOP's SM accelerator is incapable of using case 1 APDU in SM */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x20, 0x00, 0x81);
+	apdu.resp = rbuf;
+	apdu.resplen = sizeof rbuf;
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	/* now check the status bytes */
+	r =  sc_check_sw(card, apdu.sw1, apdu.sw2);
+	if (r == SC_SUCCESS) {
+		LOG_FUNC_RETURN(card->ctx, r);
+	}
+
+	LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
+}
+
+
+
+#ifdef ENABLE_OPENPACE
+#include "sm/sm-eac.h"
+#include <eac/cv_cert.h>
+#include <eac/eac.h>
+#include <eac/ta.h>
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+
+static int sc_hsm_perform_chip_authentication(sc_card_t *card)
+{
+	int r, protocol;
+	sc_path_t path;
+	u8 all_certs[1024];
+	EAC_CTX *ctx = NULL;
+	size_t all_certs_len = sizeof all_certs, left, device_cert_len, issuer_cert_len;
+	const unsigned char *cert = all_certs, *device_cert, *issuer_cert;
+	BUF_MEM *comp_pub_key = NULL;
+	sc_cvc_t cvc_device, cvc_issuer;
+	/* this is only needed to call sc_pkcs15emu_sc_hsm_decode_cvc */
+	sc_pkcs15_card_t p15card;
+	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
+	/* we know that sc_pkcs15emu_sc_hsm_decode_cvc does not require anything
+	 * else to be initialized than p15card->card */
+	p15card.card = card;
+
+	memset(&cvc_device, 0, sizeof(cvc_device));
+	memset(&cvc_issuer, 0, sizeof(cvc_issuer));
+
+
+	if (priv->EF_C_DevAut && priv->EF_C_DevAut_len) {
+		all_certs_len = priv->EF_C_DevAut_len;
+		cert = priv->EF_C_DevAut;
+	} else {
+		/* get issuer and device certificate from the card */
+		r = sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x02", 2, 0, 0);
+		if (r < 0)
+			goto err;
+		r = sc_select_file(card, &path, NULL);
+		if (r < 0)
+			goto err;
+		r = sc_read_binary(card, 0, all_certs, all_certs_len, 0);
+		if (r < 0)
+			goto err;
+
+		all_certs_len = r;
+
+		/* save EF_C_DevAut for further use */
+		cert = realloc(priv->EF_C_DevAut, all_certs_len);
+		if (cert) {
+			memcpy((unsigned char *) cert, all_certs, all_certs_len);
+			priv->EF_C_DevAut = (unsigned char *) cert;
+			priv->EF_C_DevAut_len = all_certs_len;
+		}
+
+		cert = all_certs;
+	}
+	left = all_certs_len;
+
+	device_cert = cert;
+	r = sc_pkcs15emu_sc_hsm_decode_cvc(&p15card, &cert, &left, &cvc_device);
+	if (r < 0)
+		goto err;
+	device_cert_len = all_certs_len - left;
+
+	issuer_cert = cert;
+	r = sc_pkcs15emu_sc_hsm_decode_cvc(&p15card, &cert, &left, &cvc_issuer);
+	if (r < 0)
+		goto err;
+	issuer_cert_len = all_certs_len - device_cert_len - left;
+
+	ctx = EAC_CTX_new();
+	if (!ctx) {
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
+
+
+	/* check all CVCs given of the document's pki */
+	if (!TA_STEP2_import_certificate(ctx, issuer_cert, issuer_cert_len)
+			|| !TA_STEP2_import_certificate(ctx, device_cert, device_cert_len)) {
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
+
+	if (card->type == SC_CARD_TYPE_SC_HSM_SOC) {
+		/* SoC cards are known to be implemented on newer JCOPs */
+		protocol = NID_id_CA_ECDH_AES_CBC_CMAC_128;
+	} else {
+		/* Older cards may not support AES accelerator */
+		protocol = NID_id_CA_ECDH_3DES_CBC_CBC;
+	}
+
+	/* initialize CA domain parameter with the document's public key */
+	if (!EAC_CTX_init_ca(ctx, protocol, 8)) {
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
+	EVP_PKEY_free(ctx->ca_ctx->ka_ctx->key);
+	CRYPTO_add(&ctx->ta_ctx->pub_key->references, 1, CRYPTO_LOCK_EVP_PKEY);
+	ctx->ca_ctx->ka_ctx->key = ctx->ta_ctx->pub_key;
+
+	/* generate keys for CA */
+	comp_pub_key = TA_STEP3_generate_ephemeral_key(ctx);
+	r = perform_chip_authentication_ex(card, ctx,
+			cvc_device.publicPoint, cvc_device.publicPointlen);
+
+err:
+	if (r < 0)
+		EAC_CTX_clear_free(ctx);
+	if (comp_pub_key)
+		BUF_MEM_free(comp_pub_key);
+	sc_pkcs15emu_sc_hsm_free_cvc(&cvc_device);
+	sc_pkcs15emu_sc_hsm_free_cvc(&cvc_issuer);
+
+	return r;
+}
+
+#else
+
+static int sc_hsm_perform_chip_authentication(sc_card_t *card)
+{
+	return SC_ERROR_NOT_SUPPORTED;
+}
+#endif
+
+
 
 static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
 			   int *tries_left)
@@ -169,43 +519,132 @@ static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
 	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
 	sc_apdu_t apdu;
 	u8 cmdbuff[16];
+	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
 	int r;
+	int cmd = data->cmd;
+	size_t pin2_len = data->pin2.len;
+
+	if (cmd == SC_PIN_CMD_GET_SESSION_PIN) {
+		/* First, perform a standard VERIFY */
+		data->cmd = SC_PIN_CMD_VERIFY;
+		/* we assign pin2.len to 0 early on so that in case of an error we are
+		 * not exiting with an undefined session PIN */
+		data->pin2.len = 0;
+	}
 
-	if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) {
-		if (data->pin1.len != 16)
-			return SC_ERROR_INVALID_PIN_LENGTH;
-
-		// Save SO PIN for later use in sc_hsm_init_pin()
-		r = sc_hsm_encode_sopin(data->pin1.data, priv->sopin);
-		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+	if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)
+		   	&& (data->cmd == SC_PIN_CMD_CHANGE)
+		   	&& (data->pin_reference == 0x81)
+			&& (!data->pin1.data || data->pin1.len <= 0)) {
+		return sc_hsm_soc_change(card, data, tries_left);
+	} else if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)
+		   	&& (data->cmd == SC_PIN_CMD_UNBLOCK)
+		   	&& (data->pin_reference == 0x81)
+			&& (!data->pin1.data || data->pin1.len <= 0)) {
+		return sc_hsm_soc_unblock(card, data, tries_left);
+	}
 
-		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+	/* For contactless cards always establish a secure channel before PIN
+	 * verification */
+	if (card->type == SC_CARD_TYPE_SC_HSM_SOC
+			&& (data->cmd != SC_PIN_CMD_GET_INFO)
+			&& card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) {
+		LOG_TEST_RET(card->ctx,
+				sc_hsm_perform_chip_authentication(card),
+				"Could not perform chip authentication");
 	}
 
-	if ((data->cmd == SC_PIN_CMD_CHANGE) && (data->pin_reference == 0x88)) {
-		if ((data->pin1.len != 16) || (data->pin2.len != 16))
-			return SC_ERROR_INVALID_PIN_LENGTH;
+	if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)
+			&& (data->cmd == SC_PIN_CMD_VERIFY)
+			&& (data->pin_reference == 0x81)
+			&& (!data->pin1.data || data->pin1.len <= 0)) {
+		r = sc_hsm_soc_biomatch(card, data, tries_left);
+	} else {
+		if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) {
+			if (data->pin1.len != 16)
+				return SC_ERROR_INVALID_PIN_LENGTH;
 
-		r = sc_hsm_encode_sopin(data->pin1.data, cmdbuff);
-		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+			// Save SO PIN for later use in sc_hsm_init_pin()
+			r = sc_hsm_encode_sopin(data->pin1.data, priv->sopin);
+			LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 
-		r = sc_hsm_encode_sopin(data->pin2.data, cmdbuff + 8);
-		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+			LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+		}
 
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, data->pin_reference);
-		apdu.data = cmdbuff;
-		apdu.datalen = sizeof(cmdbuff);
-		apdu.lc = 16;
-		apdu.resplen = 0;
-		data->apdu = &apdu;
-	}
+		if ((data->cmd == SC_PIN_CMD_CHANGE) && (data->pin_reference == 0x88)) {
+			if ((data->pin1.len != 16) || (data->pin2.len != 16))
+				return SC_ERROR_INVALID_PIN_LENGTH;
+
+			r = sc_hsm_encode_sopin(data->pin1.data, cmdbuff);
+			LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+			r = sc_hsm_encode_sopin(data->pin2.data, cmdbuff + 8);
+			LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, data->pin_reference);
+			apdu.data = cmdbuff;
+			apdu.datalen = sizeof(cmdbuff);
+			apdu.lc = 16;
+			apdu.resplen = 0;
+			data->apdu = &apdu;
+		}
+
+		if ((data->cmd == SC_PIN_CMD_GET_INFO)
+				&& (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)) {
+			/* JCOP's SM accelerator is incapable of using case 1 APDU in SM */
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x20, 0x00, data->pin_reference);
+			apdu.resp = rbuf;
+			apdu.resplen = sizeof rbuf;
+			data->apdu = &apdu;
+		}
 
-	data->pin1.offset = 5;
-	data->pin1.length_offset = 4;
-	data->pin2.offset = 5;
-	data->pin2.length_offset = 4;
+		data->pin1.offset = 5;
+		data->pin1.length_offset = 4;
+		data->pin2.offset = 5;
+		data->pin2.length_offset = 4;
 
-	return (*iso_ops->pin_cmd)(card, data, tries_left);
+		r = (*iso_ops->pin_cmd)(card, data, tries_left);
+	}
+	LOG_TEST_RET(card->ctx, r, "Verification failed");
+
+	if (cmd == SC_PIN_CMD_GET_SESSION_PIN) {
+		/* reset data->cmd to its original value */
+		data->cmd = SC_PIN_CMD_GET_SESSION_PIN;
+		if (data->pin_reference == 0x81) {
+			u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
+			if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) {
+				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+						"Session PIN generation only supported in SM");
+				LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+			}
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x5A, 0x01, data->pin_reference);
+			apdu.cla = 0x80;
+			apdu.resp = recvbuf;
+			apdu.resplen = sizeof recvbuf;
+			apdu.le = 0;
+			if (sc_transmit_apdu(card, &apdu) != SC_SUCCESS
+					|| sc_check_sw(card, apdu.sw1, apdu.sw2) != SC_SUCCESS) {
+				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+						"Generating session PIN failed");
+				LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+			}
+			if (data->pin2.data && pin2_len > 0) {
+				if (pin2_len >= apdu.resplen) {
+					memcpy((unsigned char *) data->pin2.data, apdu.resp,
+							apdu.resplen);
+					data->pin2.len = apdu.resplen;
+				} else {
+					sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+							"Buffer too small for session PIN");
+				}
+			}
+		} else {
+			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+					"Session PIN not supported for this PIN (0x%02X)",
+					data->pin_reference);
+		}
+	}
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
 
@@ -215,10 +654,11 @@ static int sc_hsm_logout(sc_card_t * card)
 	sc_path_t path;
 	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
 	memset(priv->sopin, 0, sizeof(priv->sopin));
+	sc_sm_stop(card);
 
 	sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
 
-	return sc_hsm_select_file(card, &path, NULL);
+	return sc_hsm_select_file_ex(card, &path, 1, NULL);
 }
 
 
@@ -409,7 +849,6 @@ static int sc_hsm_delete_file(sc_card_t *card, const sc_path_t *path)
 }
 
 
-
 static int sc_hsm_set_security_env(sc_card_t *card,
 				   const sc_security_env_t *env,
 				   int se_num)
@@ -565,6 +1004,7 @@ static int sc_hsm_compute_signature(sc_card_t *card,
 	apdu.lc = datalen;
 	apdu.datalen = datalen;
 	r = sc_transmit_apdu(card, &apdu);
+
 	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
 		int len;
@@ -1029,17 +1469,17 @@ static int sc_hsm_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
 
 static int sc_hsm_init(struct sc_card *card)
 {
-	sc_hsm_private_data_t *priv;
+#ifdef _WIN32
+	char expanded_val[PATH_MAX];
+	size_t expanded_len = PATH_MAX;
+#endif
 	int flags,ext_flags;
+	sc_file_t *file;
+	sc_path_t path;
+	sc_hsm_private_data_t *priv = card->drv_data;
 
 	LOG_FUNC_CALLED(card->ctx);
 
-	priv = calloc(1, sizeof(sc_hsm_private_data_t));
-	if (!priv)
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
-
-	card->drv_data = priv;
-
 	flags = SC_ALGORITHM_RSA_RAW|SC_ALGORITHM_ONBOARD_KEY_GEN;
 
 	_sc_card_add_rsa_alg(card, 1024, flags, 0);
@@ -1066,8 +1506,56 @@ static int sc_hsm_init(struct sc_card *card)
 
 	card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT|SC_CARD_CAP_ISO7816_PIN_INFO;
 
+	sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
+	if (sc_hsm_select_file_ex(card, &path, 0, &file) == SC_SUCCESS
+			&& file->prop_attr && file->prop_attr_len >= 5) {
+		static char card_name[SC_MAX_APDU_BUFFER_SIZE];
+		u8 type = file->prop_attr[2];
+		u8 major = file->prop_attr[3];
+		u8 minor = file->prop_attr[4];
+		char p00[] = "SmartCard-HSM Applet for JCOP";
+		char p01[] = "SmartCard-HSM Demo Applet for JCOP";
+		char *p = "SmartCard-HSM";
+		switch (type) {
+			case 0x00:
+				p = p00;
+				break;
+			case 0x01:
+				p = p01;
+				break;
+			default:
+				break;
+		}
+		snprintf(card_name, sizeof card_name, "%s version %u.%u", p, major, minor);
+		card->name = card_name;
+
+		if (file->prop_attr[1] & 0x04) {
+			card->caps |= SC_CARD_CAP_SESSION_PIN;
+		}
+		sc_file_free(file);
+	}
+
 	card->max_send_size = 1431;		// 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY
-	card->max_recv_size = 0;		// Card supports sending with extended length APDU and without limit
+	if (card->type == SC_CARD_TYPE_SC_HSM_SOC) {
+		card->max_recv_size = 0x0630;	// SoC Proxy forces this limit
+	} else {
+		card->max_recv_size = 0;		// Card supports sending with extended length APDU and without limit
+	}
+
+	priv->EF_C_DevAut = NULL;
+	priv->EF_C_DevAut_len = 0;
+
+#ifdef ENABLE_OPENPACE
+	EAC_init();
+#ifdef _WIN32
+	expanded_len = ExpandEnvironmentStringsA(CVCDIR, expanded_val, sizeof expanded_val);
+	if (0 < expanded_len && expanded_len < sizeof expanded_val)
+		EAC_set_cvc_default_dir(expanded_val);
+#else
+	EAC_set_cvc_default_dir(CVCDIR);
+#endif
+#endif
+
 	return 0;
 }
 
@@ -1076,10 +1564,20 @@ static int sc_hsm_init(struct sc_card *card)
 static int sc_hsm_finish(sc_card_t * card)
 {
 	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
+	sc_sm_stop(card);
 	if (priv->serialno) {
 		free(priv->serialno);
 	}
+	if (priv->dffcp) {
+		sc_file_free(priv->dffcp);
+	}
+	free(priv->EF_C_DevAut);
 	free(priv);
+
+#ifdef ENABLE_OPENPACE
+	EAC_cleanup();
+#endif
+
 	return SC_SUCCESS;
 }
 
diff --git a/src/libopensc/card-sc-hsm.h b/src/libopensc/card-sc-hsm.h
index 325f73f..39efb46 100644
--- a/src/libopensc/card-sc-hsm.h
+++ b/src/libopensc/card-sc-hsm.h
@@ -56,10 +56,13 @@
 /* Information the driver maintains between calls */
 typedef struct sc_hsm_private_data {
 	const sc_security_env_t *env;
+	sc_file_t *dffcp;
 	u8 algorithm;
 	int noExtLength;
 	char *serialno;
 	u8 sopin[8];
+	u8 *EF_C_DevAut;
+	size_t EF_C_DevAut_len;
 } sc_hsm_private_data_t;
 
 
diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
index 992826c..691182f 100644
--- a/src/libopensc/cards.h
+++ b/src/libopensc/cards.h
@@ -204,6 +204,7 @@ enum {
 
 	/* SmartCard-HSM */
 	SC_CARD_TYPE_SC_HSM = 26000,
+	SC_CARD_TYPE_SC_HSM_SOC = 26001,
 
 	/* Spanish DNIe card */
 	SC_CARD_TYPE_DNIE_BASE = 27000,
diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c
index e74619a..2180171 100644
--- a/src/libopensc/ctx.c
+++ b/src/libopensc/ctx.c
@@ -338,7 +338,7 @@ load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options *
 #ifdef _WIN32
 		expanded_len = PATH_MAX;
 		expanded_len = ExpandEnvironmentStringsA(val, expanded_val, expanded_len);
-		if (expanded_len > 0)
+		if (0 < expanded_len && expanded_len < sizeof expanded_val)
 			val = expanded_val;
 #endif
 		sc_ctx_log_to_file(ctx, val);
diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c
index f0355a6..b1d2c91 100644
--- a/src/libopensc/iso7816.c
+++ b/src/libopensc/iso7816.c
@@ -999,6 +999,8 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu,
 
 	switch (data->pin_type) {
 	case SC_AC_CHV:
+		/* fall through */
+	case SC_AC_SESSION:
 		break;
 	default:
 		return SC_ERROR_INVALID_ARGUMENTS;
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index 3aff3d2..c96c410 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.h
@@ -342,6 +342,7 @@ typedef struct sc_reader {
 #define SC_PIN_CMD_CHANGE	1
 #define SC_PIN_CMD_UNBLOCK	2
 #define SC_PIN_CMD_GET_INFO	3
+#define SC_PIN_CMD_GET_SESSION_PIN	4
 
 #define SC_PIN_CMD_USE_PINPAD		0x0001
 #define SC_PIN_CMD_NEED_PADDING		0x0002
@@ -475,6 +476,12 @@ struct sc_reader_operations {
 #define SC_CARD_CAP_ONLY_RAW_HASH		0x00000040
 #define SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED	0x00000080
 
+/* Card (or card driver) supports an protected authentication mechanism */
+#define SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH	0x00000100
+
+/* Card (or card driver) supports generating a session PIN */
+#define SC_CARD_CAP_SESSION_PIN	0x00000200
+
 typedef struct sc_card {
 	struct sc_context *ctx;
 	struct sc_reader *reader;
diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c
index 17c7304..28a39b7 100644
--- a/src/libopensc/pkcs15-pin.c
+++ b/src/libopensc/pkcs15-pin.c
@@ -270,7 +270,9 @@ _validate_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_auth_info *auth_i
 		return SC_ERROR_BUFFER_TOO_SMALL;
 
 	/* if we use pinpad, no more checks are needed */
-	if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD && !pinlen)
+	if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)
+		   	&& !pinlen)
 		return SC_SUCCESS;
 
 	/* If pin is given, make sure it is within limits */
@@ -391,7 +393,9 @@ _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *p
 		data.pin_reference = skey_info->key_reference;
 	}
 
-	if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD && !pinlen) {
+	if((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)
+			&& !pinlen) {
 		data.flags |= SC_PIN_CMD_USE_PINPAD;
 
 		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
@@ -487,7 +491,8 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
 	}
 
 	if((!oldpin || !newpin)
-			&& p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
+			&& (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		data.flags |= SC_PIN_CMD_USE_PINPAD;
 		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
 			data.pin1.prompt = "Please enter SO PIN";
@@ -600,7 +605,8 @@ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card,
 		break;
 	}
 
-	if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
+	if((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		data.flags |= SC_PIN_CMD_USE_PINPAD;
 		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
 			data.pin1.prompt = "Please enter PUK";
@@ -743,7 +749,8 @@ sc_pkcs15_pincache_revalidate(struct sc_pkcs15_card *p15card, const sc_pkcs15_ob
 		return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
 	}
 
-	if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
+	if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH))
 		return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
 
 	r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj);
diff --git a/src/libopensc/pkcs15-sc-hsm.c b/src/libopensc/pkcs15-sc-hsm.c
index a0dd3bf..b71c939 100644
--- a/src/libopensc/pkcs15-sc-hsm.c
+++ b/src/libopensc/pkcs15-sc-hsm.c
@@ -181,7 +181,7 @@ static const struct sc_asn1_entry c_asn1_req[C_ASN1_REQ_SIZE] = {
 
 
 static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2],
-		u8 *efbin, size_t *len)
+		u8 *efbin, size_t *len, int optional)
 {
 	sc_path_t path;
 	int r;
@@ -196,12 +196,24 @@ static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2],
 		/* avoid re-selection of SC-HSM */
 		path.aid.len = 0;
 		r = sc_select_file(p15card->card, &path, NULL);
-		LOG_TEST_RET(p15card->card->ctx, r, "Could not select EF");
-
-		r = sc_read_binary(p15card->card, 0, efbin, *len, 0);
-		LOG_TEST_RET(p15card->card->ctx, r, "Could not read EF");
+		if (r < 0) {
+			sc_log(p15card->card->ctx, "Could not select EF");
+		} else {
+			r = sc_read_binary(p15card->card, 0, efbin, *len, 0);
+		}
 
-		*len = r;
+		if (r < 0) {
+			sc_log(p15card->card->ctx, "Could not read EF");
+			if (!optional) {
+				return r;
+			}
+			/* optional files are saved as empty files to avoid card
+			 * transactions. Parsing the file's data will reveal that they were
+			 * missing. */
+			*len = 0;
+		} else {
+			*len = r;
+		}
 
 		if (p15card->opts.use_file_cache) {
 			/* save this with our AID */
@@ -593,7 +605,7 @@ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) {
 
 	/* Try to select a related EF containing the PKCS#15 description of the key */
 	len = sizeof efbin;
-	r = read_file(p15card, fid, efbin, &len);
+	r = read_file(p15card, fid, efbin, &len, 1);
 	LOG_TEST_RET(card->ctx, r, "Could not read EF.PRKD");
 
 	ptr = efbin;
@@ -627,7 +639,8 @@ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) {
 	fid[0] = EE_CERTIFICATE_PREFIX;
 
 	len = sizeof efbin;
-	r = read_file(p15card, fid, efbin, &len);
+	r = read_file(p15card, fid, efbin, &len, 0);
+	LOG_TEST_RET(card->ctx, r, "Could not read EF");
 
 	LOG_TEST_RET(card->ctx, r, "Could not read EF");
 
@@ -683,7 +696,7 @@ static int sc_pkcs15emu_sc_hsm_add_dcod(sc_pkcs15_card_t * p15card, u8 id) {
 
 	/* Try to select a related EF containing the PKCS#15 description of the data */
 	len = sizeof efbin;
-	r = read_file(p15card, fid, efbin, &len);
+	r = read_file(p15card, fid, efbin, &len, 1);
 	LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD");
 
 	ptr = efbin;
@@ -722,7 +735,7 @@ static int sc_pkcs15emu_sc_hsm_add_cd(sc_pkcs15_card_t * p15card, u8 id) {
 
 	/* Try to select a related EF containing the PKCS#15 description of the data */
 	len = sizeof efbin;
-	r = read_file(p15card, fid, efbin, &len);
+	r = read_file(p15card, fid, efbin, &len, 1);
 	LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD");
 
 	ptr = efbin;
@@ -753,7 +766,7 @@ static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card)
 
 	/* Read token info */
 	len = sizeof efbin;
-	r = read_file(p15card, (u8 *) "\x2F\x03", efbin, &len);
+	r = read_file(p15card, (u8 *) "\x2F\x03", efbin, &len, 1);
 	LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo");
 
 	r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, len);
@@ -771,6 +784,7 @@ static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card)
 static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
 {
 	sc_card_t *card = p15card->card;
+	sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
 	sc_file_t *file = NULL;
 	sc_path_t path;
 	u8 filelist[MAX_EXT_APDU_LENGTH];
@@ -780,7 +794,8 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
 	struct sc_app_info *appinfo;
 	struct sc_pkcs15_auth_info pin_info;
 	struct sc_pkcs15_object pin_obj;
-	u8 efbin[512];
+	struct sc_pin_cmd_data pindata;
+	u8 efbin[1024];
 	u8 *ptr;
 	size_t len;
 
@@ -809,11 +824,24 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
 	sc_file_free(file);
 
 	/* Read device certificate to determine serial number */
-	len = sizeof efbin;
-	r = read_file(p15card, (u8 *) "\x2F\x02", efbin, &len);
-	LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut");
+	if (priv->EF_C_DevAut && priv->EF_C_DevAut_len) {
+		ptr = priv->EF_C_DevAut;
+		len = priv->EF_C_DevAut_len;
+	} else {
+		len = sizeof efbin;
+		r = read_file(p15card, (u8 *) "\x2F\x02", efbin, &len, 1);
+		LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut");
+
+		/* save EF_C_DevAut for further use */
+		ptr = realloc(priv->EF_C_DevAut, len);
+		if (ptr) {
+			memcpy(ptr, efbin, len);
+			priv->EF_C_DevAut = ptr;
+			priv->EF_C_DevAut_len = len;
+		}
 
-	ptr = efbin;
+		ptr = efbin;
+	}
 
 	memset(&devcert, 0 ,sizeof(devcert));
 	r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert);
@@ -883,7 +911,6 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
 	if (r < 0)
 		LOG_FUNC_RETURN(card->ctx, r);
 
-
 	memset(&pin_info, 0, sizeof(pin_info));
 	memset(&pin_obj, 0, sizeof(pin_obj));
 
@@ -909,6 +936,30 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
 		LOG_FUNC_RETURN(card->ctx, r);
 
 
+	if (card->type == SC_CARD_TYPE_SC_HSM_SOC) {
+		/* SC-HSM of this type always has a PIN-Pad */
+		r = SC_SUCCESS;
+	} else {
+		memset(&pindata, 0, sizeof(pindata));
+		pindata.cmd = SC_PIN_CMD_GET_INFO;
+		pindata.pin_type = SC_AC_CHV;
+		pindata.pin_reference = 0x85;
+
+		r = sc_pin_cmd(card, &pindata, NULL);
+	}
+	if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
+		memset(&pindata, 0, sizeof(pindata));
+		pindata.cmd = SC_PIN_CMD_GET_INFO;
+		pindata.pin_type = SC_AC_CHV;
+		pindata.pin_reference = 0x86;
+
+		r = sc_pin_cmd(card, &pindata, NULL);
+	}
+
+	if (r != SC_ERROR_DATA_OBJECT_NOT_FOUND)
+		card->caps |= SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH;
+
+
 	filelistlength = sc_list_files(card, filelist, sizeof(filelist));
 	LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier");
 
@@ -941,7 +992,8 @@ int sc_pkcs15emu_sc_hsm_init_ex(sc_pkcs15_card_t *p15card,
 	if (opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) {
 		return sc_pkcs15emu_sc_hsm_init(p15card);
 	} else {
-		if (p15card->card->type != SC_CARD_TYPE_SC_HSM) {
+		if (p15card->card->type != SC_CARD_TYPE_SC_HSM
+				&& p15card->card->type != SC_CARD_TYPE_SC_HSM_SOC) {
 			return SC_ERROR_WRONG_CARD;
 		}
 		return sc_pkcs15emu_sc_hsm_init(p15card);
diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c
index 0fdcbed..d72fc31 100644
--- a/src/libopensc/pkcs15-syn.c
+++ b/src/libopensc/pkcs15-syn.c
@@ -82,6 +82,7 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card)
 		case SC_CARD_TYPE_OPENPGP_V2:
 		case SC_CARD_TYPE_OPENPGP_GNUK:
 		case SC_CARD_TYPE_SC_HSM:
+		case SC_CARD_TYPE_SC_HSM_SOC:
 		case SC_CARD_TYPE_DNIE_BASE:
 		case SC_CARD_TYPE_DNIE_BLANK:
 		case SC_CARD_TYPE_DNIE_ADMIN:
diff --git a/src/libopensc/types.h b/src/libopensc/types.h
index 7368422..e665c54 100644
--- a/src/libopensc/types.h
+++ b/src/libopensc/types.h
@@ -148,6 +148,7 @@ struct sc_crt {
 #define SC_AC_SEN                       0x00000020 /* Security Environment. */
 #define SC_AC_SCB                       0x00000040 /* IAS/ECC SCB byte. */
 #define SC_AC_IDA                       0x00000080 /* PKCS#15 authentication ID */
+#define SC_AC_SESSION			0x00000100 /* Session PIN */
 
 #define SC_AC_UNKNOWN			0xFFFFFFFE
 #define SC_AC_NEVER			0xFFFFFFFF
diff --git a/src/minidriver/Makefile.mak b/src/minidriver/Makefile.mak
index ee8fa27..5ce80ef 100644
--- a/src/minidriver/Makefile.mak
+++ b/src/minidriver/Makefile.mak
@@ -14,5 +14,5 @@ $(TARGET): $(OBJECTS) $(LIBS)
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type minidriver.exports >> $*.def
-	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib /DELAYLOAD:bcrypt.dll
+	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib /DELAYLOAD:bcrypt.dll
 	if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2
diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c
index 705b734..34b1288 100644
--- a/src/minidriver/minidriver.c
+++ b/src/minidriver/minidriver.c
@@ -4774,7 +4774,8 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData,
 		return SCARD_F_INTERNAL_ERROR;
 
 	if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) {
-		if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD))
+		if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+					|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH))
 			return SCARD_E_UNSUPPORTED_FEATURE;
 	}
 
@@ -4783,7 +4784,8 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData,
 
 	/* using a pin pad */
 	if (NULL == pbPinData) {
-		if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD))
+		if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+					|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH))
 			return SCARD_E_INVALID_PARAMETER;
 		if (!(dwFlags & CARD_PIN_SILENT_CONTEXT)
 				&& !(vs->ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS)) {
@@ -4809,7 +4811,9 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData,
 
 	/* Do we need to display a prompt to enter PIN on pin pad? */
 	logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%p\n",
-		vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? "yes" : "no", pbPinData, vs->hwndParent);
+		vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+		|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH
+		? "yes" : "no", pbPinData, vs->hwndParent);
 
 	/* check if the pin is the session pin generated by a previous authentication with a pinpad */
 	if (pbPinData != NULL && cbPinData == sizeof(MAGIC_SESSION_PIN) && memcmp(MAGIC_SESSION_PIN, pbPinData, sizeof(MAGIC_SESSION_PIN)) == 0) {
@@ -4836,7 +4840,9 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData,
 	logprintf(pCardData, 2, "Pin code correct.\n");
 
 	/* set the session pin according to the minidriver specification */
-	if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) {
+	if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN
+			&& (vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		/* we set it to a special value for pinpad authentication to force a new pinpad authentication */
 		if (pcbSessionPin) *pcbSessionPin = sizeof(MAGIC_SESSION_PIN);
 		if (ppbSessionPin) {
@@ -4907,7 +4913,8 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData,
 
 	vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
 
-	if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) {
+	if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+				|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		if (pbAuthenticatingPinData == NULL  || cbAuthenticatingPinData == 0)    {
 			logprintf(pCardData, 1, "Invalid current PIN data\n");
 			return SCARD_E_INVALID_PARAMETER;
@@ -5192,7 +5199,9 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData,
 		if (p->dwVersion != PIN_INFO_CURRENT_VERSION)
 			return ERROR_REVISION_MISMATCH;
 
-		p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? ExternalPinType : AlphaNumericPinType;
+		p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD
+			|| vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH
+			? ExternalPinType : AlphaNumericPinType;
 		p->dwFlags = 0;
 		switch (dwFlags)   {
 			case ROLE_USER:
diff --git a/src/pkcs11/Makefile.mak b/src/pkcs11/Makefile.mak
index 8fd0ff9..1aeb9e6 100644
--- a/src/pkcs11/Makefile.mak
+++ b/src/pkcs11/Makefile.mak
@@ -17,15 +17,15 @@ all: $(TARGET1) $(TARGET2) $(TARGET3)
 !INCLUDE $(TOPDIR)\win32\Make.rules.mak
 
 $(TARGET1): $(OBJECTS) $(LIBS)
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib
 	if EXIST $(TARGET1).manifest mt -manifest $(TARGET1).manifest -outputresource:$(TARGET1);2
 
 $(TARGET2): $(OBJECTS) $(LIBS)
 	del pkcs11-global.obj
 	cl $(CODE_OPTIMIZATION) $(COPTS) /DMODULE_APP_NAME=\"onepin-opensc-pkcs11\" /c pkcs11-global.c
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib
 	if EXIST $(TARGET2).manifest mt -manifest $(TARGET2).manifest -outputresource:$(TARGET2);2
 
 $(TARGET3): $(OBJECTS3) $(LIBS3)
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENSSL_LIB) gdi32.lib advapi32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib advapi32.lib
 	if EXIST $(TARGET3).manifest mt -manifest $(TARGET3).manifest -outputresource:$(TARGET3);2
diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c
index 42c5093..19a7286 100644
--- a/src/pkcs11/framework-pkcs15.c
+++ b/src/pkcs11/framework-pkcs15.c
@@ -961,7 +961,7 @@ pkcs15_init_slot(struct sc_pkcs15_card *p15card, struct sc_pkcs11_slot *slot,
 	if (auth != NULL)
 		slot->token_info.flags |= CKF_USER_PIN_INITIALIZED;
 
-	if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
+	if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH))
 		slot->token_info.flags |= CKF_PROTECTED_AUTHENTICATION_PATH;
 
 	if (p15card->card->caps & SC_CARD_CAP_RNG && p15card->card->ops->get_challenge != NULL)
@@ -1489,7 +1489,8 @@ pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType,
 	if (pin_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
 		return CKR_FUNCTION_REJECTED;
 
-	if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
+	if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+			|| (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		/* pPin should be NULL in case of a pin pad reader, but
 		 * some apps (e.g. older Netscapes) don't know about it.
 		 * So we don't require that pPin == NULL, but set it to
@@ -1650,7 +1651,8 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot,
 		return CKR_USER_PIN_NOT_INITIALIZED;
 
 	sc_log(context, "Change '%.*s' (ref:%i,type:%i)", (int) sizeof pin_obj->label, pin_obj->label, auth_info->attrs.pin.reference, login_user);
-	if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
+	if ((p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
+			|| (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) {
 		/* pPin should be NULL in case of a pin pad reader, but
 		 * some apps (e.g. older Netscapes) don't know about it.
 		 * So we don't require that pPin == NULL, but set it to
diff --git a/src/sm/sm-eac.c b/src/sm/sm-eac.c
index c51b4b8..a556105 100644
--- a/src/sm/sm-eac.c
+++ b/src/sm/sm-eac.c
@@ -1762,13 +1762,11 @@ int perform_chip_authentication(sc_card_t *card,
 		unsigned char **ef_cardsecurity, size_t *ef_cardsecurity_len)
 {
 	int r;
-	BUF_MEM *picc_pubkey = NULL, *nonce = NULL, *token = NULL,
-			*eph_pub_key = NULL;
+	BUF_MEM *picc_pubkey = NULL;
 	struct iso_sm_ctx *isosmctx;
 	struct npa_sm_ctx *eacsmctx;
 
-	if (!card || !card->sm_ctx.info.cmd_data
-			|| !ef_cardsecurity || !ef_cardsecurity_len) {
+	if (!card || !ef_cardsecurity || !ef_cardsecurity_len) {
 		r = SC_ERROR_INVALID_ARGUMENTS;
 		goto err;
 	}
@@ -1779,7 +1777,6 @@ int perform_chip_authentication(sc_card_t *card,
 	}
 	eacsmctx = isosmctx->priv_data;
 
-
 	/* Passive Authentication */
 	if (!*ef_cardsecurity && !*ef_cardsecurity_len) {
 		r = get_ef_card_security(card, ef_cardsecurity, ef_cardsecurity_len);
@@ -1796,8 +1793,42 @@ int perform_chip_authentication(sc_card_t *card,
 		goto err;
 	}
 
+	r = perform_chip_authentication_ex(card, eacsmctx->ctx,
+			(unsigned char *) picc_pubkey->data, picc_pubkey->length);
+
+err:
+	BUF_MEM_clear_free(picc_pubkey);
+
+	if (card)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
+	else
+		return r;
+}
+
+int perform_chip_authentication_ex(sc_card_t *card, void *eac_ctx,
+		unsigned char *picc_pubkey, size_t picc_pubkey_len)
+{
+	int r;
+	BUF_MEM *picc_pubkey_buf = NULL, *nonce = NULL, *token = NULL,
+			*eph_pub_key = NULL;
+	EAC_CTX *ctx = eac_ctx;
+
+	if (!card || !ctx) {
+		r = SC_ERROR_INVALID_ARGUMENTS;
+		goto err;
+	}
+
+
+	picc_pubkey_buf = BUF_MEM_create_init(picc_pubkey, picc_pubkey_len);
+	if (!picc_pubkey_buf) {
+		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not verify EF.CardSecurity.");
+		ssl_error(card->ctx);
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
+
 
-	r = npa_mse_set_at_ca(card, eacsmctx->ctx->ca_ctx->protocol);
+	r = npa_mse_set_at_ca(card, ctx->ca_ctx->protocol);
 	if (r < 0) {
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties "
 				"(MSE: Set AT failed).");
@@ -1805,7 +1836,7 @@ int perform_chip_authentication(sc_card_t *card,
 	}
 
 
-	eph_pub_key = CA_STEP2_get_eph_pubkey(eacsmctx->ctx);
+	eph_pub_key = CA_STEP2_get_eph_pubkey(ctx);
 	if (!eph_pub_key) {
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys.");
 		ssl_error(card->ctx);
@@ -1819,7 +1850,7 @@ int perform_chip_authentication(sc_card_t *card,
 	}
 
 
-	if (!CA_STEP4_compute_shared_secret(eacsmctx->ctx, picc_pubkey)) {
+	if (!CA_STEP4_compute_shared_secret(ctx, picc_pubkey_buf)) {
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute shared secret.");
 		ssl_error(card->ctx);
 		r = SC_ERROR_INTERNAL;
@@ -1827,7 +1858,7 @@ int perform_chip_authentication(sc_card_t *card,
 	}
 
 
-	if (!CA_STEP6_derive_keys(eacsmctx->ctx, nonce, token)) {
+	if (!CA_STEP6_derive_keys(ctx, nonce, token)) {
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys.");
 		ssl_error(card->ctx);
 		r = SC_ERROR_INTERNAL;
@@ -1836,15 +1867,19 @@ int perform_chip_authentication(sc_card_t *card,
 
 
 	/* Initialize secure channel */
-	if (!EAC_CTX_set_encryption_ctx(eacsmctx->ctx, EAC_ID_CA)) {
+	if (!EAC_CTX_set_encryption_ctx(ctx, EAC_ID_CA)) {
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize encryption.");
 		ssl_error(card->ctx);
 		r = SC_ERROR_INTERNAL;
 		goto err;
 	}
 
+	if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) {
+		r = npa_sm_start(card, ctx, NULL, 0, NULL, 0);
+	}
+
 err:
-	BUF_MEM_clear_free(picc_pubkey);
+	BUF_MEM_clear_free(picc_pubkey_buf);
 	BUF_MEM_clear_free(nonce);
 	BUF_MEM_clear_free(token);
 	BUF_MEM_clear_free(eph_pub_key);
@@ -2371,6 +2406,12 @@ int perform_chip_authentication(sc_card_t *card,
 	return SC_ERROR_NOT_SUPPORTED;
 }
 
+int perform_chip_authentication_ex(sc_card_t *card, void *eac_ctx,
+		unsigned char *picc_pubkey, size_t picc_pubkey_len)
+{
+	return SC_ERROR_NOT_SUPPORTED;
+}
+
 #endif
 
 static const char *MRZ_name = "MRZ";
diff --git a/src/sm/sm-eac.h b/src/sm/sm-eac.h
index 755dd2a..fcb3577 100644
--- a/src/sm/sm-eac.h
+++ b/src/sm/sm-eac.h
@@ -230,6 +230,8 @@ int perform_terminal_authentication(sc_card_t *card,
  */
 int perform_chip_authentication(sc_card_t *card,
 		unsigned char **ef_cardsecurity, size_t *ef_cardsecurity_len);
+int perform_chip_authentication_ex(sc_card_t *card, void *eacsmctx,
+		unsigned char *picc_pubkey, size_t picc_pubkey_len);
 
 /** 
  * @brief Sends a reset retry counter APDU
diff --git a/src/smm/Makefile.mak b/src/smm/Makefile.mak
index d0eb992..a50ccbc 100644
--- a/src/smm/Makefile.mak
+++ b/src/smm/Makefile.mak
@@ -14,7 +14,7 @@ $(TARGET): $(OBJECTS) $(LIBS)
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type $*.exports >> $*.def
-	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib
+	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib
 	if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2
 
 !ELSE
diff --git a/src/tools/npa-tool.c b/src/tools/npa-tool.c
index a2a74a0..11b5575 100644
--- a/src/tools/npa-tool.c
+++ b/src/tools/npa-tool.c
@@ -486,7 +486,7 @@ main (int argc, char **argv)
 		} else if (cmdline.puk_given) {
 			pace_input.pin_id = PACE_PUK;
 			pace_input.pin_length = 10;
-			maxsecret = 9999999999LLU;
+			maxsecret = 9999999999;
 			if (puk) {
 				if (sscanf(puk, "%llu", &secret) != 1) {
 					fprintf(stderr, "%s is not an unsigned long long.\n",
diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c
index 9841035..0f1cfeb 100644
--- a/src/tools/pkcs15-tool.c
+++ b/src/tools/pkcs15-tool.c
@@ -1541,7 +1541,8 @@ static int unblock_pin(void)
 	u8 *pin, *puk;
 	int r, pinpad_present = 0;
 
-	pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD;
+	pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+	   	|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH;
 
 	if (!(pin_obj = get_pin_info()))
 		return 2;
@@ -1638,7 +1639,8 @@ static int change_pin(void)
 	u8 *pincode, *newpin;
 	int r, pinpad_present = 0;
 
-	pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD;
+	pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD
+	   	|| p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH;
 
 	if (!(pin_obj = get_pin_info()))
 		return 2;
diff --git a/win32/Make.rules.mak b/win32/Make.rules.mak
index 621beb4..5a10278 100644
--- a/win32/Make.rules.mak
+++ b/win32/Make.rules.mak
@@ -80,9 +80,10 @@ CANDLEFLAGS = -dzlib="C:\zlib-dll" $(CANDLEFLAGS)
 # - set the OPENPACE_LIB  below to your OpenPACE lib file
 #OPENPACE_DEF= /DENABLE_OPENPACE
 !IF "$(OPENPACE_DEF)" == "/DENABLE_OPENPACE"
-OPENPACE_DIR = C:\OpenPACE
-OPENPACE_INCL_DIR = /I$(OPENPACE_DIR)\include
-OPENPACE_LIB = $(OPENPACE_DIR)\lib\libeac.lib
+OPENPACE_DIR = C:\openpace
+OPENPACE_INCL_DIR = /I$(OPENPACE_DIR)\src
+OPENPACE_LIB = $(OPENPACE_DIR)\src\libeac.lib
+CANDLEFLAGS = -dOpenPACE="$(OPENPACE_DIR)" $(CANDLEFLAGS)
 !ENDIF
 
 
diff --git a/win32/OpenSC.wxs.in b/win32/OpenSC.wxs.in
index 1a024e3..29beecc 100644
--- a/win32/OpenSC.wxs.in
+++ b/win32/OpenSC.wxs.in
@@ -280,6 +280,16 @@
                 </Component>
               </Directory>
             <?endif ?>
+            <?ifdef OpenPACE ?>
+              <Directory Id="INSTALLDIR_CVC" Name="cvc">
+                <Component Id="UTSRCACC100001" Guid="*" Win64="$(var.Win64YesNo)">
+                  <File Source="$(var.SOURCE_DIR)\etc\UTSRCACC100001"/>
+                </Component>
+                <Component Id="DESRCACC100001" Guid="*" Win64="$(var.Win64YesNo)">
+                  <File Source="$(var.SOURCE_DIR)\etc\DESRCACC100001"/>
+                </Component>
+              </Directory>
+            <?endif ?>
           </Directory>
         </Directory>
       </Directory>
@@ -304,6 +314,10 @@
         <?ifdef OpenSSL ?>
           <ComponentRef Id="smm_local.dll"/>
         <?endif ?>
+        <?ifdef OpenPACE ?>
+          <ComponentRef Id="UTSRCACC100001"/>
+          <ComponentRef Id="DESRCACC100001"/>
+        <?endif ?>
       </Feature>
       <Feature Id="OpenSC_pkcs11" Level="1" Title="OpenSC PKCS#11 module" Description="PKCS#11 module usd by most open source and cross-platform software (like Firefox, Putty, TrueCrypt, OpenVPN etc)" TypicalDefault="install">
         <ComponentRef Id="opensc_pkcs11.dll"/>
diff --git a/win32/customactions.cpp b/win32/customactions.cpp
index 2eaa0fd..9c8377c 100644
--- a/win32/customactions.cpp
+++ b/win32/customactions.cpp
@@ -74,6 +74,8 @@ MD_REGISTRATION minidriver_registration[] = {
                                           24, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
 	{TEXT("SmartCard-HSM-CL"),                {0x3B,0x8E,0x80,0x01,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0x18},
                                           19, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
+	{TEXT("SmartCard-HSM-FP"),                {0x3B,0x80,0x80,0x01,0x01},
+                                           5, {0xff,0xff,0xff,0xff,0xff}},
 	/* from minidriver-westcos.reg */
 	{TEXT("CEV WESTCOS"),                     {0x3f,0x69,0x00,0x00,0x00,0x64,0x01,0x00,0x00,0x00,0x80,0x90,0x00},
                                           13, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xf0,0xff,0xff}},
diff --git a/win32/winconfig.h.in b/win32/winconfig.h.in
index 55f74fd..f170666 100644
--- a/win32/winconfig.h.in
+++ b/win32/winconfig.h.in
@@ -118,6 +118,10 @@
 #define OPENSC_VS_FF_PRODUCT_NAME  "@OPENSC_VS_FF_PRODUCT_NAME@"
 #endif
 
+#ifndef CVCDIR
+#define CVCDIR "%PROGRAMFILES%\\OpenSC Project\\OpenSC\\cvc"
+#endif
+
 #ifndef DEFAULT_PKCS11_PROVIDER
 #define DEFAULT_PKCS11_PROVIDER "@DEFAULT_PKCS11_PROVIDER@"
 #endif

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



More information about the pkg-opensc-commit mailing list