diff -Nru opensc-0.17.0/appveyor.yml opensc-0.19.0/appveyor.yml --- opensc-0.17.0/appveyor.yml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/appveyor.yml 2018-09-13 11:47:21.000000000 +0000 @@ -1,4 +1,4 @@ -version: 0.16.0.{build} +version: 0.19.0.{build} platform: - x86 @@ -6,21 +6,15 @@ configuration: - Release - - Debug - - Light-Release - - Light-Debug + - Light environment: + GH_TOKEN: + secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY matrix: - VSVER: 14 - VSVER: 12 - - VSVER: 10 - -matrix: - allow_failures: - # not included in AppVeyor right now - - platform: x64 - VSVER: 10 + DO_PUSH_ARTIFACT: yes install: - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` @@ -29,30 +23,23 @@ throw "There are newer queued builds for this pull request, failing early." } - date /T & time /T - set PATH=C:\cygwin\bin;%PATH% - - set OPENSSL_VER=1_0_2f - - set OPENPACE_VER=1.0.1 - - set ZLIB_VER_DOT=1.2.8 - - ps: $env:PACKAGE_NAME=(git describe --tags) + - set OPENPACE_VER=1.0.3 + - set ZLIB_VER_DOT=1.2.11 + - ps: $env:PACKAGE_NAME=(git describe --tags --abbrev=0) - ps: >- If ($env:Platform -Match "x86") { $env:VCVARS_PLATFORM="x86" $env:OPENSSL_PF="Win32" - $env:ARTIFACT="OpenSC-win32_vs${env:VSVER}-${env:CONFIGURATION}.msi" + $env:ARTIFACT="OpenSC-win32_${env:PACKAGE_NAME}" } Else { $env:VCVARS_PLATFORM="amd64" $env:OPENSSL_PF="Win64" - $env:ARTIFACT="OpenSC-win64_vs${env:VSVER}-${env:CONFIGURATION}.msi" - } - - ps: >- - If ($env:Configuration -Like "*Debug*") { - $env:NMAKE_EXTRA="DEBUG_DEF=/DDEBUG ${env:NMAKE_EXTRA}" + $env:ARTIFACT="OpenSC-win64_${env:PACKAGE_NAME}" } - ps: >- - If (!($env:Configuration -Like "*Light*")) { - If (!(Test-Path -Path "C:\OpenSSL-${env:OPENSSL_PF}" )) { - Start-FileDownload https://slproweb.com/download/${env:OPENSSL_PF}OpenSSL-${env:OPENSSL_VER}.exe -FileName C:\WinOpenSSL.exe - C:\WinOpenSSL.exe /SILENT /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART - } + If ($env:Configuration -Like "*Light*") { + $env:ARTIFACT="${env:ARTIFACT}-Light" + } Else { $env:NMAKE_EXTRA="OPENSSL_DEF=/DENABLE_OPENSSL ${env:NMAKE_EXTRA}" If (!(Test-Path C:\zlib )) { appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip @@ -65,10 +52,12 @@ Rename-Item -path "c:\openpace-${env:OPENPACE_VER}" -newName "openpace" } } + If (!(Test-Path cngsdk.msi )) { + appveyor DownloadFile "http://download.microsoft.com/download/2/C/9/2C93059C-0532-42DF-8C24-9AEAFF00768E/cngsdk.msi" + } - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS")) - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%" - call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM% - - appveyor DownloadFile "http://download.microsoft.com/download/2/C/9/2C93059C-0532-42DF-8C24-9AEAFF00768E/cngsdk.msi" - cngsdk.msi /quiet - uname -a - set @@ -81,58 +70,49 @@ xcopy C:\zlib C:\zlib-${env:OPENSSL_PF} /e /i /y /s cd C:\zlib-${env:OPENSSL_PF} (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc - If ($env:Platform -Match "x86") { - nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="inffas32.obj match686.obj" zlib.lib - } Else { - nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" zlib.lib - } + nmake -f win32/Makefile.msc zlib.lib } $env:NMAKE_EXTRA="ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib ${env:NMAKE_EXTRA}" If (!(Test-Path -Path "C:\openpace-${env:OPENSSL_PF}" )) { # build libeac.lib as a static library xcopy C:\openpace C:\openpace-${env:OPENSSL_PF} /e /i /y /s cd C:\openpace-${env:OPENSSL_PF}\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 + # OpenSSL 1.1.0 + #cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /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 ssl_compat.c + # OpenSSL 1.0.2 + 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 ssl_compat.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 ssl_compat.obj cd C:\projects\OpenSC } $env:NMAKE_EXTRA="OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF} ${env:NMAKE_EXTRA}" } - bash -c "exec 0- - If ($env:Configuration -Like "*Debug*") { - Get-ChildItem -recurse c:\projects\OpenSC -exclude vc*.pdb *.pdb | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + Get-ChildItem -recurse C:\projects\OpenSC -exclude vc*.pdb *.pdb | % { + 7z a -tzip ${env:ARTIFACT}-Debug.zip $_.FullName } + - appveyor PushArtifact %ARTIFACT%-Debug.zip + + # keep in sync with .travis.yml + - bash -c "git config --global user.email 'no-reply@appveyor.com'" + - bash -c "git config --global user.name 'AppVeyor'" + - bash -c "if [ \"$DO_PUSH_ARTIFACT\" = yes -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then .github/push_artifacts.sh \"AppVeyor build ${APPVEYOR_BUILD_NUMBER}.${APPVEYOR_JOB_NUMBER}\"; fi" cache: - - C:\OpenSSL-Win32 -> appveyor.yml - - C:\OpenSSL-Win64 -> appveyor.yml - C:\zlib -> appveyor.yml - C:\zlib-Win32 -> appveyor.yml - C:\zlib-Win64 -> appveyor.yml - C:\openpace -> appveyor.yml - C:\openpace-Win32 -> appveyor.yml - C:\openpace-Win64 -> appveyor.yml - -deploy: - - provider: GitHub - tag: $(APPVEYOR_REPO_TAG_NAME) - release: OpenSC-$(APPVEYOR_REPO_TAG_NAME) - description: 'release OpenSC $(APPVEYOR_REPO_TAG_NAME)' - auth_token: - secure: NGaTqWohBQa7fgE62rEm2sp9jkv6S9FRc3YEi3T5CpaoyIY6K89FJjqzaoPLr8vj - artifact: /OpenSC-.*\.msi/ - draft: false - prerelease: true - on: - branch: /0.16.0-rc.*/ # here branch is release tag - appveyor_repo_tag: true # deploy on tag push only + - cngsdk.msi -> appveyor.yml diff -Nru opensc-0.17.0/bootstrap.ci opensc-0.19.0/bootstrap.ci --- opensc-0.17.0/bootstrap.ci 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/bootstrap.ci 2018-09-13 11:47:21.000000000 +0000 @@ -10,19 +10,12 @@ -h Show this message -s Package suffix -S Use package suffix as 'g' appended with the date of last commit - -r Package version revision - -R Use package version revision as Git commit number from 'git describe' result - -b Package branch - -B Use package branch as current Git branch EOF } SUFFIX= -REVISION= -VERBOSE= -KEEPVERSION= -while getopts “:hs:Sr:RK” OPTION +while getopts “:hs:S” OPTION do case $OPTION in h) @@ -35,12 +28,6 @@ S) SUFFIX=g`git log -1 --pretty=fuller --date=iso | grep CommitDate: | sed -E 's/^CommitDate:\s(.*)/\1/' | sed -E 's/(.*)-(.*)-(.*) (.*):(.*):(.*)\s+.*/\1\2\3\4\5\6/'` ;; - r) - REVISION=$OPTARG - ;; - R) - REVISION=`git describe | perl -ne 'print $1 if /^[\.0-9]*-([0-9]*)-g[a-z0-9]*$/;'` - ;; ?) usage exit @@ -49,31 +36,17 @@ done set -e -set -x + if [ -f Makefile ]; then make distclean fi rm -rf *~ *.cache config.guess config.log config.status config.sub depcomp ltmain.sh version.m4.ci -if [ -n "$SUFFIX" ] || [ -n "$REVISION" ] +if [ -n "$SUFFIX" ] then - cp -a version.m4 version.m4.tmp - - if [ -n "$SUFFIX" ] - then - echo Set package suffix "$SUFFIX" - sed 's/^define(\[PACKAGE_SUFFIX\],\s*\[\([-~]*[0-9a-zA-Z]*\)\])$/define(\[PACKAGE_SUFFIX\], \['$SUFFIX'\])/g' version.m4.tmp > version.m4.ci - cp version.m4.ci version.m4.tmp - fi - - if [ -n "$REVISION" ] - then - echo Set package revision "$REVISION" - sed 's/^define(\[PACKAGE_VERSION_REVISION\],\s*\[\([-~]*[0-9a-zA-Z]*\)\])$/define(\[PACKAGE_VERSION_REVISION\], \['$REVISION'\])/g' version.m4.tmp > version.m4.ci - fi - - rm -f version.m4.tmp + echo Set package suffix "$SUFFIX" + sed 's/^define(\[PACKAGE_SUFFIX\],\s*\[\([-~]*[0-9a-zA-Z]*\)\])$/define(\[PACKAGE_SUFFIX\], \['$SUFFIX'\])/g' < version.m4 > version.m4.ci fi ./bootstrap diff -Nru opensc-0.17.0/configure.ac opensc-0.19.0/configure.ac --- opensc-0.17.0/configure.ac 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/configure.ac 2018-09-13 11:47:21.000000000 +0000 @@ -5,8 +5,9 @@ define([PRODUCT_NAME], [OpenSC]) define([PRODUCT_TARNAME], [opensc]) define([PRODUCT_BUGREPORT], [https://github.com/OpenSC/OpenSC/issues]) +define([PRODUCT_URL], [https://github.com/OpenSC/OpenSC]) define([PACKAGE_VERSION_MAJOR], [0]) -define([PACKAGE_VERSION_MINOR], [17]) +define([PACKAGE_VERSION_MINOR], [19]) define([PACKAGE_VERSION_FIX], [0]) define([PACKAGE_SUFFIX], []) @@ -18,10 +19,9 @@ define([VS_FF_PRODUCT_UPDATES], [https://github.com/OpenSC/OpenSC/releases]) define([VS_FF_PRODUCT_URL], [https://github.com/OpenSC/OpenSC]) -m4_include(version.m4) m4_sinclude(version.m4.ci) -AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX],[PRODUCT_BUGREPORT],[PRODUCT_TARNAME]) +AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX],[PRODUCT_BUGREPORT],[PRODUCT_TARNAME],[PRODUCT_URL]) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -43,8 +43,8 @@ # (Code changed: REVISION++) # (Oldest interface removed: OLDEST++) # (Interfaces added: CURRENT++, REVISION=0) -OPENSC_LT_CURRENT="5" -OPENSC_LT_OLDEST="5" +OPENSC_LT_CURRENT="6" +OPENSC_LT_OLDEST="6" OPENSC_LT_REVISION="0" OPENSC_LT_AGE="0" OPENSC_LT_AGE="$((${OPENSC_LT_CURRENT}-${OPENSC_LT_OLDEST}))" @@ -123,9 +123,6 @@ PROFILE_DIR_DEFAULT="\$(pkgdatadir)" ;; esac -AC_DEFINE_UNQUOTED([DEBUG_FILE], ["${DEBUG_FILE}"], [Debug file]) -AC_DEFINE_UNQUOTED([PROFILE_DIR], ["${PROFILE_DIR}"], [Directory of profiles]) -AC_DEFINE_UNQUOTED([PROFILE_DIR_DEFAULT], ["${PROFILE_DIR_DEFAULT}"], [Default directory of profiles]) case "${host}" in *-mingw*) @@ -133,9 +130,12 @@ ;; esac +AX_CHECK_COMPILE_FLAG(-Wunknown-warning-option, [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"], [-Werror]) +AM_CONDITIONAL([HAVE_UNKNOWN_WARNING_OPTION], [test "${have_unknown_warning_option}" = "yes"]) + AC_ARG_ENABLE( [strict], - [AS_HELP_STRING([--disable-strict],[disable strict compile mode @<:@disabled@:>@])], + [AS_HELP_STRING([--disable-strict],[disable strict compile mode @<:@enabled@:>@])], , [enable_strict="yes"] ) @@ -246,10 +246,17 @@ ) AC_ARG_ENABLE( - [werror-declaration-after-statement], - [AS_HELP_STRING([--disable-werror-declaration-after-statement],[disable -Werror 'declaration-after-statement' @<:@enabled@:>@])], + [notify], + [AS_HELP_STRING([--enable-notify],[enable notifications @<:@detect@:>@])], + , + [enable_notify="detect"] +) + +AC_ARG_ENABLE( + [tests], + [AS_HELP_STRING([--enable-tests],[Build tests in src/tests/ directory @<:@detect@:>@])], , - [werror_declaration_after_statement="yes"] + [enable_tests="detect"] ) AC_ARG_WITH( @@ -260,6 +267,13 @@ ) AC_ARG_WITH( + [completiondir], + [AS_HELP_STRING([--with-completiondir=PATH],[Directory of Bash completion @<:@detect@:>@])], + [completiondir="${withval}"], + [completiondir="detect"] +) + +AC_ARG_WITH( [pcsc-provider], [AS_HELP_STRING([--with-pcsc-provider=PATH],[Path to system pcsc provider @<:@system default@:>@])], , @@ -330,7 +344,6 @@ AC_MSG_CHECKING([git checkout]) GIT_CHECKOUT="no" if test -n "${GIT}" -a -d "${srcdir}/.git"; then - AC_DEFINE([HAVE_CONFIG_VERSION_H], [1], [extra version available in config-version.h]) GIT_CHECKOUT="yes" fi AC_MSG_RESULT([${GIT_CHECKOUT}]) @@ -377,7 +390,7 @@ AC_CHECK_FUNCS([ \ getpass gettimeofday getline memset mkdir \ strdup strerror getopt_long getopt_long_only \ - strlcpy strlcat strnlen + strlcpy strlcat strnlen sigaction ]) AC_CHECK_SIZEOF(void *) if test "${ac_cv_sizeof_void_p}" = 8; then @@ -443,14 +456,80 @@ AC_DEFINE([ENABLE_DNIE_UI], [1], [Enable the use of external user interface program to request DNIe user pin]) case "${host}" in + *-*-darwin*) + LDFLAGS="${LDFLAGS} -framework Carbon" + ;; + esac + case "${host}" in *-apple-*) - if test "${enable_dnie_ui}" = "yes"; then - LDFLAGS="${LDFLAGS} -framework Carbon" - fi + LDFLAGS="${LDFLAGS} -framework CoreFoundation" ;; esac fi +case "${host}" in + *-*-darwin*) + have_notify="yes" + ;; + *) + PKG_CHECK_MODULES( [GIO2], [gio-2.0], + [ have_notify="yes" + have_gio2="yes" ], + [ have_notify="no" + have_gio2="no" ]) + saved_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${GIO2_CFLAGS}" + AC_CHECK_HEADERS(gio/gio.h, [], + [ AC_MSG_WARN([glib2 headers not found]) + have_notify="no" + have_gio2="no" ]) + CFLAGS="${saved_CFLAGS}" + saved_LIBS="$LIBS" + LIBS="$LIBS ${GIO2_LIBS}" + AC_MSG_CHECKING([for g_application_send_notification]) + AC_TRY_LINK_FUNC(g_application_send_notification, [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_WARN([Cannot link against glib2]) + have_notify="no" + have_gio2="no" ]) + LIBS="$saved_LIBS" + ;; +esac + +case "${enable_notify}" in + no) + have_notify="no" + ;; + detect) + if test "${have_notify}" = "yes"; then + enable_notify="yes" + else + enable_notify="no" + fi + ;; +esac + +if test "${enable_notify}" = "yes"; then + if test "${have_notify}" = "yes"; then + AC_DEFINE([ENABLE_NOTIFY], [1], [Use notification libraries and header files]) + if test "${have_gio2}" = "yes"; then + AC_DEFINE([ENABLE_GIO2], [1], [Use glib2 libraries and header files]) + OPTIONAL_NOTIFY_CFLAGS="${GIO2_CFLAGS}" + OPTIONAL_NOTIFY_LIBS="${GIO2_LIBS}" + fi + else + AC_MSG_ERROR([notification linkage required, but no notification provider was found]) + fi +fi + +have_cmocka="yes" +PKG_CHECK_MODULES([CMOCKA], [cmocka >= 1.0.1],,[have_cmocka="no"]) +AC_CHECK_HEADER([setjmp.h]) +AC_CHECK_HEADER([cmocka.h],, [have_cmocka="no"], +[#include +#include +#include +]) + AC_ARG_VAR([ZLIB_CFLAGS], [C compiler flags for zlib]) AC_ARG_VAR([ZLIB_LIBS], [linker flags for zlib]) if test -z "${ZLIB_LIBS}"; then @@ -577,6 +656,23 @@ OPENSSL_LIBS="" fi +if test "${enable_tests}" = "detect"; then + if test "${have_cmocka}" = "yes" -a "${have_openssl}" = "yes"; then + enable_tests="yes" + else + enable_tests="no" + fi +fi + +if test "${enable_tests}" = "yes"; then + if test "${have_cmocka}" != "yes"; then + AC_MSG_ERROR([Tests required, but cmocka is not available]) + fi + if test "${have_openssl}" != "yes"; then + AC_MSG_ERROR([Tests required, but openssl is not available]) + fi +fi + PKG_CHECK_EXISTS([libeac], [PKG_CHECK_MODULES([OPENPACE], [libeac >= 0.9])], @@ -750,6 +846,14 @@ AC_DEFINE([ENABLE_CRYPTOTOKENKIT], [1], [Define if CryptoTokenKit is to be enabled]) fi +if test "${completiondir}" = "detect"; then + echo completion ${completiondir} + PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], + [completiondir="`pkg-config --variable=completionsdir bash-completion`"], + [completiondir="${sysconfdir}/bash_completion.d"]) +fi +AC_SUBST([completiondir]) + AC_SUBST(DYN_LIB_EXT) AC_SUBST(LIBDIR) @@ -773,22 +877,23 @@ DEFAULT_SM_MODULE="${LIB_PRE}smm-local${DYN_LIB_EXT}" case "${host}" in *-mingw*|*-winnt*|*-cygwin*) - DEFAULT_SM_MODULE_PATH="\# module_path = \"\";" + DEFAULT_SM_MODULE_PATH="%PROGRAMFILES%\\\OpenSC Project\\\OpenSC\\\tools" ;; *) - DEFAULT_SM_MODULE_PATH="module_path = \$(libdir);" + DEFAULT_SM_MODULE_PATH="${libdir}" ;; esac - AC_DEFINE_UNQUOTED([DEFAULT_SM_MODULE], ["${DEFAULT_SM_MODULE}"], [Default SM module]) - AC_DEFINE_UNQUOTED([DEFAULT_SM_MODULE_PATH], ["${DEFAULT_SM_MODULE_PATH}"], [Default SM module path]) fi if test "${with_pkcs11_provider}" = "detect"; then - DEFAULT_PKCS11_PROVIDER="opensc-pkcs11${DYN_LIB_EXT}" + if test "${WIN32}" != "yes"; then + DEFAULT_PKCS11_PROVIDER="${libdir}/opensc-pkcs11${DYN_LIB_EXT}" + else + DEFAULT_PKCS11_PROVIDER="%PROGRAMFILES%\\\OpenSC Project\\\OpenSC\\\pkcs11\\\opensc-pkcs11.dll" + fi else DEFAULT_PKCS11_PROVIDER="${with_pkcs11_provider}" fi -AC_DEFINE_UNQUOTED([DEFAULT_PKCS11_PROVIDER], ["${DEFAULT_PKCS11_PROVIDER}"], [Default PKCS11 provider]) if test "${enable_man}" = "detect"; then if test "${WIN32}" = "yes"; then @@ -807,9 +912,6 @@ AC_MSG_RESULT([ok]) fi -AC_ARG_VAR([HELP2MAN], - [absolute path to help2man used for man page generation of npa-tool]) -AC_PATH_PROG(HELP2MAN, help2man, not found) AC_ARG_VAR([GENGETOPT], [absolute path to gengetopt used for command line parsing of npa-tool]) AC_PATH_PROG(GENGETOPT, gengetopt, not found) @@ -914,6 +1016,8 @@ AC_SUBST([DEBUG_FILE]) AC_SUBST([PROFILE_DIR]) AC_SUBST([PROFILE_DIR_DEFAULT]) +AC_SUBST([OPTIONAL_NOTIFY_CFLAGS]) +AC_SUBST([OPTIONAL_NOTIFY_LIBS]) AM_CONDITIONAL([ENABLE_MAN], [test "${enable_man}" = "yes"]) AM_CONDITIONAL([ENABLE_THREAD_LOCKING], [test "${enable_thread_locking}" = "yes"]) @@ -931,31 +1035,26 @@ AM_CONDITIONAL([ENABLE_SM], [test "${enable_sm}" = "yes"]) AM_CONDITIONAL([ENABLE_DNIE_UI], [test "${enable_dnie_ui}" = "yes"]) AM_CONDITIONAL([ENABLE_NPATOOL], [test "${ENABLE_NPATOOL}" = "yes"]) +AM_CONDITIONAL([ENABLE_TESTS], [test "${enable_tests}" = "yes"]) AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"]) if test "${enable_pedantic}" = "yes"; then enable_strict="yes"; - CFLAGS="${CFLAGS} -pedantic -Wextra" + CFLAGS="${CFLAGS} -pedantic" fi if test "${enable_strict}" = "yes"; then - CFLAGS="${CFLAGS} -Wall -Wextra -Wno-unused-parameter" -fi -if test "$GCC" = "yes"; then - # This should be resolved not ignored. - CFLAGS="-fno-strict-aliasing ${CFLAGS}" -fi - -if test "${werror_declaration_after_statement}" = "yes"; then - CFLAGS="${CFLAGS} -Werror=declaration-after-statement" + CFLAGS="${CFLAGS} -Wall -Wextra -Wno-unused-parameter -Werror" fi AC_CONFIG_FILES([ Makefile doc/Makefile doc/tools/Makefile + doc/files/Makefile etc/Makefile src/Makefile src/common/Makefile + src/ui/Makefile src/libopensc/Makefile src/sm/Makefile src/pkcs11/Makefile @@ -966,8 +1065,10 @@ src/scconf/Makefile src/tests/Makefile src/tests/regression/Makefile + src/tests/p11test/Makefile src/tools/Makefile src/tools/versioninfo-tools.rc + src/tools/versioninfo-opensc-notify.rc src/smm/Makefile src/minidriver/Makefile src/minidriver/versioninfo-minidriver.rc @@ -1005,6 +1106,7 @@ User binaries: $(eval eval eval echo "${bindir}") Configuration files: $(eval eval eval echo "${sysconfdir}") +Bash completion: ${completiondir} XSL stylesheets: ${xslstylesheetsdir} man support: ${enable_man} @@ -1020,11 +1122,13 @@ minidriver support: ${enable_minidriver} SM support: ${enable_sm} SM default module: ${DEFAULT_SM_MODULE} +SM default path: $(eval eval eval echo "${DEFAULT_SM_MODULE_PATH}") DNIe UI support: ${enable_dnie_ui} -Debug file: ${DEBUG_FILE} +Notification support: ${enable_notify} +Build tests: ${enable_tests} PC/SC default provider: ${DEFAULT_PCSC_PROVIDER} -PKCS11 default provider: ${DEFAULT_PKCS11_PROVIDER} +PKCS11 default provider: $(eval eval eval echo "${DEFAULT_PKCS11_PROVIDER}") Host: ${host} Compiler: ${CC} @@ -1045,6 +1149,8 @@ OPENCT_LIBS: ${OPENCT_LIBS} PCSC_CFLAGS: ${PCSC_CFLAGS} CRYPTOTOKENKIT_CFLAGS: ${CRYPTOTOKENKIT_CFLAGS} +GIO2_CFLAGS: ${GIO2_CFLAGS} +GIO2_LIBS: ${GIO2_LIBS} EOF diff -Nru opensc-0.17.0/CONTRIBUTING.md opensc-0.19.0/CONTRIBUTING.md --- opensc-0.17.0/CONTRIBUTING.md 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -# Reporting Bugs - -Please read about [reporting bugs](https://github.com/OpenSC/OpenSC/wiki/How-to-report-bugs-so-that-they-can-be-fixed) before opening an issue. diff -Nru opensc-0.17.0/debian/changelog opensc-0.19.0/debian/changelog --- opensc-0.17.0/debian/changelog 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/changelog 2019-06-10 16:28:21.000000000 +0000 @@ -1,3 +1,52 @@ +opensc (0.19.0-2~ubuntu18.04.1~ppa1) bionic; urgency=medium + + * No-change backport to bionic + + -- Gianfranco Costamagna Mon, 10 Jun 2019 18:28:21 +0200 + +opensc (0.19.0-2) unstable; urgency=medium + + * Add config files docs. + Thanks Peter Marschall for the patch. (Closes: 910131) + * Add example config file. + Thanks Peter Marschall. (Closes: 910133) + + -- Eric Dorland Mon, 04 Mar 2019 01:14:51 -0500 + +opensc (0.19.0-1) unstable; urgency=medium + + * New upstream release (Closes: 908363, 909444) + * Fix linebreak in watch file + + -- Eric Dorland Sun, 30 Sep 2018 16:26:03 -0400 + +opensc (0.19.0~rc1-1) unstable; urgency=medium + + * New upstream release + * Update watch rules + * Standards-Version to 4.2.1.1 + + -- Eric Dorland Sun, 09 Sep 2018 00:23:09 -0400 + +opensc (0.18.0-3) unstable; urgency=medium + + * Include the opensc-notify tool + + -- Eric Dorland Sat, 02 Jun 2018 19:46:02 -0400 + +opensc (0.18.0-2) unstable; urgency=medium + + * Install all binaries and manpages (Closes: 899236) + * Standards-Version to 4.1.4 + + -- Eric Dorland Tue, 22 May 2018 13:10:58 -0400 + +opensc (0.18.0-1) unstable; urgency=medium + + * New upstream release. + + -- Eric Dorland Sun, 20 May 2018 21:25:13 -0400 + opensc (0.17.0-3) unstable; urgency=medium * Switch to debhelper 11 diff -Nru opensc-0.17.0/debian/control opensc-0.19.0/debian/control --- opensc-0.17.0/debian/control 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/control 2019-03-04 06:14:51.000000000 +0000 @@ -7,6 +7,7 @@ docbook-xsl, flex, help2man, + libglib2.0-dev, libltdl3-dev, libpcsclite-dev (>= 1.2.9-beta1), libreadline-dev, @@ -14,7 +15,7 @@ pkg-config, xsltproc, zlib1g-dev -Standards-Version: 4.1.3 +Standards-Version: 4.2.1.1 Homepage: https://github.com/OpenSC/OpenSC/wiki Vcs-Git: https://salsa.debian.org/opensc-team/opensc.git Vcs-Browser: https://salsa.debian.org/opensc-team/opensc diff -Nru opensc-0.17.0/debian/opensc.docs opensc-0.19.0/debian/opensc.docs --- opensc-0.17.0/debian/opensc.docs 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/opensc.docs 2019-03-04 06:14:51.000000000 +0000 @@ -1,2 +1,2 @@ - +doc/files/files.html doc/tools/tools.html diff -Nru opensc-0.17.0/debian/opensc.examples opensc-0.19.0/debian/opensc.examples --- opensc-0.17.0/debian/opensc.examples 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/debian/opensc.examples 2019-03-04 06:14:51.000000000 +0000 @@ -0,0 +1 @@ +etc/opensc.conf.example diff -Nru opensc-0.17.0/debian/opensc.install opensc-0.19.0/debian/opensc.install --- opensc-0.17.0/debian/opensc.install 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/opensc.install 2019-03-04 06:14:51.000000000 +0000 @@ -1,33 +1,8 @@ -debian/tmp/usr/bin/cardos-tool -debian/tmp/usr/bin/cryptoflex-tool -debian/tmp/usr/bin/dnie-tool -debian/tmp/usr/bin/eidenv -debian/tmp/usr/bin/iasecc-tool -debian/tmp/usr/bin/netkey-tool -debian/tmp/usr/bin/openpgp-tool -debian/tmp/usr/bin/opensc-explorer -debian/tmp/usr/bin/opensc-tool -debian/tmp/usr/bin/piv-tool -debian/tmp/usr/bin/pkcs11-tool -debian/tmp/usr/bin/pkcs15* -debian/tmp/usr/bin/sc-hsm-tool -debian/tmp/usr/bin/westcos-tool +debian/tmp/usr/bin/* -debian/tmp/usr/share/man/man1/cardos-tool.1 -debian/tmp/usr/share/man/man1/cryptoflex-tool.1 -debian/tmp/usr/share/man/man1/dnie-tool.1 -debian/tmp/usr/share/man/man1/eidenv.1 -debian/tmp/usr/share/man/man1/iasecc-tool.1 -debian/tmp/usr/share/man/man1/netkey-tool.1 -debian/tmp/usr/share/man/man1/openpgp-tool.1 -debian/tmp/usr/share/man/man1/opensc-explorer.1 -debian/tmp/usr/share/man/man1/opensc-tool.1 -debian/tmp/usr/share/man/man1/piv-tool.1 -debian/tmp/usr/share/man/man1/pkcs11-tool.1 -debian/tmp/usr/share/man/man1/pkcs15*.1 -debian/tmp/usr/share/man/man1/sc-hsm-tool.1 -debian/tmp/usr/share/man/man1/westcos-tool.1 +debian/tmp/usr/share/man/man1/* debian/tmp/usr/share/man/man5/* debian/tmp/usr/share/opensc/*.profile +debian/tmp/usr/share/applications/org.opensc.notify.desktop etc/opensc.conf etc/opensc diff -Nru opensc-0.17.0/debian/rules opensc-0.19.0/debian/rules --- opensc-0.17.0/debian/rules 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/rules 2019-03-04 06:14:51.000000000 +0000 @@ -8,6 +8,7 @@ --enable-pcsc \ --enable-doc \ --enable-dnie-ui \ + --enable-notify \ --enable-readline \ --enable-sm \ --enable-zlib \ diff -Nru opensc-0.17.0/debian/watch opensc-0.19.0/debian/watch --- opensc-0.17.0/debian/watch 2018-02-25 02:36:07.000000000 +0000 +++ opensc-0.19.0/debian/watch 2019-03-04 06:14:51.000000000 +0000 @@ -1,5 +1,6 @@ -version=3 +version=4 -opts="filenamemangle=s/(?:.*)?v?(\d[\d\.]*)\.tar\.gz/-$1.tar.gz/" \ - https://github.com/OpenSC/OpenSC/tags (?:.*/)?v?(\d[\d\.]*)\.tar\.gz +opts="filenamemangle=s/(?:.*)?v?(\d\S+)\.tar\.gz/opensc-$1.tar.gz/, \ + uversionmangle=s/-rc/~rc/" \ + https://github.com/OpenSC/OpenSC/tags (?:.*/)?v?(\d\S+)\.tar\.gz diff -Nru opensc-0.17.0/doc/files/files.html opensc-0.19.0/doc/files/files.html --- opensc-0.17.0/doc/files/files.html 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/files/files.html 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1096 @@ +OpenSC Manual Pages: Section 5

OpenSC Manual Pages: Section 5


Table of Contents

opensc.conf — configuration file for OpenSC
pkcs15-profile — format of profile for pkcs15-init

Name

opensc.conf — configuration file for OpenSC

Description

+ OpenSC obtains configuration data from the following sources in the following order +

  1. + command-line options +

  2. + environment variables +

  3. + Windows registry key in + HKEY_CURRENT_USER (if available) +

  4. + Windows registry key in + HKEY_LOCAL_MACHINE (if available) +

  5. + system-wide configuration file + (/usr/etc/opensc.conf) +

+

+ The configuration file, opensc.conf, is composed + of blocks, which, in general, have the + following format: +

+key [, name...] {
+	block_contents
+}
+			

+ block_contents is one or more + block_items where a + block_item is one of +

  • + # comment string +

  • + key [, name...] = value; +

  • + block +

+

+ At the root level, opensc.conf should contain + one or more application specific configuration blocks: +

+app application {
+	block_contents
+}
+			

+ application + specifies one of: +

  • + default: The fall-back configuration block for all applications +

  • + opensc-pkcs11: Configuration block for the PKCS#11 module (opensc-pkcs11.so) +

  • + onepin-opensc-pkcs11: Configuration block for the PKCS#11 one-PIN-module (onepin-opensc-pkcs11.so) +

  • + cardmod: Configuration block for Windows' minidriver (opensc-minidriver.dll) +

  • + tokend: Configuration block for macOS' tokend (OpenSC.tokend) +

  • + cardos-tool, + cryptoflex-tool, + dnie-tool, + egk-tool, + eidenv, + gids-tool, + iasecc-tool, + netkey-tool, + npa-tool, + openpgp-tool, + opensc-asn1, + opensc-explorer, + opensc-notify, + opensc-tool, + piv-tool, + pkcs11-tool, + pkcs15-crypt, + pkcs15-init, + pkcs15-tool, + sc-hsm-tool, + westcos-tool: + Configuration block for OpenSC tools +

+

Configuration Options

+ debug = num; +

+ Amount of debug info to print (Default: + 0). A greater value means more + debug info. +

+ The environment variable + OPENSC_DEBUG overwrites this + setting. +

+ debug_file = filename; +

+ The file to which debug output will be written + (Default: stderr). Special + values stdout and + stderr are recognized. +

+ profile_dir = filename; +

+ PKCS#15 initialization/personalization profiles + directory for + pkcs15-init(1). + + (Default: /usr/share/opensc). +

+ If this configuration value is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\ProfileDir is + checked. +

+ disable_popups = bool; +

+ Disable pop-ups of built-in GUI (Default: false). +

+ enable_default_driver = bool; +

+ Enable default card driver (Default: + false). Default card driver is + explicitly enabled for + opensc-explorer(1). + + and + opensc-tool(1). + +

+ card_drivers = name... ; +

+ Whitelist of card drivers to load at start-up. + The special value internal (the + default) will load all statically linked drivers. +

+ If an unknown (i.e. not internal or old) driver is + supplied, a separate configuration configuration + block has to be written for the driver. A special + value old will load all + statically linked drivers that may be removed in + the future. +

+ The list of supported card driver names can be + retrieved from the output of opensc-tool + --list-drivers. +

+ The environment variable + OPENSC_DRIVER overwrites this + setting. +

+ ignored_readers = name... ; +

+ List of readers to ignore (Default: empty). If any + of the comma separated strings listed is matched in + a reader name (case sensitive, partial matching + possible), the reader is ignored by OpenSC. Use + opensc-tool --list-readers to + see all currently connected readers. +

+ reader_driver name { + block_contents + } + +

+ Configuration of the smart card reader driver where name is one of: +

+

+ See the section called “Configuration of Smart Card Reader Driver”. +

+ card_driver name { + block_contents + } + +

+ Configuration of the card driver where name is one of: +

+

+ card_atr hexstring { + block_contents + } + +

+ In addition to the built-in list of known cards in + the card driver, you can configure a new card for + the driver using the card_atr + block. +

+ For details see the section called “Configuration based on ATR”. +

+ secure_messaging name { + block_contents + } + +

+ Configuration options for the secure messaging profile name: +

+ module_name = filename; +

+ Name of external SM module (Default: libsmm-local.so). +

+ module_path = filename; +

+ Directory with external SM module + (Default: /usr/lib). +

+ If this configuration value is not + found on Windows, the registry key + Software\OpenSC + Project\OpenSC\SmDir is + checked. +

+ module_data = value; +

+ Specific data to tune the module initialization. +

+ mode = value; +

+ Secure messaging mode. Known parameters: +

  • + transmit: + In this mode the + procedure to securize + an APDU is called by + the OpenSC general APDU + transmit procedure. In + this mode all APDUs, + except the ones + filtered by the card + specific procedure, are + securized. +

  • + acl: + In this mode APDU are + securized only if + needed by the ACLs of + the command to be + executed. +

+

+ flags = value; +

+ Secure messaging type specific flags. +

+ kmc = hexstring; +

+ Default KMC of the GP Card Manager for the Oberthur's Java cards. +

+ ifd_serial = hexstring; +
+ keyset[_aid]_num_enc = + value; + keyset[_aid]_num_mac = + value; +

+ Keyset values from IAM profiles of + the Gemalto IAS/ECC cards with an + optional application identifier +

+ framework name { + block_contents + } + +

+ Internal configuration options where name is one of: +

+

+ pkcs11 { + block_contents + } + +

+ Parameters for the OpenSC PKCS11 module. +

+ For details see the section called “Configuration of PKCS#11”. +

Configuration of Smart Card Reader Driver

Configuration Options for all Reader Drivers

+ max_send_size = num; + max_recv_size = num; +

+ Limit command and response sizes + (Default: + max_send_size + = 255, + max_recv_size + = 256) . Some + Readers don't propagate their + transceive capabilities correctly. + max_send_size and max_recv_size + allow setting the limits manually, + for example to enable extended + length capabilities. +

+ enable_escape bool; +

+ Detect reader capabilities with + escape commands (wrapped APDUs with + CLA=0xFF as defined by PC/SC pt. 3 + and BSI TR-03119, e.g. for getting + the UID, escaped PIN commands and + the reader's firmware version, + Default: false) +

Configuration of CT-API Readers

+ module filename { + ports = nums; + } + +

+ Load the specified CT-API module with the specified number of ports. +

Configuration of PC/SC Readers

+ connect_exclusive = bool; +

+ Connect to reader in exclusive mode + (Default: false)? + This option has no effect in Windows' minidriver. +

+ disconnect_action = action; +

+ What to do when disconnecting from + a card (SCardDisconnect). Valid + values are + leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ transaction_end_action = action; +

+ What to do at the end of a + transaction (SCardEndTransaction). + Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ reconnect_action = action; +

+ What to do when reconnection to a + card (SCardReconnect). Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ enable_pinpad = bool; +

+ Enable pinpad if detected (PC/SC + v2.0.2 Part 10, Default: + true) +

+ fixed_pinlength = num; +

+ Some pinpad readers can only handle + one exact length of the PIN. + fixed_pinlength + sets this value so that OpenSC + expands the padding to this length + (Default: 0, + i.e. not fixed). +

+ provider_library = filename; +

+ Use specific PC/SC provider + (Default: + libpcsclite.so.1). +

Configuration of OpenCT Readers

+ readers = num; +

+ Virtual readers to allocate (Default: 2). +

Configuration Options for German ID Card

+ can = value; +

+ German ID card requires the CAN to + be verified before QES PIN. This, + however, is not part of the PKCS#15 + profile of the card. So for + verifying the QES PIN we actually + need both. The CAN may be given + here. If the CAN is not given here, + it will be prompted on the command + line or on the reader (depending on + the reader's capabilities). +

+ st_dv_certificate = filename; + st_certificate = filename; + st_key = filename; +

+ QES is only possible with a Comfort + Reader (CAT-K), which holds a + cryptographic key to authenticate + itself as signature terminal (ST). + We usually will use the reader's + capability to sign the data. + However, during developement you + may specify soft certificates and + keys for a ST. +

+ An example PKI can be found in the + example data for the + German + ID card emulator +

Configuration Options for DNIe

+ user_consent_enabled = bool; +

+ Configure the warning message when + performing a signature operation + with the DNIe. Only used if + compiled with + --enable-dnie-ui +

+ user_consent_app = filename; +

+ Specify the pinentry application to + use if warning is configured to be + displayed using pinentry (Default: + /usr/bin/pinentry). + Only used if compiled with + --enable-dnie-ui +

Configuration based on ATR

+

+ atrmask = hexstring; +

+ The mask is logically AND'd with an + card ATR prior to comparison with + the ATR reference value above. + Using this mask allows identifying + and configuring multiple ATRs as + the same card model. +

+ driver = name; +

+ When enabled, overrides all + possible settings from the card + drivers built-in card configuration + list. +

+ name = name; +

+ Set card name for card drivers that + allows it. +

+ type = num; +

+ Allows setting the exact type of + the card internally used by the + card driver. Allowed values can be + found in the source code of + cards.h. +

+ flags = value... ; +

+ Card flags as an hex value. + Multiple values are OR'd together. + Depending on card driver, this + allows fine-tuning the capabilities + in the card driver for your card. +

+ Optionally, some known parameters + can be specified as strings: +

  • + rng: + On-board random number + source +

  • + keep_alive: + Request the card driver + to send a "keep alive" + command before each + transaction to make + sure that the required + applet is still + selected. +

+

+ pkcs15emu = name; +

+ When using PKCS#15 emulation, force + the emulation driver for specific + cards. Required for external + drivers, but can be used with + built-in drivers, too. +

+ force_protocol = value; +

+ Force protocol selection for + specific cards. Known parameters: +

  • + t0 +

  • + t1 +

  • + raw +

+

+ md_read_only = bool; +

+ Mark card as read/only card in + Minidriver/BaseCSP interface + (Default: false). +

+ md_supports_X509_enrollment = bool; +

+ Indicate X509 enrollment support at + Minidriver/BaseCSP interface + (Default: false). +

+ md_guid_as_id = bool; +

+ Use the GUID generated for the key + as id in the PKCS#15 structure + (Default: false, i.e. auto generated) +

+ md_guid_as_label = bool; +

+ Use the GUID generated for the key + as label in the PKCS#15 structure + (Default: false, + i.e. no label set). +

+ md_supports_container_key_gen = bool; +

+ Card allows generating key pairs on the card (Default: false). +

+ md_supports_container_key_import = bool; +

+ Card allows importing private keys + (Default: false). +

+ md_pinpad_dlg_title = value; +

+ Window title of the PIN pad dialog + (Default: "Windows + Security"). +

+ md_pinpad_dlg_icon = filename; +

+ Filename of the icon for the PIN + pad dialog; use + "" for no icon + (Default: Built-in smart card icon). +

+ md_pinpad_dlg_main = value; +

+ Main instruction of the PIN pad + dialog (Default: "OpenSC + Smart Card Provider"). +

+ md_pinpad_dlg_content_user = value; +

+ Content of the PIN pad dialog for + role "user" (Default: + "Please enter your PIN on the PIN + pad."). +

+ md_pinpad_dlg_content_user_sign = value; +

+ Content of the PIN pad dialog for + role "user+signature" (Default: + "Please enter your digital signature + PIN on the PIN pad."). +

+ md_pinpad_dlg_content_admin = value; +

+ Content of the PIN pad dialog for + role "admin" (Default: + "Please enter your PIN to unblock the + user PIN on the PIN pad.") +

+ md_pinpad_dlg_expanded = value; +

+ Expanded information of the PIN pad + dialog (Default: "This window will be + closed automatically after the PIN has been + submitted on the PIN pad (timeout typically + after 30 seconds).") +

+ md_pinpad_dlg_enable_cancel = bool; +

+ Allow the user to cancel the PIN + pad dialog (Default: + false). + + If this value is set to + true, the user needs to + click "OK" to start the PIN verification on the + PIN pad. The user can choose the default + behavior by enabling or disabling the checkbox + of the dialog. The setting is saved by the + program's full path + (program_path) that + uses OpenSC. +

+ The registry key HKCU\Software\OpenSC + Project\OpenSC\md_pinpad_dlg_enable_cancel\program_path + overwrites this setting with a + DWORD set to either + 1 (enabled) or + 0 (disabled). +

+ md_pinpad_dlg_timeout = num; +

+ Time in seconds for the progress + bar of the PIN pad dialog to tick. + 0 removes the + progress bar (Default: + 30). +

+ notify_card_inserted = value; + notify_card_inserted_text = value; +

+ Notification title and text when + card was inserted (Default: + "Smart card + detected", ATR of + the card). +

+ notify_card_removed = value; + notify_card_removed_text = value; +

+ Notification title and text when + card was removed (Default: + "Smart card + removed", name of + smart card reader). +

+ notify_pin_good = value; + notify_pin_good_text = value; +

+ Notification title and text when + PIN was verified (Default: + "PIN verified", + "Smart card is + unlocked"). +

+ notify_pin_bad = value; + notify_pin_bad_text = value; +

+ Notification title and text when + PIN was wrong (Default: + "PIN not + verified", + "Smart card is + locked"). +

+

Configuration of PKCS#15 Framework

+ use_file_caching = bool; +

+ Whether to cache the card's files (e.g. + certificates) on disk in + file_cache_dir (Default: + false). +

+ If caching is done by a system process, the + cached files may be placed inaccessible from + the user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. +

+ file_cache_dir = filename; +

+ Where to cache the card's files. The default values are: +

  • + HOME/.eid/cache/ (Unix) +

  • + USERPROFILE\.eid-cache\ (Windows) +

+

+ If caching is done by a system process, the + cached files may be placed inaccessible from + a user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. +

+ use_pin_caching = bool; +

+ Use PIN caching (Default: true)? +

+ pin_cache_counter = num; +

+ How many times to use a PIN from cache before + re-authenticating it (Default: + 10)? +

+ pin_cache_ignore_user_consent = bool; +

+ Older PKCS#11 applications not supporting + CKA_ALWAYS_AUTHENTICATE may + need to set this to get signatures to work with + some cards (Default: false). +

+ enable_pkcs15_emulation = bool; +

+ Enable pkcs15 emulation (Default: + true). +

+ try_emulation_first = bool; +

+ Prefer pkcs15 emulation code before the normal + pkcs15 processing (Default: + no). Some cards work in + emu-only mode, and do not depend on this + option. +

+ enable_builtin_emulation = bool; +

+ Enable builtin emulators (Default: + true). +

+ builtin_emulators = emulators; +

+ List of the builtin pkcs15 emulators to test + (Default: westcos, openpgp, infocamere, + starcert, tcos, esteid, itacns, postecert, + PIV-II, cac, gemsafeGPK, gemsafeV1, actalis, + atrust-acos, tccardos, entersafe, pteid, + oberthur, sc-hsm, dnie, gids, iasecc, jpki, + coolkey, din66291) +

+ pkcs11_enable_InitToken = bool; +

+ Enable initialization and card recognition + (Default: false). +

+ emulate name { + block_contents + } + +

+ Configuration options for a PKCS#15 emulator + where name is a + short name for an external card driver. +

+ module = filename; +

+ For pkcs15 emulators loaded from an + external shared library/DLL, you need to + specify the path name of the module and + customize the card_atr example above + correctly. +

+ function = name; +

+ Get the init function name of the + emulator (Default: + sc_pkcs15_init_func_ex) +

+ application hexstring { + block_contents + } + +

+ Configuration of the on-card-application where + hexstring is the + application identifier (AID). +

+ type = name; +

+ Type of application where + name is one + of: +

  • + generic +

  • + protected +

+

+ Used to distinguish the common access + application and application for which + authentication to perform some + operation cannot be obtained with the + common procedures (ex. object creation + protected by secure messaging). Used + by PKCS#11 module configured to expose + restricted number of slots. (for ex. + configured to expose only User PIN + slot, User and Sign PINs slots, ...) +

+ model = name; +
+ disable = bool; +

+ Do not expose application in PKCS#15 + framework (Default: + false) +

Configuration of Tokend

+ score = num; +

+ Score for OpenSC.tokend + (Default: 300). The tokend with + the highest score shall be used. +

+ ignore_private_certificate = bool; +

+ Tokend ignore to read PIN protected certificate + that is set + SC_PKCS15_CO_FLAG_PRIVATE flag + (Default: true). +

Configuration of PKCS#11

+ max_virtual_slots = num; +

+ Maximum Number of virtual slots (Default: + 16). If there are more slots + than defined here, the remaining slots will be + hidden from PKCS#11. +

+ slots_per_card = num; +

+ Maximum number of slots per smart card (Default: + 4). If the card has fewer keys + than defined here, the remaining number of slots + will be empty. +

+ lock_login = bool; +

+ By default, the OpenSC PKCS#11 module will not lock + your card once you authenticate to the card via + C_Login (Default: + false). + + Thus the other users or other applications is not + prevented from connecting to the card and perform + crypto operations (which may be possible because + you have already authenticated with the card). This + setting is not very secure. +

+ Also, if your card is not locked, you can enconter + problems due to limitation of the OpenSC framework, + that still is not thoroughly tested in the multi + threads environment. +

+ Your settings will be more secure if you choose to + lock your card. Nevertheless this behavior is a + known violation of PKCS#11 specification. Now once + one application has started using your card with + C_Login, no other application + can use it, until the first is done and calls + C_Logout or + C_Finalize. In the case of many + PKCS#11 application this does not happen until you + exit the application. +

+ Thus it is impossible to use several smart card + aware applications at the same time, e.g. you + cannot run both Firefox + and Thunderbird at the + same time, if both are configured to use your smart + card. +

+ atomic = bool; +

+ By default, interacting with the OpenSC PKCS#11 + module may change the state of the token, e.g. + whether a user is logged in or not (Default: + false). +

+ Thus other users or other applications may change + or use the state of the token unknowingly. Other + applications may create signatures abusing an + existing login or they may logout unnoticed. +

+ With this setting enabled the login state of the + token is tracked and cached (including the PIN). + Every transaction is preceded by restoring the + login state. After every transaction a logout is + performed. This setting by default also enables + lock_login to disable access for + other applications during the atomic transactions. +

+ Please note that any PIN-pad should be disabled + (see enable_pinpad), because the + user would have to input his PIN for every + transaction. +

+ init_sloppy = bool; +

+ With this setting disabled, the OpenSC PKCS#11 + module will initialize the slots available when the + application calls C_GetSlotList. + With this setting enabled, the slots will also get + initialized when C_GetSlotInfo + is called (Default: true). +

+ This setting is a workaround for + Java which does not call + C_GetSlotList when configured + with a static slot instead of + slotListIndex. +

+ user_pin_unblock_style = mode; +

+ User PIN unblock style mode + is one of: +

  • + none (Default): PIN + unblock is not possible with PKCS#11 API +

  • + set_pin_in_unlogged_session: + C_SetPIN in unlogged + session: PUK is passed as the + OldPin argument of the + C_SetPIN call. +

  • + set_pin_in_specific_context: + C_SetPIN in the + CKU_SPECIFIC_CONTEXT + logged session: PUK is passed as the + OldPin argument of the + C_SetPIN call. +

  • + init_pin_in_so_session: + C_InitPIN in + CKU_SO logged session: + User PIN 'UNBLOCK' is protected by SOPIN. + (PUK == SOPIN). +

+

+ create_puk_slot = bool; +

+ Create slot for unblocking PIN with PUK (Default: + false). This way PKCS#11 API can + be used to login with PUK and change a PIN. May + cause problems with some applications like + Firefox and + Thunderbird. +

+ create_slots_for_pins = mode... ; +

+ Symbolic names of PINs for which slots are created + where mode is a list of: +

  • + all (Default): All + non-SO-PIN, non-unblocking PINs +

  • + user: The first + global or first local PIN +

  • + sign: The second PIN + (first local, second global or second + local) +

+

+ Card can contain more then one PINs or more then + one on-card application with its own PINs. + Normally, to access all of them with the PKCS#11 + API a slot has to be created for all of them. Many + slots could be annoying for some of widely used + application, like FireFox. This configuration + parameter allows to select the PIN(s) for which + PKCS#11 slot will be created. +

+ Only PINs initialised, non-SO-PIN, non-unblocking + are associated with symbolic name. +

+ For the module to simulate the opensc-onepin module + behavior the following option + create_slots_for_pins = "user"; +

Environment

+ OPENSC_CONF +

+ Filename for a user defined configuration file +

+ If this environment variable is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\ConfigFile is + checked. +

+ OPENSC_DEBUG +

+ See + debug = num; + +

+ OPENSC_DRIVER +

+ See + card_drivers = name... ; + +

+ CARDMOD_LOW_LEVEL_DEBUG +

+ Write minidriver debug information to + C:\tmp\md.log, if set to + 1. +

+ If this environment variable is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\MiniDriverDebug is + checked. +

+ PIV_EXT_AUTH_KEY, + PIV_9A_KEY, + PIV_9C_KEY, + PIV_9D_KEY, + PIV_9E_KEY +

+ PIV configuration during initialization with + piv-tool. +

Files

+ /usr/etc/opensc.conf +

+ System-wide configuration file +

+ /usr/share/doc/opensc/opensc.conf +

+ Extended example configuration file +


Name

pkcs15-profile — format of profile for pkcs15-init

Description

+ The pkcs15-init utility for PKCS #15 smart card + personalization is controlled via profiles. When starting, it will read two + such profiles at the moment, a generic application profile, and a card + specific profile. The generic profile must be specified on the command line, + while the card-specific file is selected based on the type of card detected. +

+ The generic application profile defines general information about the card + layout, such as the path of the application DF, various PKCS #15 files within + that directory, and the access conditions on these files. It also defines + general information about PIN, key and certificate objects. Currently, there + is only one such generic profile, pkcs15.profile. +

+ The card specific profile contains additional information required during + card initialization, such as location of PIN files, key references etc. + Profiles currently reside in @pkgdatadir@ +

Syntax

+ This section should contain information about the profile syntax. Will add + this soonishly. +

See also

+ pkcs15-init(1), + pkcs15-crypt(1) +

diff -Nru opensc-0.17.0/doc/files/files.xml opensc-0.19.0/doc/files/files.xml --- opensc-0.17.0/doc/files/files.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/files/files.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,10 @@ + + + + + OpenSC Manual Pages: Section 5 + + + + diff -Nru opensc-0.17.0/doc/files/Makefile.am opensc-0.19.0/doc/files/Makefile.am --- opensc-0.17.0/doc/files/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/files/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,32 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +dist_noinst_DATA = pkcs15-profile.5.xml opensc.conf.5.xml.in files.xml +if ENABLE_DOC +html_DATA = files.html +endif + +if ENABLE_MAN +man5_MANS = pkcs15-profile.5 opensc.conf.5 +endif + +opensc.conf.5.xml opensc.conf.5: $(srcdir)/opensc.conf.5.xml.in + sed \ + -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ + -e 's|@docdir[@]|$(docdir)|g' \ + -e 's|@libdir[@]|$(libdir)|g' \ + -e 's|@DYN_LIB_EXT[@]|$(DYN_LIB_EXT)|g' \ + -e 's|@DEFAULT_PCSC_PROVIDER[@]|$(DEFAULT_PCSC_PROVIDER)|g' \ + -e 's|@PROFILE_DIR_DEFAULT[@]|$(PROFILE_DIR_DEFAULT)|g' \ + -e 's|@DEFAULT_SM_MODULE[@]|$(DEFAULT_SM_MODULE)|g' \ + < $< > opensc.conf.5.xml + $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/manpages" --xinclude -o $@ man.xsl opensc.conf.5.xml + +files.html: $(srcdir)/files.xml $(wildcard $(srcdir)/*.5.xml) opensc.conf.5.xml + $(XSLTPROC) --nonet --path "$(builddir):$(srcdir)/..:$(xslstylesheetsdir)/html" --xinclude -o $@ html.xsl $< + +%.5: $(srcdir)/%.5.xml + sed -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' < $< \ + | $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/manpages" --xinclude -o $@ man.xsl $< + +clean-local: + -rm -rf $(html_DATA) $(man5_MANS) opensc.conf.5.xml diff -Nru opensc-0.17.0/doc/files/opensc.conf.5.xml.in opensc-0.19.0/doc/files/opensc.conf.5.xml.in --- opensc-0.17.0/doc/files/opensc.conf.5.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/files/opensc.conf.5.xml.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1626 @@ + + + + opensc.conf + 5 + OpenSC + OpenSC File Formats + opensc + + + + opensc.conf + configuration file for OpenSC + + + + Description + + OpenSC obtains configuration data from the following sources in the following order + + + command-line options + + + environment variables + + + Windows registry key in + HKEY_CURRENT_USER (if available) + + + Windows registry key in + HKEY_LOCAL_MACHINE (if available) + + + system-wide configuration file + (@sysconfdir@/opensc.conf) + + + + + The configuration file, opensc.conf, is composed + of blocks, which, in general, have the + following format: + +key, name { + block_contents +} + + block_contents is one or more + block_items where a + block_item is one of + + + # comment string + + + key, name = value; + + + block + + + + + At the root level, opensc.conf should contain + one or more application specific configuration blocks: + +app application { + block_contents +} + + application + specifies one of: + + + default: The fall-back configuration block for all applications + + + opensc-pkcs11: Configuration block for the PKCS#11 module (opensc-pkcs11@DYN_LIB_EXT@) + + + onepin-opensc-pkcs11: Configuration block for the PKCS#11 one-PIN-module (onepin-opensc-pkcs11@DYN_LIB_EXT@) + + + cardmod: Configuration block for Windows' minidriver (opensc-minidriver.dll) + + + tokend: Configuration block for macOS' tokend (OpenSC.tokend) + + + cardos-tool, + cryptoflex-tool, + dnie-tool, + egk-tool, + eidenv, + gids-tool, + iasecc-tool, + netkey-tool, + npa-tool, + openpgp-tool, + opensc-asn1, + opensc-explorer, + opensc-notify, + opensc-tool, + piv-tool, + pkcs11-tool, + pkcs15-crypt, + pkcs15-init, + pkcs15-tool, + sc-hsm-tool, + westcos-tool: + Configuration block for OpenSC tools + + + + + + + Configuration Options + + + + + + + Amount of debug info to print (Default: + 0). A greater value means more + debug info. + + + The environment variable + OPENSC_DEBUG overwrites this + setting. + + + + + + + + The file to which debug output will be written + (Default: stderr). Special + values stdout and + stderr are recognized. + + + + + + + + PKCS#15 initialization/personalization profiles + directory for + + pkcs15-init + 1. + + (Default: @PROFILE_DIR_DEFAULT@). + + + If this configuration value is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\ProfileDir is + checked. + + + + + + + + Disable pop-ups of built-in GUI (Default: false). + + + + + + + + Enable default card driver (Default: + false). Default card driver is + explicitly enabled for + + opensc-explorer + 1. + + and + + opensc-tool + 1. + + + + + + + + + Whitelist of card drivers to load at start-up. + The special value internal (the + default) will load all statically linked drivers. + + + If an unknown (i.e. not internal or old) driver is + supplied, a separate configuration configuration + block has to be written for the driver. A special + value old will load all + statically linked drivers that may be removed in + the future. + + + The list of supported card driver names can be + retrieved from the output of opensc-tool + --list-drivers. + + + The environment variable + OPENSC_DRIVER overwrites this + setting. + + + + + + + + List of readers to ignore (Default: empty). If any + of the comma separated strings listed is matched in + a reader name (case sensitive, partial matching + possible), the reader is ignored by OpenSC. Use + opensc-tool --list-readers to + see all currently connected readers. + + + + + + + + + Configuration of the smart card reader driver where name is one of: + + + ctapi: See + + + + pcsc: See + + + openct: See + + + cryptotokenkit: Configuration block for CryptoTokenKit readers + + + + + See . + + + + + + + + + Configuration of the card driver where name is one of: + + + npa: See + + + dnie: See + + + Any other value: Configuration block for an externally loaded card driver + + + + + + + + + + + In addition to the built-in list of known cards in + the card driver, you can configure a new card for + the driver using the + block. + + + For details see . + + + + + + + + + Configuration options for the secure messaging profile name: + + + + + + + + Name of external SM module (Default: @DEFAULT_SM_MODULE@). + + + + + + + + Directory with external SM module + (Default: @libdir@). + + + If this configuration value is not + found on Windows, the registry key + Software\OpenSC + Project\OpenSC\SmDir is + checked. + + + + + + + + Specific data to tune the module initialization. + + + + + + + + Secure messaging mode. Known parameters: + + + transmit: + In this mode the + procedure to securize + an APDU is called by + the OpenSC general APDU + transmit procedure. In + this mode all APDUs, + except the ones + filtered by the card + specific procedure, are + securized. + + + acl: + In this mode APDU are + securized only if + needed by the ACLs of + the command to be + executed. + + + + + + + + + + Secure messaging type specific flags. + + + + + + + + Default KMC of the GP Card Manager for the Oberthur's Java cards. + + + + + + + + + + + + + + Keyset values from IAM profiles of + the Gemalto IAS/ECC cards with an + optional application identifier + + + + + + + + + + + Internal configuration options where name is one of: + + + pkcs15: See + + + tokend: See + + + + + + + + + + + Parameters for the OpenSC PKCS11 module. + + + For details see . + + + + + + + Configuration of Smart Card Reader Driver + + + Configuration Options for all Reader Drivers + + + + + + + + Limit command and response sizes + (Default: + + = 255, + + = 256) . Some + Readers don't propagate their + transceive capabilities correctly. + max_send_size and max_recv_size + allow setting the limits manually, + for example to enable extended + length capabilities. + + + + + + + + Detect reader capabilities with + escape commands (wrapped APDUs with + CLA=0xFF as defined by PC/SC pt. 3 + and BSI TR-03119, e.g. for getting + the UID, escaped PIN commands and + the reader's firmware version, + Default: false) + + + + + + + Configuration of CT-API Readers + + + + + + + Load the specified CT-API module with the specified number of ports. + + + + + + + Configuration of PC/SC Readers + + + + + + + Connect to reader in exclusive mode + (Default: false)? + This option has no effect in Windows' minidriver. + + + + + + + + What to do when disconnecting from + a card (SCardDisconnect). Valid + values are + leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. + + + + + + + + What to do at the end of a + transaction (SCardEndTransaction). + Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. + + + + + + + + What to do when reconnection to a + card (SCardReconnect). Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. + + + + + + + + Enable pinpad if detected (PC/SC + v2.0.2 Part 10, Default: + true) + + + + + + + + Some pinpad readers can only handle + one exact length of the PIN. + + sets this value so that OpenSC + expands the padding to this length + (Default: 0, + i.e. not fixed). + + + + + + + + Use specific PC/SC provider + (Default: + @DEFAULT_PCSC_PROVIDER@). + + + + + + + Configuration of OpenCT Readers + + + + + + + Virtual readers to allocate (Default: 2). + + + + + + + + + Configuration Options for German ID Card + + + + + + + German ID card requires the CAN to + be verified before QES PIN. This, + however, is not part of the PKCS#15 + profile of the card. So for + verifying the QES PIN we actually + need both. The CAN may be given + here. If the CAN is not given here, + it will be prompted on the command + line or on the reader (depending on + the reader's capabilities). + + + + + + + + + + QES is only possible with a Comfort + Reader (CAT-K), which holds a + cryptographic key to authenticate + itself as signature terminal (ST). + We usually will use the reader's + capability to sign the data. + However, during developement you + may specify soft certificates and + keys for a ST. + + + An example PKI can be found in the + example data for the + German + ID card emulator + + + + + + + Configuration Options for DNIe + + + + + + + Configure the warning message when + performing a signature operation + with the DNIe. Only used if + compiled with + + + + + + + + + Specify the pinentry application to + use if warning is configured to be + displayed using pinentry (Default: + /usr/bin/pinentry). + Only used if compiled with + + + + + + + + Configuration based on ATR + + + + + + + + The mask is logically AND'd with an + card ATR prior to comparison with + the ATR reference value above. + Using this mask allows identifying + and configuring multiple ATRs as + the same card model. + + + + + + + + When enabled, overrides all + possible settings from the card + drivers built-in card configuration + list. + + + + + + + + Set card name for card drivers that + allows it. + + + + + + + + Allows setting the exact type of + the card internally used by the + card driver. Allowed values can be + found in the source code of + cards.h. + + + + + + + + Card flags as an hex value. + Multiple values are OR'd together. + Depending on card driver, this + allows fine-tuning the capabilities + in the card driver for your card. + + + Optionally, some known parameters + can be specified as strings: + + + rng: + On-board random number + source + + + keep_alive: + Request the card driver + to send a "keep alive" + command before each + transaction to make + sure that the required + applet is still + selected. + + + + + + + + + + When using PKCS#15 emulation, force + the emulation driver for specific + cards. Required for external + drivers, but can be used with + built-in drivers, too. + + + + + + + + Force protocol selection for + specific cards. Known parameters: + + + t0 + + + t1 + + + raw + + + + + + + + + + Mark card as read/only card in + Minidriver/BaseCSP interface + (Default: false). + + + + + + + + Indicate X509 enrollment support at + Minidriver/BaseCSP interface + (Default: false). + + + + + + + + Use the GUID generated for the key + as id in the PKCS#15 structure + (Default: false, i.e. auto generated) + + + + + + + + Use the GUID generated for the key + as label in the PKCS#15 structure + (Default: false, + i.e. no label set). + + + + + + + + Card allows generating key pairs on the card (Default: false). + + + + + + + + Card allows importing private keys + (Default: false). + + + + + + + + Window title of the PIN pad dialog + (Default: "Windows + Security"). + + + + + + + + Filename of the icon for the PIN + pad dialog; use + "" for no icon + (Default: Built-in smart card icon). + + + + + + + + Main instruction of the PIN pad + dialog (Default: "OpenSC + Smart Card Provider"). + + + + + + + + Content of the PIN pad dialog for + role "user" (Default: + "Please enter your PIN on the PIN + pad."). + + + + + + + + Content of the PIN pad dialog for + role "user+signature" (Default: + "Please enter your digital signature + PIN on the PIN pad."). + + + + + + + + Content of the PIN pad dialog for + role "admin" (Default: + "Please enter your PIN to unblock the + user PIN on the PIN pad.") + + + + + + + + Expanded information of the PIN pad + dialog (Default: "This window will be + closed automatically after the PIN has been + submitted on the PIN pad (timeout typically + after 30 seconds).") + + + + + + + + Allow the user to cancel the PIN + pad dialog (Default: + false). + + If this value is set to + true, the user needs to + click "OK" to start the PIN verification on the + PIN pad. The user can choose the default + behavior by enabling or disabling the checkbox + of the dialog. The setting is saved by the + program's full path + (program_path) that + uses OpenSC. + + + The registry key HKCU\Software\OpenSC + Project\OpenSC\md_pinpad_dlg_enable_cancel\program_path + overwrites this setting with a + DWORD set to either + 1 (enabled) or + 0 (disabled). + + + + + + + + Time in seconds for the progress + bar of the PIN pad dialog to tick. + 0 removes the + progress bar (Default: + 30). + + + + + + + + + Notification title and text when + card was inserted (Default: + "Smart card + detected", ATR of + the card). + + + + + + + + + Notification title and text when + card was removed (Default: + "Smart card + removed", name of + smart card reader). + + + + + + + + + Notification title and text when + PIN was verified (Default: + "PIN verified", + "Smart card is + unlocked"). + + + + + + + + + Notification title and text when + PIN was wrong (Default: + "PIN not + verified", + "Smart card is + locked"). + + + + + + + + Configuration of PKCS#15 Framework + + + + + + + Whether to cache the card's files (e.g. + certificates) on disk in + (Default: + false). + + + If caching is done by a system process, the + cached files may be placed inaccessible from + the user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. + + + + + + + + Where to cache the card's files. The default values are: + + + + HOME/.eid/cache/ (Unix) + + + + + USERPROFILE\.eid-cache\ (Windows) + + + + + + If caching is done by a system process, the + cached files may be placed inaccessible from + a user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. + + + + + + + + Use PIN caching (Default: true)? + + + + + + + + How many times to use a PIN from cache before + re-authenticating it (Default: + 10)? + + + + + + + + Older PKCS#11 applications not supporting + CKA_ALWAYS_AUTHENTICATE may + need to set this to get signatures to work with + some cards (Default: false). + + + + + + + + Enable pkcs15 emulation (Default: + true). + + + + + + + + Prefer pkcs15 emulation code before the normal + pkcs15 processing (Default: + no). Some cards work in + emu-only mode, and do not depend on this + option. + + + + + + + + Enable builtin emulators (Default: + true). + + + + + + + + List of the builtin pkcs15 emulators to test + (Default: westcos, openpgp, infocamere, + starcert, tcos, esteid, itacns, postecert, + PIV-II, cac, gemsafeGPK, gemsafeV1, actalis, + atrust-acos, tccardos, entersafe, pteid, + oberthur, sc-hsm, dnie, gids, iasecc, jpki, + coolkey, din66291) + + + + + + + + Enable initialization and card recognition + (Default: false). + + + + + + + + Configuration options for a PKCS#15 emulator + where name is a + short name for an external card driver. + + + + + + + + For pkcs15 emulators loaded from an + external shared library/DLL, you need to + specify the path name of the module and + customize the card_atr example above + correctly. + + + + + + + + Get the init function name of the + emulator (Default: + sc_pkcs15_init_func_ex) + + + + + + + + + + + + Configuration of the on-card-application where + hexstring is the + application identifier (AID). + + + + + + + + Type of application where + name is one + of: + + + generic + + + protected + + + + + Used to distinguish the common access + application and application for which + authentication to perform some + operation cannot be obtained with the + common procedures (ex. object creation + protected by secure messaging). Used + by PKCS#11 module configured to expose + restricted number of slots. (for ex. + configured to expose only User PIN + slot, User and Sign PINs slots, ...) + + + + + + + + + + + + + Do not expose application in PKCS#15 + framework (Default: + false) + + + + + + + + + + Configuration of Tokend + + + + + + + Score for OpenSC.tokend + (Default: 300). The tokend with + the highest score shall be used. + + + + + + + + Tokend ignore to read PIN protected certificate + that is set + SC_PKCS15_CO_FLAG_PRIVATE flag + (Default: true). + + + + + + + Configuration of PKCS#11 + + + + + + + Maximum Number of virtual slots (Default: + 16). If there are more slots + than defined here, the remaining slots will be + hidden from PKCS#11. + + + + + + + + Maximum number of slots per smart card (Default: + 4). If the card has fewer keys + than defined here, the remaining number of slots + will be empty. + + + + + + + + By default, the OpenSC PKCS#11 module will not lock + your card once you authenticate to the card via + C_Login (Default: + false). + + Thus the other users or other applications is not + prevented from connecting to the card and perform + crypto operations (which may be possible because + you have already authenticated with the card). This + setting is not very secure. + + + Also, if your card is not locked, you can enconter + problems due to limitation of the OpenSC framework, + that still is not thoroughly tested in the multi + threads environment. + + + Your settings will be more secure if you choose to + lock your card. Nevertheless this behavior is a + known violation of PKCS#11 specification. Now once + one application has started using your card with + C_Login, no other application + can use it, until the first is done and calls + C_Logout or + C_Finalize. In the case of many + PKCS#11 application this does not happen until you + exit the application. + + + Thus it is impossible to use several smart card + aware applications at the same time, e.g. you + cannot run both Firefox + and Thunderbird at the + same time, if both are configured to use your smart + card. + + + + + + + + By default, interacting with the OpenSC PKCS#11 + module may change the state of the token, e.g. + whether a user is logged in or not (Default: + false). + + + Thus other users or other applications may change + or use the state of the token unknowingly. Other + applications may create signatures abusing an + existing login or they may logout unnoticed. + + + With this setting enabled the login state of the + token is tracked and cached (including the PIN). + Every transaction is preceded by restoring the + login state. After every transaction a logout is + performed. This setting by default also enables + to disable access for + other applications during the atomic transactions. + + + Please note that any PIN-pad should be disabled + (see ), because the + user would have to input his PIN for every + transaction. + + + + + + + + With this setting disabled, the OpenSC PKCS#11 + module will initialize the slots available when the + application calls C_GetSlotList. + With this setting enabled, the slots will also get + initialized when C_GetSlotInfo + is called (Default: true). + + + This setting is a workaround for + Java which does not call + C_GetSlotList when configured + with a static slot instead of + slotListIndex. + + + + + + + + User PIN unblock style mode + is one of: + + + none (Default): PIN + unblock is not possible with PKCS#11 API + + + set_pin_in_unlogged_session: + C_SetPIN in unlogged + session: PUK is passed as the + OldPin argument of the + C_SetPIN call. + + + set_pin_in_specific_context: + C_SetPIN in the + CKU_SPECIFIC_CONTEXT + logged session: PUK is passed as the + OldPin argument of the + C_SetPIN call. + + + init_pin_in_so_session: + C_InitPIN in + CKU_SO logged session: + User PIN 'UNBLOCK' is protected by SOPIN. + (PUK == SOPIN). + + + + + + + + + + Create slot for unblocking PIN with PUK (Default: + false). This way PKCS#11 API can + be used to login with PUK and change a PIN. May + cause problems with some applications like + Firefox and + Thunderbird. + + + + + + + + Symbolic names of PINs for which slots are created + where mode is a list of: + + + all (Default): All + non-SO-PIN, non-unblocking PINs + + + user: The first + global or first local PIN + + + sign: The second PIN + (first local, second global or second + local) + + + + + Card can contain more then one PINs or more then + one on-card application with its own PINs. + Normally, to access all of them with the PKCS#11 + API a slot has to be created for all of them. Many + slots could be annoying for some of widely used + application, like FireFox. This configuration + parameter allows to select the PIN(s) for which + PKCS#11 slot will be created. + + + Only PINs initialised, non-SO-PIN, non-unblocking + are associated with symbolic name. + + + For the module to simulate the opensc-onepin module + behavior the following option + + + + + + + + + + Environment + + + + OPENSC_CONF + + + Filename for a user defined configuration file + + + If this environment variable is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\ConfigFile is + checked. + + + + + OPENSC_DEBUG + + + See + + + + + OPENSC_DRIVER + + + See + + + + + CARDMOD_LOW_LEVEL_DEBUG + + + Write minidriver debug information to + C:\tmp\md.log, if set to + 1. + + + If this environment variable is not found on + Windows, the registry key + Software\OpenSC + Project\OpenSC\MiniDriverDebug is + checked. + + + + + PIV_EXT_AUTH_KEY, + PIV_9A_KEY, + PIV_9C_KEY, + PIV_9D_KEY, + PIV_9E_KEY + + + PIV configuration during initialization with + piv-tool. + + + + + + + Files + + + + @sysconfdir@/opensc.conf + + + System-wide configuration file + + + + + @docdir@/opensc.conf + + + Extended example configuration file + + + + + + diff -Nru opensc-0.17.0/doc/files/pkcs15-profile.5.xml opensc-0.19.0/doc/files/pkcs15-profile.5.xml --- opensc-0.17.0/doc/files/pkcs15-profile.5.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/files/pkcs15-profile.5.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,61 @@ + + + + pkcs15-profile + 5 + OpenSC + OpenSC File Formats + opensc + + + + pkcs15-profile + format of profile for pkcs15-init + + + + Description + + The pkcs15-init utility for PKCS #15 smart card + personalization is controlled via profiles. When starting, it will read two + such profiles at the moment, a generic application profile, and a card + specific profile. The generic profile must be specified on the command line, + while the card-specific file is selected based on the type of card detected. + + + The generic application profile defines general information about the card + layout, such as the path of the application DF, various PKCS #15 files within + that directory, and the access conditions on these files. It also defines + general information about PIN, key and certificate objects. Currently, there + is only one such generic profile, pkcs15.profile. + + + The card specific profile contains additional information required during + card initialization, such as location of PIN files, key references etc. + Profiles currently reside in @pkgdatadir@ + + + + + Syntax + + This section should contain information about the profile syntax. Will add + this soonishly. + + + + + See also + + + pkcs15-init + 1 + , + + pkcs15-crypt + 1 + + + + + diff -Nru opensc-0.17.0/doc/Makefile.am opensc-0.19.0/doc/Makefile.am --- opensc-0.17.0/doc/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,6 +1,6 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -SUBDIRS = tools +SUBDIRS = tools files dist_noinst_SCRIPTS = html.xsl man.xsl dist_noinst_DATA = api.css diff -Nru opensc-0.17.0/doc/tools/cardos-tool.1.xml opensc-0.19.0/doc/tools/cardos-tool.1.xml --- opensc-0.17.0/doc/tools/cardos-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/cardos-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -49,6 +49,13 @@ + , + + + Print help message on screen. + + + , @@ -56,11 +63,31 @@ - number, - number + num, + num + + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + + + + + arg, + arg - Specify the reader number number to use. - The default is reader 0. + Specify startkey for format. + + + + arg, + arg + + Change Startkey with given APDU command. @@ -82,4 +109,10 @@ + + + Authors + cardos-tool was written by + Andreas Jellinghaus aj@dungeon.inka.de. + diff -Nru opensc-0.17.0/doc/tools/completion-template opensc-0.19.0/doc/tools/completion-template --- opensc-0.17.0/doc/tools/completion-template 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/completion-template 2018-09-13 11:47:21.000000000 +0000 @@ -15,6 +15,14 @@ fi case "${prev}" in + MODULEOPTS) + _filedir so + return 0 + ;; + FILEOPTS) + _filedir + return 0 + ;; OPTSWITHARGS) return 0 ;; diff -Nru opensc-0.17.0/doc/tools/cryptoflex-tool.1.xml opensc-0.19.0/doc/tools/cryptoflex-tool.1.xml --- opensc-0.17.0/doc/tools/cryptoflex-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/cryptoflex-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -121,7 +121,8 @@ - + , + Reads a public key from the card, allowing the user to extract and store or use the public key @@ -133,9 +134,14 @@ num, num - Forces cryptoflex-tool to use - reader number num for operations. The default - is to use reader number 0, the first reader in the system. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -156,6 +162,15 @@ Verifies CHV1 before issuing commands + + + , + + + Causes cryptoflex-tool to + wait for a card insertion. + + @@ -170,4 +185,10 @@ + + Authors + cryptoflex-tool was written by + Juha Yrjölä juha.yrjola@iki.fi. + + diff -Nru opensc-0.17.0/doc/tools/dnie-tool.1.xml opensc-0.19.0/doc/tools/dnie-tool.1.xml --- opensc-0.17.0/doc/tools/dnie-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/dnie-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -68,7 +68,7 @@ Show DNIe sw version. - Displays sofware version for in-card DNIe OS + Displays software version for in-card DNIe OS @@ -83,11 +83,17 @@ - number, - number + num, + num - Specify the reader number to use. - The default is reader 0. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -119,10 +125,6 @@ - See also - opensc(7) - - Authors dnie-tool was written by Juan Antonio Martinez jonsito@terra.es. diff -Nru opensc-0.17.0/doc/tools/egk-tool.1.xml opensc-0.19.0/doc/tools/egk-tool.1.xml --- opensc-0.17.0/doc/tools/egk-tool.1.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/egk-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,115 @@ + + + + egk-tool + 1 + OpenSC + OpenSC Tools + opensc + + + + egk-tool + displays information on the German electronic health card (elektronische Gesundheitskarte, eGK) + + + + + + egk-tool + OPTIONS + + + + + Description + + The egk-tool utility is used to display information stored on the German elektronic health card (elektronische Gesundheitskarte, eGK). + + + + + Options + + + + + , + + Print help and exit. + + + + , + + Print version and exit. + + + + arg, + arg + + + Specify the reader to use. + Use -1 as arg + to automatically detect the reader to use. + By default, the first reader with a present card is used. + + + + + , + + + + Causes egk-tool to be more verbose. + Specify this flag several times to be more verbose. + + + + + + + Health Care Application (<abbrev>HCA</abbrev>) + + + + + Show 'Persönliche Versicherungsdaten' (XML). + + + + + + Show 'Allgemeine Versicherungsdaten' (XML). + + + + + + Show 'Geschützte Versicherungsdaten' (XML). + + + + + + Show 'Versichertenstammdaten-Status'. + + + + + + + + Authors + egk-tool was written by + Frank Morgner frankmorgner@gmail.com. + + + + diff -Nru opensc-0.17.0/doc/tools/eidenv.1.xml opensc-0.19.0/doc/tools/eidenv.1.xml --- opensc-0.17.0/doc/tools/eidenv.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/eidenv.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -69,9 +69,14 @@ num, num - - Use the given reader. The default is the first reader with a card. - + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + diff -Nru opensc-0.17.0/doc/tools/files.html opensc-0.19.0/doc/tools/files.html --- opensc-0.17.0/doc/tools/files.html 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/files.html 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1096 @@ +OpenSC Manual Pages: Section 5

OpenSC Manual Pages: Section 5


Table of Contents

opensc.conf — configuration file for OpenSC
pkcs15-profile — format of profile for pkcs15-init

Name

opensc.conf — configuration file for OpenSC

Description

+ OpenSC obtains configuration data from the following sources in the following order +

  1. + command-line options +

  2. + environment variables +

  3. + Windows registry (if available) +

  4. + system-wide configuration file + (/home/fm/.local/etc/opensc.conf) +

+

+ The configuration file, opensc.conf, is composed + of blocks, which, in general, have the + following format: +

+key [, name...] {
+	block_contents
+}
+			

+ block_contents is one or more + block_items where a + block_item is one of +

  • + # comment string +

  • + key [, name...] = value; +

  • + block +

+

+ At the root level, opensc.conf should contain + one or more application specific configuration blocks: +

+app application {
+	block_contents
+}
+			

+ application + specifies one of: +

  • + default: The fall-back configuration block for all applications +

  • + opensc-pkcs11: Configuration block for the PKCS#11 module (opensc-pkcs11.so) +

  • + onepin-opensc-pkcs11: Configuration block for the PKCS#11 one-PIN-module (onepin-opensc-pkcs11.so) +

  • + cardmod: Configuration block for Windows' minidriver (opensc-minidriver.dll) +

  • + tokend: Configuration block for macOS' tokend (OpenSC.tokend) +

  • + cardos-tool, + cryptoflex-tool, + dnie-tool, + egk-tool, + eidenv, + gids-tool, + iasecc-tool, + netkey-tool, + npa-tool, + openpgp-tool, + opensc-asn1, + opensc-explorer, + opensc-notify, + opensc-tool, + piv-tool, + pkcs11-tool, + pkcs15-crypt, + pkcs15-init, + pkcs15-tool, + sc-hsm-tool, + westcos-tool: + Configuration block for OpenSC tools +

+

Configuration Options

+ debug = num; +

+ Amount of debug info to print (Default: + 0). A greater value means more + debug info. +

+ The environment variable + OPENSC_DEBUG overwrites this + setting. +

+ debug_file = filename; +

+ The file to which debug output will be written + (Default: stderr). Special + values stdout and + stderr are recognized. +

+ profile_dir = filename; +

+ PKCS#15 initialization/personalization profiles + directory for + pkcs15-init(1). + + (Default: /home/fm/.local/share/opensc). +

+ If this configuration value is not found on + Windows, the registry key + HKLM\Software\OpenSC + Project\OpenSC\ProfileDir is + checked. +

+ disable_popups = bool; +

+ Disable pop-ups of built-in GUI (Default: false). +

+ enable_default_driver = bool; +

+ Enable default card driver (Default: + false). Default card driver is + explicitly enabled for + opensc-explorer(1). + + and + opensc-tool(1). + +

+ card_drivers = name... ; +

+ Whitelist of card drivers to load at start-up. + The special value internal (the + default) will load all statically linked drivers. +

+ If an unknown (i.e. not internal or old) driver is + supplied, a separate configuration configuration + block has to be written for the driver. A special + value old will load all + statically linked drivers that may be removed in + the future. +

+ The list of supported card driver names can be + retrieved from the output of opensc-tool + --list-drivers. +

+ The environment variable + OPENSC_DRIVER overwrites this + setting. +

+ ignored_readers = name... ; +

+ List of readers to ignore (Default: empty). If any + of the comma separated strings listed is matched in + a reader name (case sensitive, partial matching + possible), the reader is ignored by OpenSC. Use + opensc-tool --list-readers to + see all currently connected readers. +

+ reader_driver name { + block_contents + } + +

+ Configuration of the card reader driver where name is one of: +

+

+ For details see the section called “reader_driver Configuration Block”. +

+ card_driver name { + block_contents + } + +

+ Configuration of the card driver where name is one of: +

+

+ card_atr hexstring { + block_contents + } + +

+ In addition to the built-in list of known cards in + the card driver, you can configure a new card for + the driver using the card_atr + block. +

+ For details see the section called “card_atr Configuration Block”. +

+ secure_messaging name { + block_contents + } + +

+ Configuration options for the secure messaging profile name: +

+ module_name = filename; +

+ Name of external SM module (Default: libsmm-local.so). +

+ module_path = filename; +

+ Directory with external SM module + (Default: /home/fm/.local/lib). +

+ If this configuration value is not + found on Windows, the registry key + HKLM\Software\OpenSC + Project\OpenSC\SmDir is + checked. +

+ module_data = value; +

+ Specific data to tune the module initialization. +

+ mode = value; +

+ Secure messaging mode. Known parameters: +

  • + transmit: + In this mode the + procedure to securize + an APDU is called by + the OpenSC general APDU + transmit procedure. In + this mode all APDUs, + except the ones + filtered by the card + specific procedure, are + securized. +

  • + acl: + In this mode APDU are + securized only if + needed by the ACLs of + the command to be + executed. +

+

+ flags = value; +

+ Secure messaging type specific flags. +

+ kmc = hexstring; +

+ Default KMC of the GP Card Manager for the Oberthur's Java cards. +

+ ifd_serial = hexstring; +
+ keyset[_aid]_num_enc = + value; + keyset[_aid]_num_mac = + value; +

+ Keyset values from IAM profiles of + the Gemalto IAS/ECC cards with an + optional application identifier +

+ framework name { + block_contents + } + +

+ Internal configuration options where name is one of: +

+

+ pkcs11 { + block_contents + } + +

+ Parameters for the OpenSC PKCS11 module. +

+ For details see the section called “pkcs11 Configuration Block”. +

reader_driver Configuration Block

Configuration Options for all Reader Drivers

+ max_send_size = num; + max_recv_size = num; +

+ Limit command and response sizes + (Default: + max_send_size + = 255, + max_recv_size + = 256) . Some + Readers don't propagate their + transceive capabilities correctly. + max_send_size and max_recv_size + allow setting the limits manually, + for example to enable extended + length capabilities. +

+ enable_escape bool; +

+ Detect reader capabilities with + escape commands (wrapped APDUs with + CLA=0xFF as defined by PC/SC pt. 3 + and BSI TR-03119, e.g. for getting + the UID, escaped PIN commands and + the reader's firmware version, + Default: false) +

Special Configuration Option for CT-API Readers

+ module filename { + ports = nums; + } + +

+ Load the specified CT-API module with the specified number of ports. +

Special Configuration Options for PC/SC Readers

+ connect_exclusive = bool; +

+ Connect to reader in exclusive mode + (Default: false)? + This option has no effect in Windows' minidriver. +

+ disconnect_action = action; +

+ What to do when disconnecting from + a card (SCardDisconnect). Valid + values are + leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ transaction_end_action = action; +

+ What to do at the end of a + transaction (SCardEndTransaction). + Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ reconnect_action = action; +

+ What to do when reconnection to a + card (SCardReconnect). Valid values + are leave, + reset, + unpower (Default: + leave). + This option has no effect in Windows' minidriver. +

+ enable_pinpad = bool; +

+ Enable pinpad if detected (PC/SC + v2.0.2 Part 10, Default: + true) +

+ fixed_pinlength = num; +

+ Some pinpad readers can only handle + one exact length of the PIN. + fixed_pinlength + sets this value so that OpenSC + expands the padding to this length + (Default: 0, + i.e. not fixed). +

+ provider_library = filename; +

+ Use specific PC/SC provider + (Default: + libpcsclite.so.1). +

Special Configuration Option for OpenCT Readers

+ readers = num; +

+ Virtual readers to allocate (Default: 2). +

Special Configuration Options for German ID Card

+ can = value; +

+ German ID card requires the CAN to + be verified before QES PIN. This, + however, is not part of the PKCS#15 + profile of the card. So for + verifying the QES PIN we actually + need both. The CAN may be given + here. If the CAN is not given here, + it will be prompted on the command + line or on the reader (depending on + the reader's capabilities). +

+ st_dv_certificate = filename; + st_certificate = filename; + st_key = filename; +

+ QES is only possible with a Comfort + Reader (CAT-K), which holds a + cryptographic key to authenticate + itself as signature terminal (ST). + We usually will use the reader's + capability to sign the data. + However, during developement you + may specify soft certificates and + keys for a ST. +

+ An example PKI can be found in the + example data for the + German + ID card emulator +

Special Configuration Options for DNIe

+ user_consent_enabled = bool; +

+ Configure the warning message when + performing a signature operation + with the DNIe. Only used if + compiled with + --enable-dnie-ui +

+ user_consent_app = filename; +

+ Specify the pinentry application to + use if warning is configured to be + displayed using pinentry (Default: + /usr/bin/pinentry). + Only used if compiled with + --enable-dnie-ui +

card_atr Configuration Block

+

+ Configuration options specified by the card's ATR: +

+ atrmask = hexstring; +

+ The mask is logically AND'd with an + card ATR prior to comparison with + the ATR reference value above. + Using this mask allows identifying + and configuring multiple ATRs as + the same card model. +

+ driver = name; +

+ When enabled, overrides all + possible settings from the card + drivers built-in card configuration + list. +

+ name = name; +

+ Set card name for card drivers that + allows it. +

+ type = num; +

+ Allows setting the exact type of + the card internally used by the + card driver. Allowed values can be + found in the source code of + cards.h. +

+ flags = value... ; +

+ Card flags as an hex value. + Multiple values are OR'd together. + Depending on card driver, this + allows fine-tuning the capabilities + in the card driver for your card. +

+ Optionally, some known parameters + can be specified as strings: +

  • + rng: + On-board random number + source +

  • + keep_alive: + Request the card driver + to send a "keep alive" + command before each + transaction to make + sure that the required + applet is still + selected. +

+

+ pkcs15emu = name; +

+ When using PKCS#15 emulation, force + the emulation driver for specific + cards. Required for external + drivers, but can be used with + built-in drivers, too. +

+ force_protocol = value; +

+ Force protocol selection for + specific cards. Known parameters: +

  • + t0 +

  • + t1 +

  • + raw +

+

+ md_read_only = bool; +

+ Mark card as read/only card in + Minidriver/BaseCSP interface + (Default: false). +

+ md_supports_X509_enrollment = bool; +

+ Indicate X509 enrollment support at + Minidriver/BaseCSP interface + (Default: false). +

+ md_guid_as_id = bool; +

+ Use the GUID generated for the key + as id in the PKCS#15 structure + (Default: false, i.e. auto generated) +

+ md_guid_as_label = bool; +

+ Use the GUID generated for the key + as label in the PKCS#15 structure + (Default: false, + i.e. no label set). +

+ md_supports_container_key_gen = bool; +

+ Card allows generating key pairs on the card (Default: false). +

+ md_supports_container_key_import = bool; +

+ Card allows importing private keys + (Default: false). +

+ md_pinpad_dlg_title = value; +

+ Window title of the PIN pad dialog + (Default: "Windows + Security"). +

+ md_pinpad_dlg_icon = filename; +

+ Filename of the icon for the PIN + pad dialog; use + "" for no icon + (Default: Built-in smart card icon). +

+ md_pinpad_dlg_main = value; +

+ Main instruction of the PIN pad + dialog (Default: "OpenSC + Smart Card Provider"). +

+ md_pinpad_dlg_content_user = value; +

+ Content of the PIN pad dialog for + role "user" (Default: + "Please verify your + fingerprint or PIN on the + card."). +

+ md_pinpad_dlg_content_user_sign = value; +

+ Content of the PIN pad dialog for + role "user+signature" (Default: + "Please verify your + fingerprint or PIN for the + digital signature PIN on the + card."). +

+ md_pinpad_dlg_content_user_sign = name; +

+ Content of the PIN pad dialog for + role "user+signature" (Default: + "Please verify your + fingerprint or PIN for the + digital signature PIN on the + card."). +

+ md_pinpad_dlg_content_admin = value; +

+ Content of the PIN pad dialog for + role "admin" (Default: + "Please enter your PIN to + unblock the user PIN on the + PINPAD.") +

+ md_pinpad_dlg_content_cancel = value; +

+ Content of the PIN pad dialog after + pressing "Cancel", when the reader + doesn't respond to SCardCancel +

+ md_pinpad_dlg_expanded = value; +

+ Expanded information of the PIN pad + dialog (Default: "This + window will be closed + automatically after the PIN has + been submitted on the PINPAD + (timeout typically after 30 + seconds).") +

+ md_pinpad_dlg_expanded_cancel = value; +

+ Expanded information of the PIN pad + dialog after pressing "Cancel", + when the reader doesn't respond to + SCardCancel (Default: + "Some readers only support + canceling the operation on the + PIN pad. Press Cancel or remove + the card."). +

+ md_pinpad_dlg_enable_cancel = bool; +

+ Allow the user to cancel the PIN + pad dialog (Default: + false) +

+ md_pinpad_dlg_timeout = num; +

+ Time in seconds for the progress + bar of the PIN pad dialog to tick. + 0 removes the + progress bar (Default: + 30). +

+ notify_card_inserted = value; + notify_card_inserted_text = value; +

+ Notification title and text when + card was inserted (Default: + "Smart card + detected", ATR of + the card). +

+ notify_card_removed = value; + notify_card_removed_text = value; +

+ Notification title and text when + card was removed (Default: + "Smart card + removed", name of + smart card reader). +

+ notify_pin_good = value; + notify_pin_good_text = value; +

+ Notification title and text when + PIN was verified (Default: + "PIN verified", + "Smart card is + unlocked"). +

+ notify_pin_bad = value; + notify_pin_bad_text = value; +

+ Notification title and text when + PIN was wrong (Default: + "PIN not + verified", + "Smart card is + locked"). +

+

framework pkcs15 Configuration Block

+ use_file_caching = bool; +

+ Whether to cache the card's files (e.g. + certificates) on disk in + file_cache_dir (Default: + false). +

+ If caching is done by a system process, the + cached files may be placed inaccessible from + the user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. +

+ file_cache_dir = filename; +

+ Where to cache the card's files. The default values are: +

  • + HOME/.eid/cache/ (Unix) +

  • + USERPROFILE\.eid-cache\ (Windows) +

+

+ If caching is done by a system process, the + cached files may be placed inaccessible from + a user account. Use a globally readable and + writable location if you wish to share the + cached information. Note that the cached files + may contain personal data such as name and mail + address. +

+ use_pin_caching = bool; +

+ Use PIN caching (Default: true)? +

+ pin_cache_counter = num; +

+ How many times to use a PIN from cache before + re-authenticating it (Default: + 10)? +

+ pin_cache_ignore_user_consent = bool; +

+ Older PKCS#11 applications not supporting + CKA_ALWAYS_AUTHENTICATE may + need to set this to get signatures to work with + some cards (Default: false). +

+ enable_pkcs15_emulation = bool; +

+ Enable pkcs15 emulation (Default: + true). +

+ try_emulation_first = bool; +

+ Prefer pkcs15 emulation code before the normal + pkcs15 processing (Default: + no). Some cards work in + emu-only mode, and do not depend on this + option. +

+ enable_builtin_emulation = bool; +

+ Enable builtin emulators (Default: + true). +

+ builtin_emulators = emulators; +

+ List of the builtin pkcs15 emulators to test + (Default: esteid, openpgp, tcos, + starcert, itacns, infocamere, postecert, + actalis, atrust-acos, gemsafeGPK, + gemsafeV1, tccardos, PIV-II) +

+ pkcs11_enable_InitToken = bool; +

+ Enable initialization and card recognition in + PKCS#11 layer (Default: + false). +

+ emulate name { + block_contents + } + +

+ Configuration options for a PKCS#15 emulator + where name is a + short name for an external card driver. +

+ module = filename; +

+ For pkcs15 emulators loaded from an + external shared library/DLL, you need to + specify the path name of the module and + customize the card_atr example above + correctly. +

+ function = name; +

+ Get the init function name of the + emulator (Default: + sc_pkcs15_init_func_ex) +

+ application hexstring { + block_contents + } + +

+ Configuration of the on-card-application where + hexstring is the + application identifier (AID). +

+ type = name; +

+ Type of application where + name is one + of: +

  • + generic +

  • + protected +

+

+ Used to distinguish the common access + application and application for which + authentication to perform some + operation cannot be obtained with the + common procedures (ex. object creation + protected by secure messaging). Used + by PKCS#11 module configured to expose + restricted number of slots. (for ex. + configured to expose only User PIN + slot, User and Sign PINs slots, ...) +

+ model = name; +
+ disable = bool; +

+ Do not expose application in PKCS#15 + framework (Default: + false) +

framework tokend Configuration Block

+ score = num; +

+ Score for OpenSC.tokend + (Default: 300). The tokend with + the highest score shall be used. +

+ ignore_private_certificate = bool; +

+ Tokend ignore to read PIN protected certificate + that is set + SC_PKCS15_CO_FLAG_PRIVATE flag + (Default: true). +

pkcs11 Configuration Block

+ max_virtual_slots = num; +

+ Maximum Number of virtual slots (Default: + 16). If there are more slots + than defined here, the remaining slots will be + hidden from PKCS#11. +

+ slots_per_card = num; +

+ Maximum number of slots per smart card (Default: + 4). If the card has fewer keys + than defined here, the remaining number of slots + will be empty. +

+ lock_login = bool; +

+ By default, the OpenSC PKCS#11 module will not lock + your card once you authenticate to the card via + C_Login (Default: + false). + + Thus the other users or other applications is not + prevented from connecting to the card and perform + crypto operations (which may be possible because + you have already authenticated with the card). This + setting is not very secure. +

+ Also, if your card is not locked, you can enconter + problems due to limitation of the OpenSC framework, + that still is not thoroughly tested in the multi + threads environment. +

+ Your settings will be more secure if you choose to + lock your card. Nevertheless this behavior is a + known violation of PKCS#11 specification. Now once + one application has started using your card with + C_Login, no other application + can use it, until the first is done and calls + C_Logout or + C_Finalize. In the case of many + PKCS#11 application this does not happen until you + exit the application. +

+ Thus it is impossible to use several smart card + aware applications at the same time, e.g. you + cannot run both Firefox + and Thunderbird at the + same time, if both are configured to use your smart + card. +

+ atomic = bool; +

+ By default, interacting with the OpenSC PKCS#11 + module may change the state of the token, e.g. + whether a user is logged in or not (Default: + false). +

+ Thus other users or other applications may change + or use the state of the token unknowingly. Other + applications may create signatures abusing an + existing login or they may logout unnoticed. +

+ With this setting enabled the login state of the + token is tracked and cached (including the PIN). + Every transaction is preceded by restoring the + login state. After every transaction a logout is + performed. This setting by default also enables + lock_login to disable access for + other applications during the atomic transactions. +

+ Please note that any PIN-pad should be disabled + (see enable_pinpad), because the + user would have to input his PIN for every + transaction. +

+ init_sloppy = bool; +

+ With this setting disabled, the OpenSC PKCS#11 + module will initialize the slots available when the + application calls C_GetSlotList. + With this setting enabled, the slots will also get + initialized when C_GetSlotInfo + is called (Default: true). +

+ This setting is a workaround for + Java which does not call + C_GetSlotList when configured + with a static slot instead of + slotListIndex. +

+ user_pin_unblock_style = mode; +

+ User PIN unblock style mode + is one of: +

  • + none (Default): PIN + unblock is not possible with PKCS#11 API +

  • + set_pin_in_unlogged_session: + C_SetPIN in unlogged + session: PUK is passed as the + OldPin argument of the + C_SetPIN call. +

  • + set_pin_in_specific_context: + C_SetPIN in the + CKU_SPECIFIC_CONTEXT + logged session: PUK is passed as the + OldPin argument of the + C_SetPIN call. +

  • + init_pin_in_so_session: + C_InitPIN in + CKU_SO logged session: + User PIN 'UNBLOCK' is protected by SOPIN. + (PUK == SOPIN). +

+

+ create_puk_slot = bool; +

+ Create slot for unblocking PIN with PUK (Default: + false). This way PKCS#11 API can + be used to login with PUK and change a PIN. May + cause problems with some applications like + Firefox and + Thunderbird. +

+ create_slots_for_pins = mode... ; +

+ Symbolic names of PINs for which slots are created + where mode is a list of: +

  • + all (Default): All + non-SO-PIN, non-unblocking PINs +

  • + user: The first + global or first local PIN +

  • + sign: The second PIN + (first local, second global or second + local) +

+

+ Card can contain more then one PINs or more then + one on-card application with its own PINs. + Normally, to access all of them with the PKCS#11 + API a slot has to be created for all of them. Many + slots could be ennoying for some of widely used + application, like FireFox. This configuration + parameter allows to select the PIN(s) for which + PKCS#11 slot will be created. +

+ Only PINs initialised, non-SO-PIN, non-unblocking + are associated with symbolic name. +

+ For the module to simulate the opensc-onepin module + behavior the following option + create_slots_for_pins = "user"; +

Environment

+ OPENSC_CONF +

+ Filename for a user defined configuration file +

+ If this environment variable is not found on + Windows, the registry key + HKLM\Software\OpenSC + Project\OpenSC\ConfigFile is + checked. +

+ CARDMOD_LOW_LEVEL_DEBUG +

+ Write minidriver debug information to + C:\tmp\md.log, if set to + 1. +

+ If this environment variable is not found on + Windows, the registry key + HKLM\Software\OpenSC + Project\OpenSC\MiniDriverDebug is + checked. +

+ PIV_EXT_AUTH_KEY, + PIV_9A_KEY, + PIV_9C_KEY, + PIV_9D_KEY, + PIV_9E_KEY +

+ PIV configuration during initialization with + piv-tool. +

Files

+ /home/fm/.local/etc/opensc.conf +

+ System-wide configuration file +

+ /home/fm/.local/share/doc/opensc/opensc.conf +

+ Extended example configuration file +

Security


Name

pkcs15-profile — format of profile for pkcs15-init

Description

+ The pkcs15-init utility for PKCS #15 smart card + personalization is controlled via profiles. When starting, it will read two + such profiles at the moment, a generic application profile, and a card + specific profile. The generic profile must be specified on the command line, + while the card-specific file is selected based on the type of card detected. +

+ The generic application profile defines general information about the card + layout, such as the path of the application DF, various PKCS #15 files within + that directory, and the access conditions on these files. It also defines + general information about PIN, key and certificate objects. Currently, there + is only one such generic profile, pkcs15.profile. +

+ The card specific profile contains additional information required during + card initialization, such as location of PIN files, key references etc. + Profiles currently reside in @pkgdatadir@ +

Syntax

+ This section should contain information about the profile syntax. Will add + this soonishly. +

See also

+ pkcs15-init(1), + pkcs15-crypt(1) +

diff -Nru opensc-0.17.0/doc/tools/gids-tool.1.xml opensc-0.19.0/doc/tools/gids-tool.1.xml --- opensc-0.17.0/doc/tools/gids-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/gids-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -75,15 +75,21 @@ argument - Define the new adminastrator key. + Define the new administrator key.
argument, argument - Uses reader number - argument. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -114,4 +120,10 @@ + + Authors + gids-tool was written by + Vincent Le Toux vincent.letoux@mysmartlogon.com. + + diff -Nru opensc-0.17.0/doc/tools/iasecc-tool.1.xml opensc-0.19.0/doc/tools/iasecc-tool.1.xml --- opensc-0.17.0/doc/tools/iasecc-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/iasecc-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -34,10 +34,16 @@ - number, + num, - Specify the reader number number to use. - The default is reader 0. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -78,4 +84,10 @@ + + + Authors + iasecc-tool was written by + Viktor Tarasov viktor.tarasov@gmail.com. + diff -Nru opensc-0.17.0/doc/tools/Makefile.am opensc-0.19.0/doc/tools/Makefile.am --- opensc-0.17.0/doc/tools/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -2,6 +2,9 @@ EXTRA_DIST = completion-template +TESTS = test-manpage.sh +dist_noinst_SCRIPTS = test-manpage.sh + dist_noinst_DATA = $(wildcard $(srcdir)/*.xml) if ENABLE_DOC html_DATA = tools.html @@ -9,23 +12,17 @@ if ENABLE_MAN man1_MANS = $(patsubst $(srcdir)/%.xml, %, $(wildcard $(srcdir)/*.1.xml)) -man5_MANS = $(patsubst $(srcdir)/%.xml, %, $(wildcard $(srcdir)/*.5.xml)) endif completion_DATA = $(patsubst $(srcdir)/%.1.xml, %, $(wildcard $(srcdir)/*.1.xml)) -completiondir = $(sysconfdir)/bash_completion.d -tools.html: $(srcdir)/tools.xml $(wildcard $(srcdir)/*.1.xml) $(wildcard $(srcdir)/*.5.xml) +tools.html: $(srcdir)/tools.xml $(wildcard $(srcdir)/*.1.xml) $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/html" --xinclude -o $@ html.xsl $< %.1: $(srcdir)/%.1.xml sed -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' < $< \ | $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/manpages" --xinclude -o $@ man.xsl $< -%.5: $(srcdir)/%.5.xml - sed -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' < $< \ - | $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/manpages" --xinclude -o $@ man.xsl $< - %: $(srcdir)/%.1.xml @echo $< $@ @cat $(srcdir)/completion-template \ @@ -34,13 +31,16 @@ | sort -u | grep -- '^\-' | tr '\n' ' ')," \ | sed "s,OPTSWITHARGS,\ $(shell sed -n 's,.*.*.*,\1,pg' $< \ - | sort -u | grep -- '^\-' | tr '\n' '|' | sed 's,|$$,,')," \ + | sort -u | grep -- '^\-' | tr '\n' '|' | sed 's,|$$,,' | grep ^ || echo "!*")," \ | sed "s,FILEOPTS,\ $(shell sed -n 's,.*.*.*filename.*,\1,pg' $< \ - | sort -u | grep -- '^\-' | tr '\n' '|')," \ + | sort -u | grep -- '^\-' | tr '\n' '|' | sed 's,|$$,,' | grep ^ || echo "!*")," \ + | sed "s,MODULEOPTS,\ + $(shell sed -n 's,.*.*.*mod.*,\1,pg' $< \ + | sort -u | grep -- '^\-' | tr '\n' '|' | sed 's,|$$,,' | grep ^ || echo "!*")," \ | sed "s,FUNCTION_NAME,$(shell echo $@ | sed s,-,_,g)," \ | sed "s,PROGRAM_NAME,$@," \ > $@ clean-local: - -rm -rf $(html_DATA) $(man1_MANS) $(man5_MANS) $(completion_DATA) + -rm -rf $(html_DATA) $(man1_MANS) $(completion_DATA) diff -Nru opensc-0.17.0/doc/tools/netkey-tool.1.xml opensc-0.19.0/doc/tools/netkey-tool.1.xml --- opensc-0.17.0/doc/tools/netkey-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/netkey-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -71,10 +71,17 @@ - number, - number + num, + num - Use smart card in specified reader. Default is reader 0. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -91,7 +98,7 @@ PIN format With the , , or the one of the cards pins may be specified. You may use plain ascii-strings (i.e. 123456) or a hex-string - (i.e. 31:32:33:34:35:36). A hex-string must consists of exacly n 2-digit hexnumbers separated by n-1 colons. + (i.e. 31:32:33:34:35:36). A hex-string must consist of exactly n 2-digit hexnumbers separated by n-1 colons. Otherwise it will be interpreted as an ascii string. For example :12:34: and 1:2:3:4 are both pins of length 7, while 12:34 and 01:02:03:04 are pins of length 2 and 4. @@ -112,7 +119,7 @@ current value of your global PIN. For most of the commands that netkey-tool can execute, you have - to specify one pin. One notable exeption is the nullpin command, but + to specify one pin. One notable exception is the nullpin command, but this command can only be executed once in the lifetime of a NetKey E4 card. @@ -140,8 +147,14 @@ - change { pin | puk | - pin0 | pin1 } new-pin + change + + pin + puk + pin0 + pin1 + + new-pin This changes the value of the specified pin to the given new value. You must specify either the current value of the pin or another pin to be able to do @@ -154,13 +167,18 @@ This command can be executed only if the global PIN of your card is in nullpin-state. There's no way to return back to nullpin-state once you have changed - your global PIN. You don't need a pin to execute the nullpin-command. After a succesfull + your global PIN. You don't need a pin to execute the nullpin-command. After a successful nullpin-command netkey-tool will display your cards initial PUK-value. - unblock { pin | pin0 | pin1 } + unblock + + pin + pin0 + pin1 + This unblocks the specified pin. You must specify another pin to be able to do this and if you don't specify a correct one, diff -Nru opensc-0.17.0/doc/tools/npa-tool.1.xml opensc-0.19.0/doc/tools/npa-tool.1.xml --- opensc-0.17.0/doc/tools/npa-tool.1.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/npa-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,440 @@ + + + + npa-tool + 1 + OpenSC + OpenSC Tools + opensc + + + + npa-tool + displays information on the German eID card (neuer Personalausweis, nPA). + + + + + + npa-tool + OPTIONS + + + + + Description + + The npa-tool utility is used to display information + stored on the German eID card (neuer Personalausweis, nPA), + and to perform some write and verification operations. + + + + + Options + + + + + , + + Print help and exit. + + + + , + + Print version and exit. + + + + arg, + arg + + + Specify the reader to use. + Use -1 as arg + to automatically detect the reader to use. + By default, the first reader with a present card is used. + + + + + , + + + + Causes npa-tool to be more verbose. + Specify this flag several times to be more verbose. + + + + + + + Password Authenticated Connection Establishment (<abbrev>PACE</abbrev>) + + + + STRING, + STRING + + + Run PACE with (transport) eID-PIN. + + + + + STRING, + STRING + + + Run PACE with PUK. + + + + + STRING, + STRING + + + Run PACE with Card Access Number (CAN). + + + + + STRING, + STRING + + + Run PACE with Machine Readable Zone (MRZ). + Enter the MRZ without newlines. + + + + + + Specify whether to use environment variables PIN, + PUK, CAN, MRZ, + and NEWPIN. + You may want to clean your environment before enabling this. + (default=off) + + + + + + + PIN management + + + + STRING, + STRING + + + Install a new PIN. + + + + + , + + + + Resume eID-PIN (uses CAN to activate last retry). + (default=off) + + + + + , + + + + Unblock PIN (uses PUK to activate three more retries). + (default=off) + + + + + + + Terminal Authentication (<abbrev>TA</abbrev>) and Chip Authentication (<abbrev>CA</abbrev>) + + + + FILENAME, + FILENAME + + + Specify Card Verifiable (CV) certificate + to create a certificate chain. + The option can be given multiple times, in which case the + order is important. + + + + HEX_STRING + + Certificate description to show for Terminal Authentication. + + + + HEX_STRING + + Specify the Card Holder Authorization Template + (CHAT) to use. + If not given, it defaults to the terminal's CHAT. + Use 7F4C0E060904007F000703010203530103 + to trigger EAC on the CAT-C (Komfortleser). + + + + + HEX_STRING, + HEX_STRING + + + Specify the terminal's auxiliary data. + If not given, the default is determined by verification + of validity, age and community ID. + + + + + FILENAME, + FILENAME + + + Specify the terminal's private key. + + + + DIRECTORY + + Specify where to look for the certificate of the + Country Verifying Certification Authority + (CVCA). + If not given, it defaults to + /home/fm/.local/etc/eac/cvc. + + + + + DIRECTORY + + Specify where to look for the X.509 certificate. + If not given, it defaults to + /home/fm/.local/etc/eac/x509. + + + + + + Disable checking the validity period of CV certificates. + (default=off) + + + + + + Disable passive authentication. (default=off) + + + + + + + Read and write data groups + + + + Read data group 1: Document Type. + + + + Read data group 2: Issuing State. + + + + Read data group 3: Date of Expiry. + + + + Read data group 4: Given Name(s). + + + + Read data group 5: Family Name. + + + + Read data group 6: Religious/Artistic Name. + + + + Read data group 7: Academic Title. + + + + Read data group 8: Date of Birth. + + + + Read data group 9: Place of Birth. + + + + Read data group 10: Nationality. + + + + Read data group 11: Sex. + + + + Read data group 12: Optional Data. + + + + Read data group 13: Birth Name. + + + + Read data group 14. + + + + Read data group 15. + + + + Read data group 16. + + + + Read data group 17: Normal Place of Residence. + + + + Read data group 18: Community ID. + + + + Read data group 19: Residence Permit I. + + + + Read data group 20: Residence Permit II. + + + + Read data group 21: Optional Data. + + + + HEX_STRING + Write data group 17: Normal Place of Residence. + + + + HEX_STRING + Write data group 18: Community ID. + + + + HEX_STRING + Write data group 19: Residence Permit I. + + + + HEX_STRING + Write data group 20: Residence Permit II. + + + HEX_STRING + Write data group 21: Optional Data. + + + + + + Verification of validity, age and community ID + + + YYYYMMDD + + Verify chip's validity with a reference date. + + + + YYYYMMDD + + Verify age with a reference date. + + + + HEX_STRING + + Verify community ID with a reference ID. + + + + + + + Special options, not always useful + + + + , + + + + Brute force PIN, CAN or PUK. + Use together with options , + , or . + (default=off) + + + + + FILENAME, + FILENAME + + + Specify the file with APDUs of HEX_STRINGs to send + through the secure channel. + (default=`stdin') + + + + + + Force compliance to BSI TR-03110 version 2.01. (default=off) + + + + + + Disable all checking of fly-by-data. (default=off) + + + + + + + + Authors + npa-tool was written by + Frank Morgner frankmorgner@gmail.com. + + + + diff -Nru opensc-0.17.0/doc/tools/openpgp-tool.1.xml opensc-0.19.0/doc/tools/openpgp-tool.1.xml --- opensc-0.17.0/doc/tools/openpgp-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/openpgp-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -40,109 +40,148 @@ - prog, - prog + arg - Execute the given program with data in environment variables. + Delete key indicated by arg. + arg can be 1, + 2, 3, or + all. - , - + arg, + arg - Print help message on screen. + Dump private data object (DO) + indicated by arg. + arg can be in the form + x, + 10x, or + 010x + to access DO 010x, + where x is 1, + 2, 3, or + 4. - + , + - Print values in raw format, as they are stored on the card. + Erase (i.e. reset) the card. - + prog, + prog - Print values in pretty format. + Execute the given program with data in environment variables. - , - + arg, + arg - Show card holder information. + Generate key with the ID given as arg. + arg can be one of 1, + 2, or 3. - num, - num + , + - Use the given reader. The default is the first reader with a card. + Print help message on screen. - pintype + bitlength, + bitlength - - - Verify PIN (CHV1, CHV2 or CHV3). - - + + Specify the length of the key to be generated. + If not given, it defaults to 2048 bit. + string - - + The PIN text to verify. If set to env:VARIABLE, the value of the environment variable VARIABLE is used. - - + - ID, - ID + - - - Generate key. Specify key ID (1, 2 or 3) to generate. - - + + Print values in pretty format. + - bitlength, - bitlength + + + + Print values in raw format, as they are stored on the card. + + + + + + num, + num - - - Length (default 2048 bit) of the key to be generated. - - + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + + + + + , + + + + Show card holder information. + + + + + + pintype + + + Verify PIN (CHV1, CHV2 or CHV3). + @@ -151,7 +190,7 @@ - Print the version of the utility and exit. + Print the version of the utility and exit. @@ -161,7 +200,7 @@ - Verbose operation. Use several times to enable debug output. + Verbose operation. Use several times to enable debug output. @@ -171,10 +210,9 @@ - Wait for a card to be inserted. + Wait for a card to be inserted. - diff -Nru opensc-0.17.0/doc/tools/opensc-asn1.1.xml opensc-0.19.0/doc/tools/opensc-asn1.1.xml --- opensc-0.17.0/doc/tools/opensc-asn1.1.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/opensc-asn1.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,64 @@ + + + + opensc-asn1 + 1 + OpenSC + OpenSC Tools + opensc + + + + opensc-asn1 + parse ASN.1 data + + + + + + opensc-asn1 + OPTIONS + FILES + + + + + Description + + The opensc-asn1 utility is used to parse ASN.1 data. + + + + + Options + + + + + , + + Print help and exit. + + + + , + + Print version and exit. + + + + + + + Authors + opensc-asn1 was written by + Frank Morgner frankmorgner@gmail.com. + + + + diff -Nru opensc-0.17.0/doc/tools/opensc-explorer.1.xml opensc-0.19.0/doc/tools/opensc-explorer.1.xml --- opensc-0.17.0/doc/tools/opensc-explorer.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/opensc-explorer.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -68,10 +68,14 @@ num, num - - Use the given reader number. The default - is 0, the first reader in the system. - + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -93,408 +97,470 @@ - - Commands - - The following commands are supported at opensc-explorer's - interactive prompt or in script files passed via the command line parameter - SCRIPT. - - - - apdu hex-data - - - Send a custom APDU command hex-data. - - - - - - asn1 file-id - - Parse and print the ASN.1 encoded content of the file specified by - file-id. - - - - - cat [file-id | sfi:short-id] - - Print the contents of the currently selected EF or the contents - of a file specified by file-id or the short file id - short-id. - - - - - - cd {.. | file-id | aid:DF-name} - - - Change to another DF specified by the argument passed. - If the argument given is .., then move up one level in the - file system hierarchy. - If it is file-id, which must be a DF directly - beneath the current DF, then change to that DF. - If it is an application identifier given as - aid:DF-name, - then jump to the MF of the application denoted by - DF-name. - - - - - - change CHVpin-ref [[old-pin] new-pin] - - - Change a PIN, where pin-ref is the PIN reference. - - Examples: - - - change CHV2 00:00:00:00:00:00 "foobar" - - Change PIN CHV2 - to the new value foobar, - giving the old value 00:00:00:00:00:00. - - - - change CHV2 "foobar" - - Set PIN CHV2 - to the new value foobar. - - - - change CHV2 - - Change PIN CHV2 using the card reader's pinpad. - - - - - - - - - - create file-id size - - Create a new EF. file-id specifies the - id number and size is the size of the new file. - - - - - - debug [level] - - - Set OpenSC debug level to level. - If level is omitted the current debug level will be shown. - - - - - - delete file-id - - Remove the EF or DF specified by file-id - - - - - do_get hex-tag [output] - - - Copy the internal card's 'tagged' data into the local file. - The local file is specified by output while the tag of - the card's data is specified by hex-tag. - - - If output is omitted, the name of the output file will be - derived from hex-tag. - - - - - - - do_put hex-tag input - - - Update internal card's 'tagged' data. - hex-tag is the tag of the card's data. - input is the filename of the source file or the literal data presented as - a sequence of hexadecimal values or " enclosed string. - - - - - - - echo string ... - - - Print the strings given. - - - - - - erase - - Erase the card, if the card supports it. - - - - - get file-id [output] - - - Copy an EF to a local file. The local file is specified - by output while the card file is specified by file-id. - - - If output is omitted, the name of the output file will be - derived from the full card path to file-id. - - - - - - - info [file-id] - - Display attributes of a file specified by file-id. - If file-id is not supplied, - the attributes of the current file are printed. - - - - - ls [pattern ...] - - List files in the current DF. - If no pattern is given, then all files are listed. - If one ore more patterns are given, only files matching - at least one pattern are listed. - - - - - find [start-id [end-id]] - - Find all files in the current DF. - Files are found by selecting all file identifiers in the range from start-fid to end-fid (by default from 0000 to FFFF). - - - - - find_tags [start-tag [end-tag]] - - Find all tags of data objects in the current context. - Tags are found by using GET DATA in the range from start-tag to end-tag (by default from 0000 to FFFF). - - - - - mkdir file-id size - - Create a DF. file-id specifies the id number - and size is the size of the new file. - - - - - put file-id input - - Copy a local file to the card. The local file is specified - by input while the card file is specified by file-id. - - - - - - quit - - Exit the program. - - - - - random count - - - Generate random sequence of count bytes. - - - - - - rm file-id - - Remove the EF or DF specified by file-id - - - - - unblock CHVpin-ref [puk [new pin]] - - - - Unblock the PIN denoted by pin-ref - using the PUK puk, and set potentially - change its value to new pin. - - - PUK and PIN values can be a sequence of hexadecimal values, - "-enclosed strings, empty (""), - or absent. - If they are absent, the values are read from the card reader's pin pad. - - - Examples: - - - unblock CHV2 00:00:00:00:00:00 "foobar" - - Unblock PIN CHV2 using PUK - 00:00:00:00:00:00 - and set it to the new value foobar. - - - - unblock CHV2 00:00:00:00:00:00 "" - - Unblock PIN CHV2 using PUK - 00:00:00:00:00:00 keeping the old value. - - - - unblock CHV2 "" "foobar" - - Set new value of PIN CHV2 - to foobar. - - - - unblock CHV2 00:00:00:00:00:00 - - Unblock PIN CHV2 using PUK - 00:00:00:00:00:00. - The new PIN value is prompted by pinpad. - - - - unblock CHV2 "" - - Set PIN CHV2. - The new PIN value is prompted by pinpad. - - - - unblock CHV2 - - Unblock PIN CHV2. - The unblock code and new PIN value are prompted by pinpad. - - - - - - - - - - update_binary file-id offs data - - - Binary update of the file specified by - file-id with the literal data - data starting from offset specified - by offs. - data can be supplied as a sequencer - of the hex values or as a " enclosed string. - - - - - - update_record file-id rec-nr rec-offs data - - - Update record specified by rec-nr of the file - specified by file-id with the literal data - data starting from offset specified by - rec-offs. - data can be supplied as a sequence of the hex values or - as a " enclosed string. - - - - - - verify key-type key-id [key] - - Present a PIN or key to the card, where - key-type can be one of CHV, - KEY, AUT or PRO. - key-id is a number representing the key or PIN reference. - key is the key or PIN to be verified, formatted as a - colon-separated list of hex values or a " enclosed string. - - - If key is omitted, the exact action depends on the - card reader's features: if the card readers supports PIN input via a pin pad, - then the PIN will be verified using the card reader's pin pad. - If the card reader does not support PIN input, then the PIN will be asked - interactively. - - - Examples: - - - verify CHV0 31:32:33:34:00:00:00:00 - - Verify CHV2 using the hex value - 31:32:33:34:00:00:00:00 - - - - verify CHV1 "secret" - - Verify CHV1 - using the string value secret. - - - - verify KEY2 - - Verify KEY2, - get the value from the card reader's pin pad. - - - - - - - - - - sm [open]|[close] - - - Calls the card's open or close Secure Messaging handler. - - - - - - + + Commands + + The following commands are supported at opensc-explorer's + interactive prompt or in script files passed via the command line parameter + SCRIPT. + + + + apdu + hex-data + + + Send a custom APDU command hex-data. + + + + + + asn1 + file-id + + Parse and print the ASN.1 encoded content of the file specified by + file-id. + + + + + cat + + file-id + sfi:short-id + + + Print the contents of the currently selected EF or the contents + of a file specified by file-id or the short file id + short-id. + + + + + + cd + + .. + file-id + aid:DF-name + + + + Change to another DF specified by the argument passed. + If the argument given is .., + then move up one level in the file system hierarchy. + If it is file-id, + which must be a DF directly + beneath the current DF, then change to that DF. + If it is an application identifier given as + aid:DF-name, + then jump to the MF of the application denoted by + DF-name. + + + + + + change + CHVpin-ref + + old-pin + new-pin + + + + Change a PIN, where pin-ref is the PIN reference. + + Examples: + + + change CHV2 00:00:00:00:00:00 "foobar" + + Change PIN CHV2 + to the new value foobar, + giving the old value 00:00:00:00:00:00. + + + + change CHV2 "foobar" + + Set PIN CHV2 + to the new value foobar. + + + + change CHV2 + + Change PIN CHV2 using the card reader's pinpad. + + + + + + + + + + create + file-id + size + + Create a new EF. file-id specifies the + id number and size is the size of the new file. + + + + + + debug + level + + + Set OpenSC debug level to level. + If level is omitted the current debug level will be shown. + + + + + + delete + file-id + + Remove the EF or DF specified by file-id + + + + + do_get + hex-tag + output + + + Copy the internal card's 'tagged' data into the local file. + The local file is specified by output while the tag of + the card's data is specified by hex-tag. + + + If output is omitted, the name of the output file will be + derived from hex-tag. + + + + + + + do_put + hex-tag + input + + + Update internal card's 'tagged' data. + hex-tag is the tag of the card's data. + input is the filename of the source file or the literal data presented as + a sequence of hexadecimal values or " enclosed string. + + + + + + + echo + string + + + Print the strings given. + + + + + + erase + + Erase the card, if the card supports it. + + + + + get + file-id + output + + + Copy an EF to a local file. The local file is specified + by output while the card file is specified by file-id. + + + If output is omitted, the name of the output file will be + derived from the full card path to file-id. + + + + + + + info + file-id + + Display attributes of a file specified by file-id. + If file-id is not supplied, + the attributes of the current file are printed. + + + + + ls + pattern + + List files in the current DF. + If no pattern is given, then all files are listed. + If one ore more patterns are given, only files matching + at least one pattern are listed. + + + + + find + + start-id + end-id + + + Find all files in the current DF. + Files are found by selecting all file identifiers in the range from start-fid to end-fid (by default from 0000 to FFFF). + + + + + find_tags + + start-tag + end-tag + + + Find all tags of data objects in the current context. + Tags are found by using GET DATA in the range from start-tag to end-tag (by default from 0000 to FFFF). + + + + + mkdir + file-id + size + + Create a DF. file-id specifies the id number + and size is the size of the new file. + + + + + put + file-id + input + + Copy a local file to the card. The local file is specified + by input while the card file is specified by file-id. + + + + + + quit + + Exit the program. + + + + + random + count + + + Generate random sequence of count bytes. + + + + + + rm + file-id + + Remove the EF or DF specified by file-id + + + + + unblock + CHVpin-ref + + puk + new-pin + + + + + Unblock the PIN denoted by pin-ref + using the PUK puk, and set potentially + change its value to new-pin. + + + PUK and PIN values can be a sequence of hexadecimal values, + "-enclosed strings, empty (""), + or absent. + If they are absent, the values are read from the card reader's pin pad. + + + Examples: + + + unblock CHV2 00:00:00:00:00:00 "foobar" + + Unblock PIN CHV2 using PUK + 00:00:00:00:00:00 + and set it to the new value foobar. + + + + unblock CHV2 00:00:00:00:00:00 "" + + Unblock PIN CHV2 using PUK + 00:00:00:00:00:00 keeping the old value. + + + + unblock CHV2 "" "foobar" + + Set new value of PIN CHV2 + to foobar. + + + + unblock CHV2 00:00:00:00:00:00 + + Unblock PIN CHV2 using PUK + 00:00:00:00:00:00. + The new PIN value is prompted by pinpad. + + + + unblock CHV2 "" + + Set PIN CHV2. + The new PIN value is prompted by pinpad. + + + + unblock CHV2 + + Unblock PIN CHV2. + The unblock code and new PIN value are prompted by pinpad. + + + + + + + + + + update_binary + file-id + offs + data + + + Binary update of the file specified by + file-id with the literal data + data starting from offset specified + by offs. + data can be supplied as a sequencer + of the hex values or as a " enclosed string. + + + + + + update_record + file-id + rec-nr + rec-offs + data + + + Update record specified by rec-nr of the file + specified by file-id with the literal data + data starting from offset specified by + rec-offs. + data can be supplied as a sequence of the hex values or + as a " enclosed string. + + + + + + verify + key-typekey-id + key + + Present a PIN or key to the card, where + key-type can be one of CHV, + KEY, AUT or PRO. + key-id is a number representing the key or PIN reference. + key is the key or PIN to be verified, formatted as a + colon-separated list of hex values or a " enclosed string. + + + If key is omitted, the exact action depends on the + card reader's features: if the card readers supports PIN input via a pin pad, + then the PIN will be verified using the card reader's pin pad. + If the card reader does not support PIN input, then the PIN will be asked + interactively. + + + Examples: + + + verify CHV0 31:32:33:34:00:00:00:00 + + Verify CHV2 using the hex value + 31:32:33:34:00:00:00:00 + + + + verify CHV1 "secret" + + Verify CHV1 + using the string value secret. + + + + verify KEY2 + + Verify KEY2, + get the value from the card reader's pin pad. + + + + + + + + + + sm + + open + close + + + + Calls the card's open or close Secure Messaging handler. + + + + + + See also @@ -506,4 +572,10 @@ + + Authors + opensc-explorer was written by + Juha Yrjölä juha.yrjola@iki.fi. + + diff -Nru opensc-0.17.0/doc/tools/opensc-notify.1.xml opensc-0.19.0/doc/tools/opensc-notify.1.xml --- opensc-0.17.0/doc/tools/opensc-notify.1.xml 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/opensc-notify.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,136 @@ + + + + opensc-notify + 1 + OpenSC + OpenSC Tools + opensc + + + + opensc-notify + monitor smart card events and send notifications + + + + + + opensc-notify + OPTIONS + + + + + Description + + The opensc-notify utility is used to + monitor smart card events and send the appropriate notification. + + + + + Options + + + + + , + + Print help and exit. + + + + , + + Print version and exit. + + + + + + Mode: customized + + Send customized notifications. + + + + + STRING, + STRING + + + Specify the title of the notification. + + + + + STRING, + STRING + + + Specify the main text of the notification. + + + + + + + Mode: standard + + Manually send standard notifications. + + + + + , + + + See notify_card_inserted + in opensc.conf (default=off). + + + + + , + + + See notify_card_removed + in opensc.conf (default=off). + + + + + , + + + See notify_pin_good + in opensc.conf (default=off). + + + + + , + + + See notify_pin_bad + in opensc.conf (default=off). + + + + + + + + Authors + opensc-notify was written by + Frank Morgner frankmorgner@gmail.com. + + + + diff -Nru opensc-0.17.0/doc/tools/opensc-tool.1.xml opensc-0.19.0/doc/tools/opensc-tool.1.xml --- opensc-0.17.0/doc/tools/opensc-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/opensc-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -57,6 +57,12 @@ + , + + Lists algorithms supported by card + + + , @@ -92,18 +98,39 @@ + conf, + conf + + Get configuration key, format: section:name:key + + + + conf, + conf + + Get configuration key, format: section:name:key:value + + + num, num - Use the given reader number. - The default is 0, the first reader in the system. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + - [=type], + type, Resets the card in reader. - The default reset type is cold, but warm reset is also possible. + The default reset type is cold, + but warm reset is also possible. @@ -149,4 +176,10 @@ + + Authors + opensc-tool was written by + Juha Yrjölä juha.yrjola@iki.fi. + + diff -Nru opensc-0.17.0/doc/tools/piv-tool.1.xml opensc-0.19.0/doc/tools/piv-tool.1.xml --- opensc-0.17.0/doc/tools/piv-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/piv-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -24,7 +24,7 @@ The piv-tool utility can be used from the command line to perform miscellaneous smart card operations on a HSPD-12 PIV smart card as defined in NIST 800-73-3. - It is intened for use with test cards only. It can be used to load objects, and generate + It is intended for use with test cards only. It can be used to load objects, and generate key pairs, as well as send arbitrary APDU commands to a card after having authenticated to the card using the card key provided by the card vendor. @@ -94,7 +94,7 @@ ref, - ref + ref Load a certificate onto the card. ref is 9A, @@ -154,8 +154,14 @@ num, num - Use the given reader number. The default is - 0, the first reader in the system. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -195,4 +201,10 @@ + + Authors + piv-tool was written by + Douglas E. Engert deengert@gmail.com. + + diff -Nru opensc-0.17.0/doc/tools/pkcs11-tool.1.xml opensc-0.19.0/doc/tools/pkcs11-tool.1.xml --- opensc-0.17.0/doc/tools/pkcs11-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/pkcs11-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -37,9 +37,9 @@ - path + filename - Extract information from path + Extract information from filename (DER-encoded certificate file) and create the corresponding attributes when writing an object to the token. Example: the certificate subject name is used to create the CKA_SUBJECT @@ -73,6 +73,28 @@ + mechanism + + + + Specify hash algorithm used with RSA-PKCS-PSS signature or RSA-OAEP decryption. + Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may + also allow "SHA224". Default is "SHA-1". + + + Note that the input to RSA-PKCS-PSS has to be of the size equal to + the specified hash algorithm. E.g., for SHA256 the signature input must + be exactly 32 bytes long (for mechanisms SHA256-RSA-PKCS-PSS there is no + such restriction). For RSA-OAEP, the plaintext input size mLen must be + at most keyLen - 2 - 2*hashLen. For example, for RSA 3072-bit key and + SHA384, the longest plaintext to encrypt with RSA-OAEP is (with all + sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes. + + + + + + id, id @@ -100,8 +122,8 @@ - path, - path + filename, + filename Specify the path to a file for input. @@ -113,10 +135,16 @@ Generate a new key pair (public and private pair.) + + + + + Generate a new key. + - specification + specification Specify the type and length of the key to create, for example rsa:1024 or EC:prime256v1. @@ -209,7 +237,20 @@ Use the specified mechanism for token operations. See for a list - of mechanisms supported by your token. + of mechanisms supported by your token. The mechanism can also be specified in + hexadecimal, e.g., 0x80001234. + + + + + function + + Use the specified Message Generation + Function (MGF) function + for RSA-PKCS-PSS signatures or RSA-OAEP decryptions. Supported arguments are MGF1-SHA1 + to MGF1-SHA512 if supported by the driver. + The default is based on the hash selection. + @@ -222,18 +263,18 @@ - path, - path + filename, + filename Test a Mozilla-like keypair generation - and certificate request. Specify the path + and certificate request. Specify the filename to the certificate file. - path, - path + filename, + filename Specify the path to a file for output. @@ -273,6 +314,13 @@ + + + Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext). + + + + id, id @@ -311,6 +359,24 @@ + , + + Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations + + + + + bytes + + Specify how many bytes of salt should + be used in RSA-PSS signatures. Accepts two special values: + "-1" means salt length equals to digest length, + "-2" means use maximum permissible length. + Default is digest length (-1). + + + + id Specify the id of the slot to use. @@ -474,11 +540,11 @@ - id, - path + filename, + filename Write a key or certificate object to the token. - path points to the DER-encoded certificate or key file. + filename points to the DER-encoded certificate or key file. @@ -493,4 +559,32 @@ + + + Examples + + To list all certificates on the smart card: + pkcs11-tool --list-objects --type cert + + To read the certificate with ID KEY_ID + in DER format from smart card: + pkcs11-tool --read-object --id KEY_ID --type cert --outfile cert.der + + To convert the certificate in DER format to PEM format, use OpenSSL + tools: + openssl x509 -inform DER -in cert.der -outform PEM > cert.pem + + To sign some data stored in file data + using the private key with ID ID and + using the RSA-PKCS mechanism: + pkcs11-tool --sign --id ID --mechanism RSA-PKCS --input-file data --output-file data.sig + + + + + Authors + pkcs11-tool was written by + Olaf Kirch okir@suse.de. + + diff -Nru opensc-0.17.0/doc/tools/pkcs15-crypt.1.xml opensc-0.19.0/doc/tools/pkcs15-crypt.1.xml --- opensc-0.17.0/doc/tools/pkcs15-crypt.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/pkcs15-crypt.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -132,19 +132,28 @@ N, N - Selects the N-th smart - card reader configured by the system. If unspecified, - pkcs15-crypt will use the first reader - found. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + + + + + + - This option tells pkcs15-crypt - that the input file is the result of an SHA1 hash operation, - rather than an MD5 hash. Again, the data must be in binary + These options tell pkcs15-crypt + that the input file is the result of the specified hash operation. + By default, an MD5 hash is expected. Again, the data must be in binary representation. @@ -174,9 +183,18 @@ When signing with ECDSA key this option indicates to pkcs15-crypt the signature output format. - Possible values are 'rs'(default) -- two concatanated + Possible values are 'rs'(default) -- two concatenated integers (PKCS#11), 'sequence' or 'openssl' -- DER encoded sequence - of two integeres (OpenSSL). + of two integers (OpenSSL). + + + + + , + + + Causes pkcs15-crypt to + wait for a card insertion. @@ -206,4 +224,10 @@ + + Authors + pkcs15-crypt was written by + Juha Yrjölä juha.yrjola@iki.fi. + + diff -Nru opensc-0.17.0/doc/tools/pkcs15-init.1.xml opensc-0.19.0/doc/tools/pkcs15-init.1.xml --- opensc-0.17.0/doc/tools/pkcs15-init.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/pkcs15-init.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -170,11 +170,11 @@ Note that usage of option in the pkcs15-init - commands to generate or to import a new key is deprecated. - Better practice is to let the middleware to derive the identifier from the key material. - (SHA1(modulus) for RSA, SHA1(pub) for DSA, ...). - This allows easily set up relation between 'related' objects - (private/public keys and certificates). + commands to generate or to import a new key is deprecated. + Better practice is to let the middleware to derive the identifier from the key material. + (SHA1(modulus) for RSA, SHA1(pub) for DSA, ...). + This allows easily set up relation between 'related' objects + (private/public keys and certificates). In addition to the PEM key file format, pkcs15-init also @@ -255,12 +255,12 @@ Options - - - , - - Print the OpenSC package release version. - + + + , + + Print the OpenSC package release version. + name, @@ -289,6 +289,17 @@ + SERIAL + + + + Specify the serial number of the card. + + + + + + , @@ -303,6 +314,18 @@ + AID + + + + This will erase the application with the application identifier + AID. + + + + + + keyspec, keyspec @@ -314,11 +337,11 @@ optionally followed by a slash and the length of the key in bits. It is a good idea to specify the key ID along with this command, using the option, otherwise an intrinsic ID - will be calculated from the key material. Look the description of - the 'pkcs15-id-style' attribut in the 'pkcs15.profile' for the details - about the algorithm used to calculate intrinsic ID. - For the multi-application cards the target PKCS#15 application can be - specified by the hexadecimal AID value of the option. + will be calculated from the key material. Look the description of + the 'pkcs15-id-style' attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. + For the multi-application cards the target PKCS#15 application can be + specified by the hexadecimal AID value of the option. @@ -333,10 +356,10 @@ from filename. The file is supposed to contain one long option per line, without the leading dashes, for instance: - - pin frank - puk zappa - + +pin 1234 +puk 87654321 + You can specify several times. @@ -371,6 +394,17 @@ + , + + + + Do not install a SO PIN, and do not prompt for it. + + + + + + name, name @@ -419,13 +453,25 @@ Tells pkcs15-init to store the certificate given in on the card, creating a certificate object with the ID specified via the option. - Without supplied ID an intrisic ID will be calculated from the - certificate's public key. Look the description of the 'pkcs15-id-style' - attribut in the 'pkcs15.profile' for the details - about the algorithm used to calculate intrinsic ID. + Without supplied ID an intrinsic ID will be calculated from the + certificate's public key. Look the description of the 'pkcs15-id-style' + attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. The file is assumed to contain the PEM encoded certificate. - For the multi-application cards the target application can be specified - by the hexadecimal AID value of the option. + For the multi-application cards the target application can be specified + by the hexadecimal AID value of the option. + + + + + + + , + + + + + Store a new PIN/PUK on the card. @@ -459,11 +505,11 @@ formats can be specified using . It is a good idea to specify the key ID along with this command, using the option, otherwise an intrinsic ID - will be calculated from the key material. Look the description of - the 'pkcs15-id-style' attribut in the 'pkcs15.profile' for the details - about the algorithm used to calculate intrinsic ID. - For the multi-application cards the target PKCS#15 application can be - specified by the hexadecimal AID value of the option. + will be calculated from the key material. Look the description of + the 'pkcs15-id-style' attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. + For the multi-application cards the target PKCS#15 application can be + specified by the hexadecimal AID value of the option. @@ -478,6 +524,8 @@ secret key to the card. The file is assumed to contain the raw key. They key type should be specified with option. + + You may additionally specify the key ID along with this command, using the option, otherwise a random ID is generated. For the multi-application cards the target PKCS#15 application can be @@ -488,6 +536,18 @@ + filename, + filename + + + + Store a data object. + + + + + + filename, filename @@ -495,11 +555,62 @@ Tells pkcs15-init to update the certificate object with the ID specified via the option - with the certificate in . + with the certificate in filename. The file is assumed to contain a PEM encoded certificate. Pay extra attention when updating mail decryption certificates, as - missing certificates can render e-mail messages unreadable! + missing certificates can render e-mail messages unreadable! + + + + + + + arg, + arg + + + + Tells pkcs15-init to delete the + specified object. arg + is comma-separated list containing any of + privkey, pubkey, + secrkey, cert, + chain or data. + + + When data is specified, an + - must also be + specified, in the other cases an + must also be specified + + + When chain is specified, the + certificate chain starting with the cert with + specified ID will be deleted, until there's a CA + certificate that certifies another cert on the card + + + + + + + arg, + arg + + + + Tells pkcs15-init to change the + specified attribute. arg + is either privkey, + pubkey, secrkey, + cert or data. + You also have to specify the + of the object. + For now, you can only change the , e.g: + + pkcs15-init -A cert --id 45 -a 1 --label Jim + @@ -519,6 +630,35 @@ + , + + + + + Tells pkcs15-init to perform a + card specific sanity check and possibly update + procedure. + + + + + + + num, + num + + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + + + + + , @@ -532,11 +672,241 @@ + , + + + Causes pkcs15-init to + wait for a card insertion. + + + + Do not prompt the user; if no PINs supplied, pinpad will be used. + + + ID + + + + Specify ID of PUK to use/create + + + + + + + LABEL + + + + Specify label of PUK + + + + + + + LABEL + + + + Specify public key label (use with ) + + + + + + + LABEL + + + + Specify user cert label (use with ) + + + + + + + arg + + + + Specify application name of data object (use with ) + + + + + + + AID + + + + Specify AID of the on-card PKCS#15 application to be binded to (in hexadecimal form) + + + + + + + filename + filename, + + + + Output public portion of generated key to file + + + + + + + PASSPHRASE + + + + Specify passphrase for unlocking secret key + + + + + + + + + + + Mark certificate as a CA certificate + + + + + + + arg + arg, + + + + Specifies the X.509 key usage. + arg is comma-separated + list containing any of + digitalSignature, + nonRepudiation, + keyEncipherment, + dataEncipherment, + keyAgreement, + keyCertSign, + cRLSign. Abbreviated names are + allowed if unique (e.g. + dataEnc). + + + The alias sign is equivalent to + digitalSignature,keyCertSign,cRLSign + + + The alias decrypt is equivalent to + keyEncipherment,dataEncipherment + + + + + + + + , + + + + Finish initialization phase of the smart card + + + + + + + + + + + Update 'lastUpdate' attribute of tokenInfo + + + + + + + + + + + When storing PKCS#12 ignore CA certificates + + + + + + + + + + + Store or update existing certificate + + + + + + + + + + + Private key stored as an extractable key + + + + + + + + + + + Insecure mode: do not require a PIN for private key + + + + + + + GUID + + + + For a new key specify GUID for a MD container + + + + + + + + , + + + + Display help message + + + + @@ -551,4 +921,10 @@ + + Authors + pkcs15-init was written by + Olaf Kirch okir@suse.de. + + diff -Nru opensc-0.17.0/doc/tools/pkcs15-profile.5.xml opensc-0.19.0/doc/tools/pkcs15-profile.5.xml --- opensc-0.17.0/doc/tools/pkcs15-profile.5.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/pkcs15-profile.5.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ - - - - pkcs15-profile - 5 - OpenSC - OpenSC File Formats - opensc - - - - pkcs15-profile - format of profile for pkcs15-init - - - - Description - - The pkcs15-init utility for PKCS #15 smart card - personalization is controlled via profiles. When starting, it will read two - such profiles at the moment, a generic application profile, and a card - specific profile. The generic profile must be specified on the command line, - while the card-specific file is selected based on the type of card detected. - - - The generic application profile defines general information about the card - layout, such as the path of the application DF, various PKCS #15 files within - that directory, and the access conditions on these files. It also defines - general information about PIN, key and certificate objects. Currently, there - is only one such generic profile, pkcs15.profile. - - - The card specific profile contains additional information required during - card intialization, such as location of PIN files, key references etc. - Profiles currently reside in @pkgdatadir@ - - - - - Syntax - - This section should contain information about the profile syntax. Will add - this soonishly. - - - - - See also - - - pkcs15-init - 1 - , - - pkcs15-crypt - 1 - - - - - diff -Nru opensc-0.17.0/doc/tools/pkcs15-tool.1.xml opensc-0.19.0/doc/tools/pkcs15-tool.1.xml --- opensc-0.17.0/doc/tools/pkcs15-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/pkcs15-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -77,9 +77,16 @@ + + + List card objects. + + + + - List the on-card PKCS#15 applications + List the on-card PKCS#15 applications. @@ -117,6 +124,18 @@ + + + List all secret (symmetric) keys stored on the token. General + information about each secret key is listed (eg. key name, id and + algorithm). Actual secret key values are not displayed. + For some cards the PKCS#15 attributes of the private keys are protected for reading + and need the authentication with the User PIN. + In such a case the option has to be used. + + + + List all PINs stored on the token. General information @@ -243,11 +262,32 @@ + , + , + + Test if the card needs a security update + + + + + , + , + + Update the card with a security update + + + + num - Forces pkcs15-tool to use reader - number num for operations. The default is to use - reader number 0, the first reader in the system. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -271,6 +311,27 @@ + PIN + + Specify PIN + + + + + PUK + + Specify Unblock PIN + + + + + PIN + + Specify New PIN (when changing or unblocking) + + + + Verify PIN after card binding and before issuing any command @@ -279,6 +340,23 @@ + + + Equivalent to + with additional session PIN generation + + + + + , + + + Causes pkcs15-tool to + wait for a card insertion. + + + + Do not prompt the user; if no PINs supplied, pinpad will be used. @@ -302,4 +380,10 @@ + + Authors + pkcs15-tool was written by + Juha Yrjölä juha.yrjola@iki.fi. + + diff -Nru opensc-0.17.0/doc/tools/sc-hsm-tool.1.xml opensc-0.19.0/doc/tools/sc-hsm-tool.1.xml --- opensc-0.17.0/doc/tools/sc-hsm-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/sc-hsm-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -204,8 +204,14 @@ num, num - Use the given reader number. The default is - 0, the first reader in the system. + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -257,4 +263,10 @@ + + Authors + sc-hsm-tool was written by + Andreas Schwier andreas.schwier@cardcontact.de. + + diff -Nru opensc-0.17.0/doc/tools/test-manpage.sh opensc-0.19.0/doc/tools/test-manpage.sh --- opensc-0.17.0/doc/tools/test-manpage.sh 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/test-manpage.sh 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,21 @@ +#!/bin/bash +SOURCE_PATH=../../ + +# find all the manual pages in src/tools +TOOLS=`find "${SOURCE_PATH}/doc/tools" -name "*.1.xml" | sed -E -e "s|.*/([a-z0-9-]*).*|\1|"` +ALL=1 + +for T in $TOOLS; do + SWITCHES=$( ${SOURCE_PATH}/src/tools/${T} --help 2>&1 \ + | grep -v "unrecognized option '--help'" \ + | awk '{if (match($0,"--[a-zA-Z0-9-]*",a) != 0) print a[0]} + {if (match($0," -[a-zA-Z0-9]",a) != 0) print a[0]}' ) + + for S in $SWITCHES; do + grep -q -- "$S" ${SOURCE_PATH}/doc/tools/${T}.1.xml || { echo "${T}: missing switch $S"; ALL=0; }; + done +done +if [ "$ALL" = 0 ]; then + echo "Not all the switches in help are documented in manual pages" + exit 1; +fi diff -Nru opensc-0.17.0/doc/tools/tools.html opensc-0.19.0/doc/tools/tools.html --- opensc-0.17.0/doc/tools/tools.html 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/doc/tools/tools.html 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,2348 @@ +OpenSC Manual Pages: Section 1

OpenSC Manual Pages: Section 1


Table of Contents

cardos-tool — displays information about Card OS-based security tokens or format them +
cryptoflex-tool — utility for manipulating Schlumberger Cryptoflex data structures
dnie-tool — displays information about DNIe based security tokens
egk-tool — displays information on the German electronic health card (elektronische Gesundheitskarte, eGK) +
eidenv — utility for accessing visible data from + electronic identity cards
gids-tool — smart card utility for GIDS cards
iasecc-tool — displays information about IAS/ECC card +
netkey-tool — administrative utility for Netkey E4 cards
npa-tool — displays information on the German eID card (neuer Personalausweis, nPA). +
openpgp-tool — utility for accessing visible data OpenPGP smart cards + and compatible tokens
opensc-asn1 — parse ASN.1 data +
opensc-explorer — + generic interactive utility for accessing smart card + and similar security token functions +
opensc-notify — monitor smart card events and send notifications +
opensc-tool — generic smart card utility
piv-tool — smart card utility for HSPD-12 PIV cards
pkcs11-tool — utility for managing and using PKCS #11 security tokens
pkcs15-crypt — perform crypto operations using PKCS#15 smart cards
pkcs15-init — smart card personalization utility
pkcs15-tool — utility for manipulating PKCS #15 data structures + on smart cards and similar security tokens
sc-hsm-tool — smart card utility for SmartCard-HSM
westcos-tool — utility for manipulating data structures + on westcos smart cards

Name

cardos-tool — displays information about Card OS-based security tokens or format them +

Synopsis

cardos-tool [OPTIONS]

Description

+ The cardos-tool utility is used to display information about +smart cards and similar security tokens based on Siemens Card/OS M4. +

Options

+

+ --card-driver name, + -c name

Use the card driver specified by name. + The default is to auto-detect the correct card driver.

+ --format, + -f +

Format the card or token.

+ --help, + -h +

Print help message on screen.

+ --info, + -i +

Display information about the card or token.

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --startkey arg, + -s arg +

Specify startkey for format.

+ --change-startkey arg, + -S arg +

Change Startkey with given APDU command.

+ --verbose, + -v +

Causes cardos-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc library.

+ --wait, + -w +

Causes cardos-tool to wait for the token + to be inserted into reader.

+

Authors

cardos-tool was written by + Andreas Jellinghaus .


Name

cryptoflex-tool — utility for manipulating Schlumberger Cryptoflex data structures

Synopsis

cryptoflex-tool [OPTIONS]

Description

+ cryptoflex-tool is used to manipulate PKCS + data structures on Schlumberger Cryptoflex smart cards. Users + can create, list and read PINs and keys stored on the smart card. + User PIN authentication is performed for those operations that require it. +

Options

+

+ --app-df num, + -a num +

Specifies the DF to operate in

+ --create-key-files arg, + -c arg +

Creates new RSA key files for arg keys

+ --create-pin-files id, + -P id +

Creates new PIN file for CHVid

+ --exponent exp, + -e exp +

Specifies the RSA exponent, exp, + to use in key generation. The default value is 3.

+ --generate-key, + -g +

Generate a new RSA key pair

+ --key-num num, + -k num +

Specifies the key number to operate on. The default is + key number 1.

+ --list-keys, + -l +

Lists all keys stored in a public key file

+ --modulus-length length, + -m length +

Specifies the modulus length to use + in key generation. The default value is 1024.

+ --prkey-file id, + -p id +

Specifies the private key file id, id, + to use

+ --pubkey-file id, + -u id +

Specifies the public key file id, id, + to use

+ --read-key, + -R +

Reads a public key from the card, allowing the user to + extract and store or use the public key +

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --verbose, + -v +

Causes cryptoflex-tool to be more + verbose. Specify this flag several times to enable debug output in + the opensc library.

+ --verify-pin, + -V +

Verifies CHV1 before issuing commands

+ --wait, + -w +

Causes cryptoflex-tool to + wait for a card insertion.

+

See also

+ pkcs15-tool(1) +

Authors

cryptoflex-tool was written by + Juha Yrjl .


Name

dnie-tool — displays information about DNIe based security tokens

Synopsis

dnie-tool [OPTIONS]

Description

+ The dnie-tool utility is used to display additional information about DNIe, the Spanish National eID card. +

Options

+

+ --idesp, + -i +

Show the DNIe IDESP value.

+ --data, + -d +

Show DNIe personal information. + Reads and print DNIe number and User Name and SurName

+ --all, + -a +

Displays every available information. + This command is equivalent to -d -i -s

+ --serial, + -s +

Displays DNIe Serial Number +

+ --version, + -V +

Show DNIe sw version. + Displays software version for in-card DNIe OS

+ --pin pin, + -p pin +

Specify the user pin pin to use. + If set to env:VARIABLE, the + value of the environment variable + VARIABLE is used. + The default is do not enter pin

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --driver driver, + -c driver +

Specify the card driver driver to use. + Default is use driver from configuration file, or auto-detect if absent

+ --wait, + -w +

Causes dnie-tool to wait for the token to be inserted into reader.

+ --verbose, + -v +

Causes dnie-tool to be more verbose. + Specify this flag several times +to enable debug output in the opensc library.

+

Authors

dnie-tool was written by + Juan Antonio Martinez .


Name

egk-tool — displays information on the German electronic health card (elektronische Gesundheitskarte, eGK) +

Synopsis

egk-tool [OPTIONS]

Description

+ The egk-tool utility is used to display information stored on the German elektronic health card (elektronische Gesundheitskarte, eGK). +

Options

+

+ --help, + -h

Print help and exit.

+ --version, + -V

Print version and exit.

+ --reader arg, + -r arg +

+ Specify the reader to use. + Use -1 as arg + to automatically detect the reader to use. + By default, the first reader with a present card is used. +

+ --verbose, + -v +

+ Causes egk-tool to be more verbose. + Specify this flag several times to be more verbose. +

+

Health Care Application (HCA)

--pd

+ Show 'Persnliche Versicherungsdaten' (XML). +

--vd

+ Show 'Allgemeine Versicherungsdaten' (XML). +

--gvd

+ Show 'Geschtzte Versicherungsdaten' (XML). +

--vsd-status

+ Show 'Versichertenstammdaten-Status'. +

Authors

egk-tool was written by + Frank Morgner .


Name

eidenv — utility for accessing visible data from + electronic identity cards

Synopsis

eidenv [OPTIONS]

Description

+ The eidenv utility is used for + accessing data from electronic identity cards (like + national eID cards) which might not be present in + PKCS#15 objects but available in custom files on the + card. The data can be printed on screen or used by + other programs via environment variables. +

Options

+

+ --exec prog, + -x prog +

Executes the given program with + data in environment variables.

+ --help, + -h +

Print help message on screen.

+ --print, + -p +

Prints all data + fields from the card, like validity + period, document number etc.

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --stats, + -t +

Prints key usage statistics + (only for Estonian ID card).

+ --version, + -v +

Prints the version + of the utility and exits.

+ --wait, + -w +

Wait for a card to be inserted

+

Authors

eidenv utility was written by + Stef Hoeben and Martin Paljak .


Name

gids-tool — smart card utility for GIDS cards

Synopsis

gids-tool [OPTIONS]

+ The gids-tool utility can be used from the command line to perform + miscellaneous smart card operations on a GIDS smart card. +

Options

+

+ -X, + --initialize +

Initialize token.

+ --admin-key argument +

Define the administrator key

+ --pin argument +

Define user PIN.

+ --serial-number argument +

Define serial number.

+ -U, + --unblock +

Unblock the user PIN after an administrator + authentication.

+ -C, + --change-admin-key +

Change the administrator key.

+ --new-admin-key argument +

Define the new administrator key.

+ --reader argument, + -r argument +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ -w, + --wait +

Wait for a card to be inserted.

+ -v, + --verbose +

Verbose operation. Use several times to + enable debug output.

+

See also

+ opensc-tool(1) +

Authors

gids-tool was written by + Vincent Le Toux .


Name

iasecc-tool — displays information about IAS/ECC card +

Synopsis

iasecc-tool [OPTIONS]

Description

+ The iasecc-tool utility is used to display information about IAS/ECC v1.0.1 smart cards. +

Options

+

+ --reader num, +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --list-applications, +

Get list of the on-card applications.

+ --aid hex-aid, +

Select hex-aid before processing.

+ --list-sdos sdo-type, +

List SDOs of the given sdo-type, + present in default or selected application.

+ --verbose, + -v +

Causes cardos-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc library.

+ --wait, + -w +

Causes iasecc-tool to wait for the token + to be inserted into reader.

+

Authors

iasecc-tool was written by + Viktor Tarasov .


Name

netkey-tool — administrative utility for Netkey E4 cards

Synopsis

netkey-tool [OPTIONS] [COMMAND]

Description

The netkey-tool utility can be used from the + command line to perform some smart card operations with NetKey E4 cards + that cannot be done easily with other OpenSC-tools, such as changing local + PINs, storing certificates into empty NetKey E4 cert-files or displaying + the initial PUK-value.

Options

+

+ --help, + -h +

Displays a short help message.

+ --pin pin-value, + -p pin-value +

Specifies the current value of the global PIN.

+ --puk pin-value, + -u pin-value +

Specifies the current value of the global PUK.

+ --pin0 pin-value, + -0 pin-value +

Specifies the current value of the local PIN0 (aka local PIN).

+ --pin1 pin-value, + -1 pin-value +

Specifies the current value of the local PIN1 (aka local PUK).

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ -v +

Causes netkey-tool to be more verbose. This + options may be specified multiple times to increase verbosity.

+

PIN format

With the -p, -u, -0 or the -1 + one of the cards pins may be specified. You may use plain ascii-strings (i.e. 123456) or a hex-string + (i.e. 31:32:33:34:35:36). A hex-string must consist of exactly n 2-digit hexnumbers separated by n-1 colons. + Otherwise it will be interpreted as an ascii string. For example :12:34: and 1:2:3:4 are both pins of + length 7, while 12:34 and 01:02:03:04 are pins of length 2 and 4.

Commands

When used without any options or commands, netkey-tool will + display information about the smart cards pins and certificates. This will not change + your card in any aspect (assumed there are no bugs in netkey-tool). + In particular the tries-left counters of the pins are investigated without doing + actual pin-verifications.

If you specify the global PIN via the --pin option, + netkey-tool will also display the initial value of the cards + global PUK. If your global PUK was changed netkey-tool will still + display its initial value. There's no way to recover a lost global PUK once it was changed. + There's also no way to display the initial value of your global PUK without knowing the + current value of your global PIN.

For most of the commands that netkey-tool can execute, you have + to specify one pin. One notable exception is the nullpin command, but + this command can only be executed once in the lifetime of a NetKey E4 card.

+

+ cert number filename +

This command will read one of your cards certificates (as specified by + number) and save this certificate into file filename + in PEM-format. Certificates on a NetKey E4 card are readable without a pin, so you don't + have to specify one.

+ cert filename number +

This command will read the first PEM-encoded certificate from file + filename and store this into your smart cards certificate file + number. Some of your smart cards certificate files might be readonly, so + this will not work with all values of number. If a certificate file is + writable you must specify a pin in order to change it. If you try to use this command + without specifying a pin, netkey-tool will tell you which one is + needed.

+ change + { pin | puk | pin0 | pin1 } + new-pin +

This changes the value of the specified pin to the given new value. + You must specify either the current value of the pin or another pin to be able to do + this and if you don't specify a correct one, netkey-tool will tell + you which one is needed.

+ nullpin initial-pin +

This command can be executed only if the global PIN of your card is + in nullpin-state. There's no way to return back to nullpin-state once you have changed + your global PIN. You don't need a pin to execute the nullpin-command. After a successful + nullpin-command netkey-tool will display your cards initial + PUK-value.

+ unblock + { pin | pin0 | pin1 } +

This unblocks the specified pin. You must specify another pin + to be able to do this and if you don't specify a correct one, + netkey-tool will tell you which one is needed.

+

See also

+ opensc-explorer(1) +

Authors

netkey-tool was written by + Peter Koch .


Name

npa-tool — displays information on the German eID card (neuer Personalausweis, nPA). +

Synopsis

npa-tool [OPTIONS]

Description

+ The npa-tool utility is used to display information + stored on the German eID card (neuer Personalausweis, nPA), + and to perform some write and verification operations. +

Options

+

+ --help, + -h

Print help and exit.

+ --version, + -V

Print version and exit.

+ --reader arg, + -r arg +

+ Specify the reader to use. + Use -1 as arg + to automatically detect the reader to use. + By default, the first reader with a present card is used. +

+ --verbose, + -v +

+ Causes npa-tool to be more verbose. + Specify this flag several times to be more verbose. +

+

Password Authenticated Connection Establishment (PACE)

+ --pin [STRING], + -p [STRING] +

+ Run PACE with (transport) eID-PIN. +

+ --puk [STRING], + -u [STRING] +

+ Run PACE with PUK. +

+ --can [STRING], + -c [STRING] +

+ Run PACE with Card Access Number (CAN). +

+ --mrz [STRING], + -m [STRING] +

+ Run PACE with Machine Readable Zone (MRZ). + Enter the MRZ without newlines. +

--env

+ Specify whether to use environment variables PIN, + PUK, CAN, MRZ, + and NEWPIN. + You may want to clean your environment before enabling this. + (default=off) +

PIN management

+ --new-pin [STRING], + -N [STRING] +

+ Install a new PIN. +

+ --resume, + -R +

+ Resume eID-PIN (uses CAN to activate last retry). + (default=off) +

+ --unblock, + -U +

+ Unblock PIN (uses PUK to activate three more retries). + (default=off) +

Terminal Authentication (TA) and Chip Authentication (CA)

+ --cv-certificate FILENAME, + -C FILENAME +

+ Specify Card Verifiable (CV) certificate + to create a certificate chain. + The option can be given multiple times, in which case the + order is important. +

--cert-desc HEX_STRING

+ Certificate description to show for Terminal Authentication. +

--chat HEX_STRING

+ Specify the Card Holder Authorization Template + (CHAT) to use. + If not given, it defaults to the terminal's CHAT. + Use 7F4C0E060904007F000703010203530103 + to trigger EAC on the CAT-C (Komfortleser). +

+ --auxiliary-data HEX_STRING, + -A HEX_STRING +

+ Specify the terminal's auxiliary data. + If not given, the default is determined by verification + of validity, age and community ID. +

+ --private-key FILENAME, + -P FILENAME +

+ Specify the terminal's private key. +

--cvc-dir DIRECTORY

+ Specify where to look for the certificate of the + Country Verifying Certification Authority + (CVCA). + If not given, it defaults to + /home/fm/.local/etc/eac/cvc. +

+ --x509-dir DIRECTORY

+ Specify where to look for the X.509 certificate. + If not given, it defaults to + /home/fm/.local/etc/eac/x509. +

--disable-ta-checks

+ Disable checking the validity period of CV certificates. + (default=off) +

--disable-ca-checks

+ Disable passive authentication. (default=off) +

Read and write data groups

--read-dg1

Read data group 1: Document Type.

--read-dg2

Read data group 2: Issuing State.

--read-dg3

Read data group 3: Date of Expiry.

--read-dg4

Read data group 4: Given Name(s).

--read-dg5

Read data group 5: Family Name.

--read-dg6

Read data group 6: Religious/Artistic Name.

--read-dg7

Read data group 7: Academic Title.

--read-dg8

Read data group 8: Date of Birth.

--read-dg9

Read data group 9: Place of Birth.

--read-dg10

Read data group 10: Nationality.

--read-dg11

Read data group 11: Sex.

--read-dg12

Read data group 12: Optional Data.

--read-dg13

Read data group 13: Birth Name.

--read-dg14

Read data group 14.

--read-dg15

Read data group 15.

--read-dg16

Read data group 16.

--read-dg17

Read data group 17: Normal Place of Residence.

--read-dg18

Read data group 18: Community ID.

--read-dg19

Read data group 19: Residence Permit I.

--read-dg20

Read data group 20: Residence Permit II.

--read-dg21

Read data group 21: Optional Data.

+ --write-dg17 HEX_STRING

Write data group 17: Normal Place of Residence.

+ --write-dg18 HEX_STRING

Write data group 18: Community ID.

+ --write-dg19 HEX_STRING

Write data group 19: Residence Permit I.

+ --write-dg20 HEX_STRING

Write data group 20: Residence Permit II.

--write-dg21 HEX_STRING

Write data group 21: Optional Data.

Verification of validity, age and community ID

--verify-validity YYYYMMDD

+ Verify chip's validity with a reference date. +

--older-than YYYYMMDD

+ Verify age with a reference date. +

--verify-community HEX_STRING

+ Verify community ID with a reference ID. +

Special options, not always useful

+ --break, + -b +

+ Brute force PIN, CAN or PUK. + Use together with options -p, + -a, or -u. + (default=off) +

+ --translate FILENAME, + -t FILENAME +

+ Specify the file with APDUs of HEX_STRINGs to send + through the secure channel. + (default=`stdin') +

--tr-03110v201

+ Force compliance to BSI TR-03110 version 2.01. (default=off) +

--disable-all-checks

+ Disable all checking of fly-by-data. (default=off) +

Authors

npa-tool was written by + Frank Morgner .


Name

openpgp-tool — utility for accessing visible data OpenPGP smart cards + and compatible tokens

Synopsis

openpgp-tool [OPTIONS]

Description

+ The openpgp-tool utility is used for + accessing data from the OpenPGP v1.1 and v2.0 smart cards + and compatible tokens like e.g. GPF CryptoStick v1.x, + which might not be present in + PKCS#15 objects but available in custom files on the + card. The data can be printed on screen or used by + other programs via environment variables. +

Options

+

+ --del-key arg +

+ Delete key indicated by arg. + arg can be 1, + 2, 3, or + all. +

+ --do arg, + -d arg +

+ Dump private data object (DO) + indicated by arg. + arg can be in the form + x, + 10x, or + 010x + to access DO 010x, + where x is 1, + 2, 3, or + 4. +

+ --erase, + -E +

+ Erase (i.e. reset) the card. +

+ --exec prog, + -x prog +

+ Execute the given program with data in environment variables. +

+ --gen-key arg, + -G arg +

+ Generate key with the ID given as arg. + arg can be one of 1, + 2, or 3. +

+ --help, + -h +

+ Print help message on screen. +

+ --key-length bitlength, + -L bitlength +

+ Specify the length of the key to be generated. + If not given, it defaults to 2048 bit. +

+ --pin string +

+ The PIN text to verify. If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used. +

+ --pretty +

+ Print values in pretty format. +

+ --raw +

+ Print values in raw format, as they are stored on the card. +

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --user-info, + -U +

+ Show card holder information. +

+ --verify pintype +

+ Verify PIN (CHV1, CHV2 or CHV3). +

+ --version, + -V +

+ Print the version of the utility and exit. +

+ --verbose, + -v +

+ Verbose operation. Use several times to enable debug output. +

+ --wait, + -w +

+ Wait for a card to be inserted. +

+

Authors

openpgp-tool utility was written by + Peter Marschall .


Name

opensc-asn1 — parse ASN.1 data +

Synopsis

opensc-asn1 [OPTIONS] [FILES]

Description

+ The opensc-asn1 utility is used to parse ASN.1 data. +

Options

+

+ --help, + -h

Print help and exit.

+ --version, + -V

Print version and exit.

+

Authors

opensc-asn1 was written by + Frank Morgner .


Name

opensc-explorer — + generic interactive utility for accessing smart card + and similar security token functions +

Synopsis

opensc-explorer [OPTIONS] [SCRIPT]

Description

+ The opensc-explorer utility can be + used interactively to perform miscellaneous operations + such as exploring the contents of or sending arbitrary + APDU commands to a smart card or similar security token. +

Options

+ The following are the command-line options for + opensc-explorer. There are additional + interactive commands available once it is running. +

+ --card-driver driver, + -c driver +

+ Use the given card driver. The default is + auto-detected. +

+ --mf path, + -m path +

+ Select the file referenced by the given path on + startup. The default is the path to the standard master file, + 3F00. If path is empty (e.g. opensc-explorer + --mf ""), then no file is explicitly selected. +

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --verbose, -v +

+ Causes opensc-explorer to be more + verbose. Specify this flag several times to enable + debug output in the opensc library. +

+ --wait, -w +

Wait for a card to be inserted

+

Commands

+ The following commands are supported at opensc-explorer's + interactive prompt or in script files passed via the command line parameter + SCRIPT. +

+ apdu + hex-data +

Send a custom APDU command hex-data.

+ asn1 + file-id +

Parse and print the ASN.1 encoded content of the file specified by + file-id.

+ cat + [ file-id | sfi:short-id ] +

Print the contents of the currently selected EF or the contents + of a file specified by file-id or the short file id + short-id. +

+ cd + { .. | file-id | aid:DF-name } +

+ Change to another DF specified by the argument passed. + If the argument given is .., + then move up one level in the file system hierarchy. + If it is file-id, + which must be a DF directly + beneath the current DF, then change to that DF. + If it is an application identifier given as + aid:DF-name, + then jump to the MF of the application denoted by + DF-name. +

+ change + CHVpin-ref + [ + [old-pin] + new-pin + ] +

Change a PIN, where pin-ref is the PIN reference.

+ Examples: +

change CHV2 00:00:00:00:00:00 "foobar"

+ Change PIN CHV2 + to the new value foobar, + giving the old value 00:00:00:00:00:00. +

change CHV2 "foobar"

+ Set PIN CHV2 + to the new value foobar. +

change CHV2

+ Change PIN CHV2 using the card reader's pinpad. +

+

+ create + file-id + size +

Create a new EF. file-id specifies the + id number and size is the size of the new file. +

+ debug + [level] +

Set OpenSC debug level to level.

If level is omitted the current debug level will be shown.

+ delete + file-id +

Remove the EF or DF specified by file-id

+ do_get + hex-tag + [output] +

Copy the internal card's 'tagged' data into the local file.

The local file is specified by output while the tag of + the card's data is specified by hex-tag. +

+ If output is omitted, the name of the output file will be + derived from hex-tag. +

+ do_put + hex-tag + input +

Update internal card's 'tagged' data.

hex-tag is the tag of the card's data. + input is the filename of the source file or the literal data presented as + a sequence of hexadecimal values or " enclosed string. +

+ echo + string... +

Print the strings given.

+ erase +

Erase the card, if the card supports it.

+ get + file-id + [output] +

Copy an EF to a local file. The local file is specified + by output while the card file is specified by file-id. +

+ If output is omitted, the name of the output file will be + derived from the full card path to file-id. +

+ info + [file-id] +

Display attributes of a file specified by file-id. + If file-id is not supplied, + the attributes of the current file are printed.

+ ls + [pattern...] +

List files in the current DF. + If no pattern is given, then all files are listed. + If one ore more patterns are given, only files matching + at least one pattern are listed.

+ find + [ + start-id + [end-id] + ] +

Find all files in the current DF. + Files are found by selecting all file identifiers in the range from start-fid to end-fid (by default from 0000 to FFFF).

+ find_tags + [ + start-tag + [end-tag] + ] +

Find all tags of data objects in the current context. + Tags are found by using GET DATA in the range from start-tag to end-tag (by default from 0000 to FFFF).

+ mkdir + file-id + size +

Create a DF. file-id specifies the id number + and size is the size of the new file.

+ put + file-id + input +

Copy a local file to the card. The local file is specified + by input while the card file is specified by file-id. +

+ quit +

Exit the program.

+ random + count +

Generate random sequence of count bytes.

+ rm + file-id +

Remove the EF or DF specified by file-id

+ unblock + CHVpin-ref + [ + puk + [new-pin] + ] +

+ Unblock the PIN denoted by pin-ref + using the PUK puk, and set potentially + change its value to new-pin. +

+ PUK and PIN values can be a sequence of hexadecimal values, + "-enclosed strings, empty (""), + or absent. + If they are absent, the values are read from the card reader's pin pad. +

+ Examples: +

unblock CHV2 00:00:00:00:00:00 "foobar"

+ Unblock PIN CHV2 using PUK + 00:00:00:00:00:00 + and set it to the new value foobar. +

unblock CHV2 00:00:00:00:00:00 ""

+ Unblock PIN CHV2 using PUK + 00:00:00:00:00:00 keeping the old value. +

unblock CHV2 "" "foobar"

+ Set new value of PIN CHV2 + to foobar. +

unblock CHV2 00:00:00:00:00:00

+ Unblock PIN CHV2 using PUK + 00:00:00:00:00:00. + The new PIN value is prompted by pinpad. +

unblock CHV2 ""

+ Set PIN CHV2. + The new PIN value is prompted by pinpad. +

unblock CHV2

+ Unblock PIN CHV2. + The unblock code and new PIN value are prompted by pinpad. +

+

+ update_binary + file-id + offs + data +

Binary update of the file specified by + file-id with the literal data + data starting from offset specified + by offs.

data can be supplied as a sequencer + of the hex values or as a " enclosed string.

+ update_record + file-id + rec-nr + rec-offs + data +

Update record specified by rec-nr of the file + specified by file-id with the literal data + data starting from offset specified by + rec-offs.

data can be supplied as a sequence of the hex values or + as a " enclosed string.

+ verify + key-typekey-id + [key] +

Present a PIN or key to the card, where + key-type can be one of CHV, + KEY, AUT or PRO. + key-id is a number representing the key or PIN reference. + key is the key or PIN to be verified, formatted as a + colon-separated list of hex values or a " enclosed string. +

+ If key is omitted, the exact action depends on the + card reader's features: if the card readers supports PIN input via a pin pad, + then the PIN will be verified using the card reader's pin pad. + If the card reader does not support PIN input, then the PIN will be asked + interactively. +

+ Examples: +

verify CHV0 31:32:33:34:00:00:00:00

+ Verify CHV2 using the hex value + 31:32:33:34:00:00:00:00 +

verify CHV1 "secret"

+ Verify CHV1 + using the string value secret. +

verify KEY2

+ Verify KEY2, + get the value from the card reader's pin pad. +

+

+ sm + { open | close } +

Calls the card's open or close Secure Messaging handler.

+

See also

+ opensc-tool(1) +

Authors

opensc-explorer was written by + Juha Yrjl .


Name

opensc-notify — monitor smart card events and send notifications +

Synopsis

opensc-notify [OPTIONS]

Description

+ The opensc-notify utility is used to + monitor smart card events and send the appropriate notification. +

Options

+

+ --help, + -h

Print help and exit.

+ --version, + -V

Print version and exit.

+

Mode: customized

+ Send customized notifications. +

+ --title [STRING], + -t [STRING] +

+ Specify the title of the notification. +

+ --message [STRING], + -m [STRING] +

+ Specify the main text of the notification. +

Mode: standard

+ Manually send standard notifications. +

+ --notify-card-inserted, + -I

+ See notify_card_inserted + in opensc.conf (default=off). +

+ --notify-card-removed, + -R

+ See notify_card_removed + in opensc.conf (default=off). +

+ --notify-pin-good, + -G

+ See notify_pin_good + in opensc.conf (default=off). +

+ --notify-pin-bad, + -B

+ See notify_pin_bad + in opensc.conf (default=off). +

Authors

opensc-notify was written by + Frank Morgner .


Name

opensc-tool — generic smart card utility

Synopsis

opensc-tool [OPTIONS]

Description

+ The opensc-tool utility can be used from the command line to perform + miscellaneous smart card operations such as getting the card ATR or + sending arbitrary APDU commands to a card. +

Options

+

+ --version, +

Print the OpenSC package release version.

+ --atr, + -a +

Print the Answer To Reset (ATR) of the card. + Output is in hex byte format

+ --card-driver driver, + -c driver +

Use the given card driver. + The default is auto-detected.

+ --list-algorithms, +

Lists algorithms supported by card

+ --info, + -i +

Print information about OpenSC, such as version and enabled components.

+ --list-drivers, + -D +

List all installed card drivers.

+ --list-files, + -f +

Recursively list all files stored on card.

+ --list-readers, + -l +

List all configured readers.

+ --name, + -n +

Print the name of the inserted card (driver).

+ --get-conf-entry conf, + -G conf +

Get configuration key, format: section:name:key

+ --set-conf-entry conf, + -S conf +

Get configuration key, format: section:name:key:value

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --reset [type], +

Resets the card in reader. + The default reset type is cold, + but warm reset is also possible.

+ --send-apdu apdu, + -s apdu +

Sends an arbitrary APDU to the card in the format + AA:BB:CC:DD:EE:FF....

+ --serial +

Print the card serial number (normally the ICCSN). + Output is in hex byte format

+ --verbose, + -v +

Causes opensc-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc library.

+ --wait, + -w +

Wait for a card to be inserted.

+

See also

+ opensc-explorer(1) +

Authors

opensc-tool was written by + Juha Yrjl .


Name

piv-tool — smart card utility for HSPD-12 PIV cards

Synopsis

piv-tool [OPTIONS]

+ The piv-tool utility can be used from the command line to perform + miscellaneous smart card operations on a HSPD-12 PIV smart card as defined in NIST 800-73-3. + It is intended for use with test cards only. It can be used to load objects, and generate + key pairs, as well as send arbitrary APDU commands to a card after having authenticated + to the card using the card key provided by the card vendor. +

Options

+

+ --serial +

Print the card serial number derived from the CHUID object, + if any. Output is in hex byte format.

+ --name, + -n +

Print the name of the inserted card (driver)

+ --admin argument, + -A argument +

Authenticate to the card using a 2DES or 3DES key. + The argument of the form +

 {A|M}:ref:alg

+ is required, were A uses "EXTERNAL AUTHENTICATION" + and M uses "MUTUAL AUTHENTICATION". + ref is normally 9B, + and alg is 03 for 3DES. + The key is provided by the card vendor, and the environment variable + PIV_EXT_AUTH_KEY must point to a text file containing + the key in the format: + XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX +

+ --genkey argument, + -G argument +

Generate a key pair on the card and output the public key. + The argument of the form +

ref:alg

+ is required, where ref is 9A, + 9C, 9D or 9E and + alg is 06, + 07, 11 or 14 + for RSA 1024, RSA 2048, ECC 256 or ECC 384 respectively.

+ --object ContainerID, + -O ContainerID +

Load an object onto the card. + The ContainerID is as defined in NIST 800-73-n + without leading 0x. Example: CHUID object is 3000 +

+ --cert ref, + -C ref +

Load a certificate onto the card. + ref is 9A, + 9C, 9D or + 9E

+ --compresscert ref, + -Z ref +

Load a certificate that has been gzipped onto the card. + ref is 9A, + 9C, 9D or + 9E

+ --out file, + -o file +

Output file for any operation that produces output. +

+ --in file, + -i file +

Input file for any operation that requires an input file. +

+ --key-slots-discovery file +

Print properties of the key slots. Needs 'admin' authentication. +

+ --send-apdu apdu, + -s apdu +

Sends an arbitrary APDU to the card in the format + AA:BB:CC:DD:EE:FF.... + This option may be repeated.

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --card-driver driver, + -c driver +

Use the given card driver. + The default is auto-detected.

+ --wait, + -w +

Wait for a card to be inserted

+ --verbose, + -v +

Causes piv-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc + library.

+

See also

+ opensc-tool(1) +

Authors

piv-tool was written by + Douglas E. Engert .


Name

pkcs11-tool — utility for managing and using PKCS #11 security tokens

Synopsis

pkcs11-tool [OPTIONS]

Description

+ The pkcs11-tool utility is used to manage the + data objects on smart cards and similar PKCS #11 security tokens. + Users can list and read PINs, keys and certificates stored on the + token. User PIN authentication is performed for those operations + that require it. +

Options

+

+ --attr-from filename +

Extract information from filename + (DER-encoded certificate file) and create the corresponding + attributes when writing an object to the token. Example: the + certificate subject name is used to create the CKA_SUBJECT + attribute.

+ --change-pin, + -c +

Change the user PIN on the token

+ --unlock-pin +

Unlock User PIN (without --login + unlock in logged in session; otherwise --login-type + has to be 'context-specific').

+ --hash, + -h +

Hash some data.

+ --hash-algorithm mechanism +

+ Specify hash algorithm used with RSA-PKCS-PSS signature or RSA-OAEP decryption. + Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may + also allow "SHA224". Default is "SHA-1". +

+ Note that the input to RSA-PKCS-PSS has to be of the size equal to + the specified hash algorithm. E.g., for SHA256 the signature input must + be exactly 32 bytes long (for mechanisms SHA256-RSA-PKCS-PSS there is no + such restriction). For RSA-OAEP, the plaintext input size mLen must be + at most keyLen - 2 - 2*hashLen. For example, for RSA 3072-bit key and + SHA384, the longest plaintext to encrypt with RSA-OAEP is (with all + sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes. +

+ --id id, + -d id +

Specify the id of the object to operate on.

+ --init-pin +

Initializes the user PIN. This option + differs from --change-pin in that it sets the user PIN + for the first time. Once set, the user PIN can be changed + using --change-pin.

+ --init-token +

Initialize a token: set the token label as + well as a Security Officer PIN (the label must be specified + using --label).

+ --input-file filename, + -i filename +

Specify the path to a file for input.

+ --keypairgen, + -k +

Generate a new key pair (public and private pair.)

+ --keygen +

Generate a new key.

+ --key-type specification +

Specify the type and length of the key to create, for example rsa:1024 or EC:prime256v1.

+ --usage-sign +

Specify 'sign' key usage flag (sets SIGN in privkey, sets VERIFY in pubkey).

+ --usage-decrypt +

Specify 'decrypt' key usage flag (RSA only, set DECRYPT privkey, ENCRYPT in pubkey).

+ --usage-derive +

Specify 'derive' key usage flag (EC only).

+ --label name, + -a name +

Specify the name of the object to operate on + (or the token label when --init-token + is used).

+ --list-mechanisms, + -M +

Display a list of mechanisms supported by the token.

+ --list-objects, + -O +

Display a list of objects.

+ --list-slots, + -L +

Display a list of available slots on the token.

+ --list-token-slots, + -T +

List slots with tokens.

+ --login, + -l +

Authenticate to the token before performing + other operations. This option is not needed if a PIN is + provided on the command line.

+ --login-type +

Specify login type ('so', 'user', 'context-specific'; + default:'user').

+ --mechanism mechanism, + -m mechanism +

Use the specified mechanism + for token operations. See -M for a list + of mechanisms supported by your token. The mechanism can also be specified in + hexadecimal, e.g., 0x80001234.

+ --mgf function +

Use the specified Message Generation + Function (MGF) function + for RSA-PKCS-PSS signatures or RSA-OAEP decryptions. Supported arguments are MGF1-SHA1 + to MGF1-SHA512 if supported by the driver. + The default is based on the hash selection. +

+ --module mod +

Specify a PKCS#11 module (or library) to + load.

+ --moz-cert filename, + -z filename +

Test a Mozilla-like keypair generation + and certificate request. Specify the filename + to the certificate file.

+ --output-file filename, + -o filename +

Specify the path to a file for output.

+ --pin pin, + -p pin +

Use the given pin for + token operations. If set to + env:VARIABLE, the value of the + environment variable VARIABLE is + used. WARNING: Be careful using this option + as other users may be able to read the command line from + the system or if it is embedded in a script. If set to + env:VARIABLE, the value of the + environment variable VARIABLE is + used.

This option will also set + the --login option.

+ --puk puk +

Supply User PUK on the command line.

+ --new-pin pin +

Supply new User PIN on the command line.

+ --sensitive +

Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext).

+ --set-id id, + -e id +

Set the CKA_ID of the object.

+ --show-info, + -I +

Display general token information.

+ --sign, + -s +

Sign some data.

+ --decrypt, +

Decrypt some data.

+ --derive, +

Derive a secret key using another key and some data.

+ --derive-pass-der, +

Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations

+ --salt-len bytes +

Specify how many bytes of salt should + be used in RSA-PSS signatures. Accepts two special values: + "-1" means salt length equals to digest length, + "-2" means use maximum permissible length. + Default is digest length (-1).

+ --slot id +

Specify the id of the slot to use.

+ --slot-description description +

Specify the description of the slot to use.

+ --slot-index index +

Specify the index of the slot to use.

+ --token-label label +

Specify the label of token. + Will be used the first slot, that has the inserted token with this + label.

+ --so-pin pin +

Use the given pin as the + Security Officer PIN for some token operations (token + initialization, user PIN initialization, etc). If set to + env:VARIABLE, the value of the + environment variable VARIABLE is + used. The same warning as --pin also + applies here.

+ --test, + -t +

Perform some tests on the token. This + option is most useful when used with either --login + or --pin.

+ --test-hotplug +

Test hotplug capabilities (C_GetSlotList + + C_WaitForSlotEvent).

+ --private +

Set the CKA_PRIVATE attribute (object is only + viewable after a login).

+ --test-ec +

Test EC (best used with the --login + or --pin option).

+ --test-fork +

Test forking and calling C_Initialize() in the + child.

+ --type type, + -y type +

Specify the type of object to operate on. + Examples are cert, privkey + and pubkey.

+ --verbose, -v +

Cause pkcs11-tool to be + more verbose.

NB! This does not affect + OpenSC debugging level! To set OpenSC PKCS#11 module into debug + mode, set the OPENSC_DEBUG environment variable to a + non-zero number.

+ --read-object, + -r +

Get object's CKA_VALUE attribute (use with + --type).

+ --delete-object, + -b +

Delete an object.

+ --application-label label +

Specify the application label of the data object (use with + --type data).

+ --application-id id +

Specify the application ID of the data object (use with + --type data).

+ --issuer data +

Specify the issuer in hexadecimal format (use with + --type cert).

+ --subject data +

Specify the subject in hexadecimal format (use with + --type cert/privkey/pubkey).

+ --signature-format format +

Format for ECDSA signature: 'rs' (default), + 'sequence', 'openssl'.

+ --write-object filename, + -w filename +

Write a key or certificate object to the token. + filename points to the DER-encoded certificate or key file. +

+ --generate-random num +

Get num bytes of random data. +

+

Examples

+ To list all certificates on the smart card: +

pkcs11-tool --list-objects --type cert

+ + To read the certificate with ID KEY_ID + in DER format from smart card: +

pkcs11-tool --read-object  --id KEY_ID --type cert --outfile cert.der

+ + To convert the certificate in DER format to PEM format, use OpenSSL + tools: +

openssl x509 -inform DER -in cert.der -outform PEM > cert.pem

+ + To sign some data stored in file data + using the private key with ID ID and + using the RSA-PKCS mechanism: +

pkcs11-tool --sign --id ID --mechanism RSA-PKCS --input-file data --output-file data.sig

+

Authors

pkcs11-tool was written by + Olaf Kirch .


Name

pkcs15-crypt — perform crypto operations using PKCS#15 smart cards

Synopsis

pkcs15-crypt [OPTIONS]

Description

+ The pkcs15-crypt utility can be used from the + command line to perform cryptographic operations such as computing + digital signatures or decrypting data, using keys stored on a PKCS#15 + compliant smart card. +

Options

+

+ --version, +

Print the OpenSC package release version.

+ --aid aid +

Specify the AID of the on-card PKCS#15 application + to bind to. The aid must be in hexadecimal + form.

+ --decipher, + -c +

Decrypt the contents of the file specified by + the --input option. The result of the + decryption operation is written to the file specified by the + --output option. If this option is not given, + the decrypted data is printed to standard output, displaying + non-printable characters using their hex notation xNN (see also + --raw).

+ --input file, + -i file +

Specifies the input file to use. Defaults to stdin if + not specified.

+ --key id, + -k id +

Selects the ID of the key to use.

+ --output file, + -o file +

Any output will be sent to the specified file. Defaults + to stdout if not specified.

+ --pin pin, + -p pin +

When the cryptographic operation requires a + PIN to access the key, pkcs15-crypt will + prompt the user for the PIN on the terminal. Using this option + allows you to specify the PIN on the command line.

Note that on most operating systems, the command line of + a process can be displayed by any user using the ps(1) + command. It is therefore a security risk to specify + secret information such as PINs on the command line. + If you specify '-' as PIN, it will be read from STDIN.

+ --pkcs1 +

By default, pkcs15-crypt + assumes that input data has been padded to the correct length + (i.e. when computing an RSA signature using a 1024 bit key, + the input must be padded to 128 bytes to match the modulus + length). When giving the --pkcs1 option, + however, pkcs15-crypt will perform the + required padding using the algorithm outlined in the + PKCS #1 standard version 1.5.

+ --raw, + -R +

Outputs raw 8 bit data.

+ --reader N, + -r N +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --md5 + --sha-1 + --sha-224 + --sha-256 + --sha-384 + --sha-512 +

These options tell pkcs15-crypt + that the input file is the result of the specified hash operation. + By default, an MD5 hash is expected. Again, the data must be in binary + representation.

+ --sign, + -s +

Perform digital signature operation on + the data read from a file specified using the --input + option. By default, the contents of the file are assumed to + be the result of an MD5 hash operation. + Note that pkcs15-crypt + expects the data in binary representation, not ASCII.

The digital signature is stored, in binary representation, + in the file specified by the --output option. If + this option is not given, the signature is printed on standard + output, displaying non-printable characters using their hex notation + xNN + (see also --raw).

+ --signature-format, + --f +

When signing with ECDSA key this option indicates + to pkcs15-crypt the signature output format. + Possible values are 'rs'(default) -- two concatenated + integers (PKCS#11), 'sequence' or 'openssl' -- DER encoded sequence + of two integers (OpenSSL).

+ --wait, + -w +

Causes pkcs15-crypt to + wait for a card insertion.

+ --verbose, + -v +

Causes pkcs15-crypt to be more + verbose. Specify this flag several times to enable debug output + in the OpenSC library.

+

See also

+ pkcs15-init(1), + pkcs15-tool(1) +

Authors

pkcs15-crypt was written by + Juha Yrjl .


Name

pkcs15-init — smart card personalization utility

Synopsis

pkcs15-init [OPTIONS]

Description

+ The pkcs15-init utility can be used to create a PKCS #15 + structure on a smart card, and add key or certificate objects. Details of the + structure that will be created are controlled via profiles. +

+ The profile used by default is pkcs15. Alternative + profiles can be specified via the -p switch. +

PIN Usage

+ pkcs15-init can be used to create a PKCS #15 structure on + your smart card, create PINs, and install keys and certificates on the card. + This process is also called personalization. +

+ An OpenSC card can have one security officer PIN, and zero or more user PINs. + PIN stands for Personal Identification Number, and is a secret code you need + to present to the card before being allowed to perform certain operations, + such as using one of the stored RSA keys to sign a document, or modifying + the card itself. +

+ Usually, PINs are a sequence of decimal digits, but some cards will accept + arbitrary ASCII characters. Be aware however that using characters other + than digits will make the card unusable with PIN pad readers, because those + usually have keys for entering digits only. +

+ The security officer (SO) PIN is special; it is used to protect meta data + information on the card, such as the PKCS #15 structure itself. Setting + the SO PIN is optional, because the worst that can usually happen is that + someone finding your card can mess it up. To extract any of your secret + keys stored on the card, an attacker will still need your user PIN, at + least for the default OpenSC profiles. However, it is possible to create + card profiles that will allow the security officer to override user PINs. +

+ For each PIN, you can specify a PUK (also called unblock PIN). + The PUK can be used to overwrite or unlock a PIN if too many incorrect values + have been entered in a row. +

+ For some cards that use the PKCS#15 emulation, the attributes of private objects + are protected and cannot be parsed without authentication (usually with User PIN). + This authentication need to be done immediately after the card binding. + In such cases --verify-pin has to be used. +

Modes of operation

Initialization

This is the first step during card personalization, and will create the + basic files on the card. To create the initial PKCS #15 structure, invoke the + utility as +

+ pkcs15-init --create-pkcs15

+ You will then be asked for the security officer PIN and PUK. Simply + pressing return at the SO PIN prompt will skip installation of an SO PIN. +

+ If the card supports it, you should erase the contents of the card with + pkcs15-init --erase-card before creating the PKCS#15 structure. +

User PIN Installation

+ Before installing any user objects such as private keys, you need at least one + PIN to protect these objects. you can do this using +

+ pkcs15-init --store-pin --id " nn +

+ where nn is a PKCS #15 ID in hexadecimal notation. Common + values are 01, 02, etc. +

+ Entering the command above will ask you for the user's PIN and PUK. If you do + not wish to install an unblock PIN, simply press return at the PUK prompt. +

+ To set a label for this PIN object (which can be used by applications to display + a meaningful prompt to the user), use the --label command line option. +

Key generation

+ pkcs15-init lets you generate a new key and store it on the card. + You can do this using: +

+ pkcs15-init --generate-key " keyspec " --auth-id " nn +

+ where keyspec describes the algorithm and length of the + key to be created, such as rsa/512. This will create a 512 bit + RSA key. Currently, only RSA key generation is supported. Note that cards + usually support just a few different key lengths. Almost all cards will support + 512 and 1024 bit keys, some will support 768 or 2048 as well. +

+ nn is the ID of a user PIN installed previously, + e.g. 01. +

+ In addition to storing the private portion of the key on the card, + pkcs15-init will also store the the public portion of the + key as a PKCS #15 public key object. +

Private Key Upload

+ You can use a private key generated by other means and upload it to the card. + For instance, to upload a private key contained in a file named + okir.pem, which is in PEM format, you would use +

+ pkcs15-init --store-private-key okir.pem --id 45 --auth-id 01 +

+ In addition to storing the private portion of the key on the card, + pkcs15-init will also store the the public portion of the + key as a PKCS #15 public key object. +

+ Note that usage of --id option in the pkcs15-init + commands to generate or to import a new key is deprecated. + Better practice is to let the middleware to derive the identifier from the key material. + (SHA1(modulus) for RSA, SHA1(pub) for DSA, ...). + This allows easily set up relation between 'related' objects + (private/public keys and certificates). +

+ In addition to the PEM key file format, pkcs15-init also + supports DER encoded keys, and PKCS #12 files. The latter is the file format + used by Netscape Navigator (among others) when exporting certificates to + a file. A PKCS #12 file usually contains the X.509 certificate corresponding + to the private key. If that is the case, pkcs15-init will + store the certificate instead of the public key portion. +

Public Key Upload

+ You can also upload individual public keys to the card using the + --store-public-key option, which takes a filename as an + argument. This file is supposed to contain the public key. If you don't + specify a key file format using the --format option, + pkcs15-init will assume PEM format. The only other + supported public key file format is DER. +

+ Since the corresponding public keys are always uploaded automatically + when generating a new key, or when uploading a private key, you will + probably use this option only very rarely. +

Certificate Upload

+ You can upload certificates to the card using the + --store-certificate option, which takes a filename as + an argument. This file is supposed to contain the PEM encoded X.509 + certificate. +

Uploading PKCS #12 bags

+ Most browsers nowadays use PKCS #12 format files when you ask them to + export your key and certificate to a file. pkcs15-init + is capable of parsing these files, and storing their contents on the + card in a single operation. This works just like storing a private key, + except that you need to specify the file format: +

+ pkcs15-init --store-private-key okir.p12 --format pkcs12 --auth-id + 01 +

+ This will install the private key contained in the file okir.p12, + and protect it with the PIN referenced by authentication ID 01. + It will also store any X.509 certificates contained in the file, which is + usually the user certificate that goes with the key, as well as the CA certificate. +

Secret Key Upload

+ You can use a secret key generated by other means and upload it to the card. + For instance, to upload an AES-secret key generated by the system random generator + you would use +

+ pkcs15-init --store-secret-key /dev/urandom --secret-key-algorithm aes/256 --auth-id 01 +

+ By default a random ID is generated for the secret key. You may specify an ID + with the --id if needed. +

Options

+

+ --version, +

Print the OpenSC package release version.

+ --card-profile name, + -c name +

+ Tells pkcs15-init to load the specified card + profile option. You will rarely need this option. +

+ --create-pkcs15, + -C +

+ This tells pkcs15-init to create a PKCS #15 + structure on the card, and initialize any PINs. +

+ --serial SERIAL +

+ Specify the serial number of the card. +

+ --erase-card, + -E +

+ This will erase the card prior to creating the PKCS #15 structure, + if the card supports it. If the card does not support erasing, + pkcs15-init will fail. +

+ --erase-application AID +

+ This will erase the application with the application identifier + AID. +

+ --generate-key keyspec, + -G keyspec +

+ Tells the card to generate new key and store it on the card. + keyspec consists of an algorithm name + (currently, the only supported name is RSA), + optionally followed by a slash and the length of the key in bits. + It is a good idea to specify the key ID along with this command, + using the id option, otherwise an intrinsic ID + will be calculated from the key material. Look the description of + the 'pkcs15-id-style' attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. + For the multi-application cards the target PKCS#15 application can be + specified by the hexadecimal AID value of the aid option. +

+ --options-file filename +

+ Tells pkcs15-init to read additional options + from filename. The file is supposed to + contain one long option per line, without the leading dashes, + for instance: +

+pin		1234
+puk		87654321
+							

+

+ You can specify --options-file several times. +

+ --pin, + --puk + --so-pin, + --so-puk, +

+ These options can be used to specify PIN/PUK values + on the command line. If set to + env:VARIABLE, the value + of the environment variable + VARIABLE is used. Note + that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should use + these options only on a secured system, or in an + options file specified with + --options-file. +

+ --no-so-pin, +

+ Do not install a SO PIN, and do not prompt for it. +

+ --profile name, + -p name +

+ Tells pkcs15-init to load the specified general + profile. Currently, the only application profile defined is + pkcs15, but you can write your own profiles and + specify them using this option. +

+ The profile name can be combined with one or more profile + options, which slightly modify the profile's behavior. + For instance, the default OpenSC profile supports the + openpin option, which installs a single PIN during + card initialization. This PIN is then used both as the SO PIN as + well as the user PIN for all keys stored on the card. +

+ Profile name and options are separated by a + + character, as in pkcs15+onepin. +

+ --secret-key-algorithm keyspec, +

+ keyspec describes the algorithm and length of the + key to be created or downloaded, such as aes/256. + This will create a 256 bit AES key. +

+ --store-certificate filename, + -X filename +

+ Tells pkcs15-init to store the certificate given + in filename on the card, creating a certificate + object with the ID specified via the --id option. + Without supplied ID an intrinsic ID will be calculated from the + certificate's public key. Look the description of the 'pkcs15-id-style' + attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. + The file is assumed to contain the PEM encoded certificate. + For the multi-application cards the target application can be specified + by the hexadecimal AID value of the aid option. +

+ --store-pin, + -P +

+ Store a new PIN/PUK on the card. +

+ --store-public-key filename +

+ Tells pkcs15-init to download the specified + public key to the card and create a public key object with the + key ID specified via the --id. By default, + the file is assumed to contain the key in PEM format. Alternative + formats can be specified using --format. +

+ --store-private-key filename, + -S filename +

+ Tells pkcs15-init to download the specified + private key to the card. This command will also create a public + key object containing the public key portion. By default, the + file is assumed to contain the key in PEM format. Alternative + formats can be specified using --format. + It is a good idea to specify the key ID along with this command, + using the --id option, otherwise an intrinsic ID + will be calculated from the key material. Look the description of + the 'pkcs15-id-style' attribute in the 'pkcs15.profile' for the details + about the algorithm used to calculate intrinsic ID. + For the multi-application cards the target PKCS#15 application can be + specified by the hexadecimal AID value of the aid option. +

+ --store-secret-key filename, +

+ Tells pkcs15-init to download the specified + secret key to the card. The file is assumed to contain the raw key. + They key type should be specified with --secret-key-algorithm + option. +

+ You may additionally specify the key ID along with this command, + using the --id option, otherwise a random ID is generated. + For the multi-application cards the target PKCS#15 application can be + specified by the hexadecimal AID value of the aid option. +

+ --store-data filename, + -W filename +

+ Store a data object. +

+ --update-certificate filename, + -U filename +

+ Tells pkcs15-init to update the certificate + object with the ID specified via the --id option + with the certificate in filename. + The file is assumed to contain a PEM encoded certificate. +

Pay extra attention when updating mail decryption certificates, as + missing certificates can render e-mail messages unreadable! +

+ --delete-objects arg, + -D arg +

+ Tells pkcs15-init to delete the + specified object. arg + is comma-separated list containing any of + privkey, pubkey, + secrkey, cert, + chain or data. +

+ When data is specified, an + ---application-id must also be + specified, in the other cases an + --id must also be specified +

+ When chain is specified, the + certificate chain starting with the cert with + specified ID will be deleted, until there's a CA + certificate that certifies another cert on the card +

+ --change-attributes arg, + -A arg +

+ Tells pkcs15-init to change the + specified attribute. arg + is either privkey, + pubkey, secrkey, + cert or data. + You also have to specify the --id + of the object. + For now, you can only change the --label, e.g: +

+								pkcs15-init -A cert --id 45 -a 1 --label Jim
+							

+

+ --use-default-transport-keys, + -T +

+ Tells pkcs15-init to not ask for the transport + keys and use default keys, as known by the card driver. +

+ --sanity-check, + -T +

+ Tells pkcs15-init to perform a + card specific sanity check and possibly update + procedure. +

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --verbose, + -v +

+ Causes pkcs15-init to be more verbose. Specify this + flag several times to enable debug output in the OpenSC library. +

+ --wait, + -w +

Causes pkcs15-init to + wait for a card insertion.

+ --use-pinpad +

Do not prompt the user; if no PINs supplied, pinpad will be used.

+ --puk-id ID +

+ Specify ID of PUK to use/create +

+ --puk-label LABEL +

+ Specify label of PUK +

+ --public-key-label LABEL +

+ Specify public key label (use with --generate-key) +

+ --cert-label LABEL +

+ Specify user cert label (use with --store-private-key) +

+ --application-name arg +

+ Specify application name of data object (use with --store-data-object) +

+ --aid AID +

+ Specify AID of the on-card PKCS#15 application to be binded to (in hexadecimal form) +

+ --output-file filename + -o filename, +

+ Output public portion of generated key to file +

+ --passphrase PASSPHRASE +

+ Specify passphrase for unlocking secret key +

+ --authority +

+ Mark certificate as a CA certificate +

+ --key-usage arg + -u arg, +

+ Specifies the X.509 key usage. + arg is comma-separated + list containing any of + digitalSignature, + nonRepudiation, + keyEncipherment, + dataEncipherment, + keyAgreement, + keyCertSign, + cRLSign. Abbreviated names are + allowed if unique (e.g. + dataEnc). +

+ The alias sign is equivalent to + digitalSignature,keyCertSign,cRLSign +

+ The alias decrypt is equivalent to + keyEncipherment,dataEncipherment +

+ --finalize + -F, +

+ Finish initialization phase of the smart card +

+ --update-last-update +

+ Update 'lastUpdate' attribute of tokenInfo +

+ --ignore-ca-certificates +

+ When storing PKCS#12 ignore CA certificates +

+ --update-existing +

+ Store or update existing certificate +

+ --extractable +

+ Private key stored as an extractable key +

+ --insecure +

+ Insecure mode: do not require a PIN for private key +

+ --md-container-guid GUID +

+ For a new key specify GUID for a MD container +

+ --help + -h, +

+ Display help message +

+

See also

+ pkcs15-profile(5) +

Authors

pkcs15-init was written by + Olaf Kirch .


Name

pkcs15-tool — utility for manipulating PKCS #15 data structures + on smart cards and similar security tokens

Synopsis

pkcs15-tool [OPTIONS]

Description

+ The pkcs15-tool utility is used to manipulate + the PKCS #15 data structures on smart cards and similar security + tokens. Users can list and read PINs, keys and certificates stored + on the token. User PIN authentication is performed for those + operations that require it. +

Options

+

+ --version, +

Print the OpenSC package release version.

+ --aid aid +

Specify in a hexadecimal form the AID of the on-card PKCS#15 + application to bind to.

+ --auth-id pin, + -a pin +

Specifies the auth id of the PIN to use for the + operation. This is useful with the --change-pin operation.

+ --change-pin +

Changes a PIN or PUK stored on the token. User authentication + is required for this operation.

+ --dump, + -D +

List all card objects.

+ --list-info +

List card objects.

+ --list-applications +

List the on-card PKCS#15 applications.

+ --list-certificates, + -c +

List all certificates stored on the token.

+ --list-data-objects, + -C +

List all data objects stored on the token. + For some cards the PKCS#15 attributes of the private data objects are + protected for reading and need the authentication with the User PIN. + In such a case the --verify-pin option has to be used. +

+ --list-keys, + -k +

List all private keys stored on the token. General + information about each private key is listed (eg. key name, id and + algorithm). Actual private key values are not displayed. + For some cards the PKCS#15 attributes of the private keys are protected for reading + and need the authentication with the User PIN. + In such a case the --verify-pin option has to be used.

+ --list-secret-keys +

List all secret (symmetric) keys stored on the token. General + information about each secret key is listed (eg. key name, id and + algorithm). Actual secret key values are not displayed. + For some cards the PKCS#15 attributes of the private keys are protected for reading + and need the authentication with the User PIN. + In such a case the --verify-pin option has to be used.

+ --list-pins +

List all PINs stored on the token. General information + about each PIN is listed (eg. PIN name). Actual PIN values are not shown.

+ --list-public-keys +

List all public keys stored on the token, including + key name, id, algorithm and length information.

+ --short + -s +

Output lists in compact format.

+ --no-cache +

Disables token data caching.

+ --clear-cache +

Removes the user's cache directory. On + Windows, this option additionally removes the system's + caching directory (requires administrator + privileges).

+ --clear-cache +

Removes the user's cache directory. On + Windows, this option additionally removes the system's + caching directory (requires administrator + privileges).

+ --output filename, + -o filename +

Specifies where key output should be written. + If filename already exists, it will be overwritten. + If this option is not given, keys will be printed to standard output.

+ --raw +

Changes how --read-data-object prints the content + to standard output. By default, when --raw is not given, it will + print the content in hex notation. If --raw is set, it will print + the binary data directly. This does not affect the output that is written to the + file specified by the --output option. Data written to a file will + always be in raw binary.

+ --read-certificate cert, + -r cert +

Reads the certificate with the given id.

+ --read-data-object cert, + -R data +

Reads data object with OID, applicationName or label. + The content is printed to standard output in hex notation, unless + the --raw option is given. + If an output file is given with the --output option, + the content is additionally written to the file. + Output to the file is always written in raw binary mode, the + --raw only affects standard output behavior.

+ --read-public-key id +

Reads the public key with id id, + allowing the user to extract and store or use the public key.

+ --read-ssh-key id +

Reads the public key with id id, + writing the output in format suitable for + $HOME/.ssh/authorized_keys.

The key label, if any will be shown in the 'Comment' field.

+ --rfc4716 +

When used in conjunction with option --read-ssh-key the + output format of the public key follows rfc4716.

The default output format is a single line (openssh).

+ --test-update, + -T, +

Test if the card needs a security update

+ --update, + -U, +

Update the card with a security update

+ --reader num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --unblock-pin, + -u +

Unblocks a PIN stored on the token. Knowledge of the + Pin Unblock Key (PUK) is required for this operation.

+ --verbose, + -v +

Causes pkcs15-tool to be more + verbose. Specify this flag several times to enable debug output + in the OpenSC library.

+ --pin PIN +

Specify PIN

+ --puk PUK +

Specify Unblock PIN

+ --new-pin PIN +

Specify New PIN (when changing or unblocking)

+ --verify-pin +

Verify PIN after card binding and before issuing any command + (without 'auth-id' the first non-SO, non-Unblock PIN will be verified)

+ --test-session-pin +

Equivalent to --verify-pin + with additional session PIN generation

+ --wait, + -w +

Causes pkcs15-tool to + wait for a card insertion.

+ --use-pinpad +

Do not prompt the user; if no PINs supplied, pinpad will be used.

+

See also

+ pkcs15-init(1), + pkcs15-crypt(1) +

Authors

pkcs15-tool was written by + Juha Yrjl .


Name

sc-hsm-tool — smart card utility for SmartCard-HSM

Synopsis

sc-hsm-tool [OPTIONS]

+ The sc-hsm-tool utility can be used from the command line to perform + extended maintenance tasks not available via PKCS#11 or other tools in the OpenSC package. + It can be used to query the status of a SmartCard-HSM, initialize a device, generate and import + Device Key Encryption Key (DKEK) shares and to wrap and unwrap keys. +

Options

+

+ --initialize, + -X +

Initialize token, removing all existing keys, certificates and files.

Use --so-pin to define SO-PIN for first initialization or to verify in subsequent + initializations.

Use --pin to define the initial user pin value.

Use --pin-retry to define the maximum number of wrong user PIN presentations.

Use with --dkek-shares to enable key wrap / unwrap.

Use with --label to define a token label

+ --create-dkek-share filename, + -C filename +

Create a DKEK share encrypted under a password and save it to the file + given as parameter.

Use --password to provide a password for encryption rather than prompting for one.

Use --pwd-shares-threshold and --pwd-shares-total to randomly generate a password and split is using a (t, n) threshold scheme.

+ --import-dkek-share filename, + -I filename +

Prompt for user password, read and decrypt DKEK share and import into SmartCard-HSM.

Use --password to provide a password for decryption rather than prompting for one.

Use --pwd-shares-total to specify the number of shares that should be entered to reconstruct the password.

+ --wrap-key filename, + -W filename +

Wrap the key referenced in --key-reference and save with it together with the key description + and certificate to the given file.

Use --pin to provide the user PIN on the command line.

+ --unwrap-key filename, + -U filename +

Read wrapped key, description and certificate from file and import into SmartCard-HSM + under the key reference given in --key-reference.

Determine the key reference using the output of pkcs15-tool -D.

Use --pin to provide a user PIN on the command line.

Use --force to remove any key, key description or certificate in the way.

+ --dkek-shares number-of-shares, + -s number-of-shares +

Define the number of DKEK shares to use for recreating the DKEK.

This is an optional parameter. Using --initialize without + --dkek-shares will disable the DKEK completely.

Using --dkek-shares with 0 shares requests the SmartCard-HSM to + generate a random DKEK. Keys wrapped with this DKEK can only be unwrapped in the + same SmartCard-HSM.

After using --initialize with one or more DKEK shares, the + SmartCard-HSM will remain in the initialized state until all DKEK shares have + been imported. During this phase no new keys can be generated or imported.

+ --so-pin value +

Define SO-PIN for initialization. If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used.

+ --pin value +

Define user PIN for initialization, wrap or + unwrap operation. If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used.

+ --pin-retry value +

Define number of PIN retries for user PIN during initialization. Default is 3.

+ --password value +

Define password for DKEK share encryption. If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used.

+ --pwd-shares-threshold value +

Define threshold for number of password shares required for reconstruction.

+ --pwd-shares-total value +

Define number of password shares.

+ --force +

Force removal of existing key, description and certificate.

+ --label label, + -l label +

Define the token label to be used in --initialize.

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --wait, + -w +

Wait for a card to be inserted

+ --verbose, + -v +

Causes sc-hsm-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc + library.

+

Examples

Create a DKEK share:

sc-hsm-tool --create-dkek-share dkek-share-1.pbe

Create a DKEK share with random password split up using a (3, 5) threshold scheme:

sc-hsm-tool --create-dkek-share dkek-share-1.pbe --pwd-shares-threshold 3 --pwd-shares-total 5

Initialize SmartCard-HSM to use a single DKEK share:

sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1 --label mytoken

Import DKEK share:

sc-hsm-tool --import-dkek-share dkek-share-1.pbe

Import DKEK share using a password split up using a (3, 5) threshold scheme for encryption:

sc-hsm-tool --import-dkek-share dkek-share-1.pbe --pwd-shares-total 3

Wrap referenced key, description and certificate:

sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219

Unwrap key into same or in different SmartCard-HSM with the same DKEK:

sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force

See also

+ opensc-tool(1) +

Authors

sc-hsm-tool was written by + Andreas Schwier .


Name

westcos-tool — utility for manipulating data structures + on westcos smart cards

Synopsis

westcos-tool [OPTIONS]

Description

+ The westcos-tool utility is used to manipulate + the westcos data structures on 2 Ko smart cards / tokens. Users can create PINs, + keys and certificates stored on the card / token. User PIN authentication is + performed for those operations that require it. +

Options

+

+ --change-pin, + -n +

Changes a PIN stored on the card. + User authentication is required for this operation.

+ --certificate file, + -t file +

Write certificate file file + in PEM format to the card. + User authentication is required for this operation.

+ --finalize, + -f +

Finalize the card. Once finalized the default key is + invalidated, so PIN and PUK cannot be changed anymore without user + authentication.

Warning, un-finalized cards are insecure because the PIN can be + changed without user authentication (knowledge of default key + is enough).

+ --generate-key, + -g +

Generate a private key on the card. The card must not have + been finalized and a PIN must be installed (i.e. the file for the PIN must + have been created, see option -i). + By default the key length is 1536 bits. User authentication is required for + this operation.

+ --help, + -h +

Print help message on screen.

+ --install-pin, + -i +

Install PIN file in on the card. + You must provide a PIN value with -x.

+ --key-length length, + -l length +

Change the length of private key. + Use with -g.

+ --overwrite-key, + -o +

Overwrite the key if there is already a key on the card.

+ --pin-value value, + -x value +

Set value of PIN. If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used.

+ --puk-value value, + -y value +

set value of PUK (or value of new PIN for change PIN + command see -n). If set to + env:VARIABLE, the value of + the environment variable + VARIABLE is used.

+ --read-file filename, + -j filename +

Read the file filename from the card. + The file is written on disk with name filename. + User authentication is required for this operation.

+ --reader num, + -r num +

+ Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. +

+ --unblock-pin, + -u +

Unblocks a PIN stored on the card. Knowledge of the + PIN Unblock Key (PUK) is required for this operation.

+ --verbose + -v +

Causes westcos-tool to be more + verbose. Specify this flag several times to enable debug output + in the OpenSC library.

+ --wait, + -w +

Wait for a card to be inserted.

+ --write-file filename, + -k filename +

Put the file with name filename + from disk to card. + On the card the file is written in filename. + User authentication is required for this operation.

+

Authors

westcos-tool was written by + Francois Leblanc .

diff -Nru opensc-0.17.0/doc/tools/tools.xml opensc-0.19.0/doc/tools/tools.xml --- opensc-0.17.0/doc/tools/tools.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/tools.xml 2018-09-13 11:47:21.000000000 +0000 @@ -1,33 +1,29 @@ +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> - OpenSC - - - OpenSC tools - - - - - - - - - - - - - - - - + OpenSC Manual Pages: Section 1 - - - OpenSC file formats - - - + + + + + + + + + + + + + + + + + + + + + diff -Nru opensc-0.17.0/doc/tools/westcos-tool.1.xml opensc-0.19.0/doc/tools/westcos-tool.1.xml --- opensc-0.17.0/doc/tools/westcos-tool.1.xml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/doc/tools/westcos-tool.1.xml 2018-09-13 11:47:21.000000000 +0000 @@ -62,8 +62,8 @@ Finalize the card. Once finalized the default key is invalidated, so PIN and PUK cannot be changed anymore without user authentication. - Warning, un-finalized are insecure because PIN can be changed - without user authentication (knowledge of default key + Warning, un-finalized cards are insecure because the PIN can be + changed without user authentication (knowledge of default key is enough).
@@ -73,8 +73,8 @@ Generate a private key on the card. The card must not have - been finalized and a PIN must be installed (ie. the file for ithe PIN must - havei been created, see option ). + been finalized and a PIN must be installed (i.e. the file for the PIN must + have been created, see option ). By default the key length is 1536 bits. User authentication is required for this operation.
@@ -138,11 +138,11 @@ - path, - path + filename, + filename - Read the file path from the card. - The file is written on disk with name path. + Read the file filename from the card. + The file is written on disk with name filename. User authentication is required for this operation. @@ -151,9 +151,14 @@ num, num - - Use the given reader. The default is the first reader with a card. - + + + Specify the reader to use. By default, the first + reader with a present card is used. If + num is an ATR, the + reader with a matching card will be chosen. + + @@ -167,6 +172,7 @@ + Causes westcos-tool to be more @@ -184,12 +190,12 @@ - path, - path + filename, + filename - Put the file with name path + Put the file with name filename from disk to card. - On the card the file is written in path. + On the card the file is written in filename. User authentication is required for this operation. diff -Nru opensc-0.17.0/etc/Makefile.am opensc-0.19.0/etc/Makefile.am --- opensc-0.17.0/etc/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/etc/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,20 +1,20 @@ CV_CERTS = DESRCACC100001 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -DISTCLEANFILES = opensc.conf +DISTCLEANFILES = opensc.conf.example EXTRA_DIST = $(CV_CERTS) Makefile.mak SUFFIXES = .in -dist_noinst_DATA = opensc.conf.in -nodist_noinst_DATA = opensc.conf +dist_noinst_DATA = opensc.conf opensc.conf.example.in +nodist_noinst_DATA = opensc.conf.example # Make sure we build this every time # as there is no dependency for this. # Can be removed if MSVC is not requried. force: -opensc.conf: opensc.conf.in force +opensc.conf.example: opensc.conf.example.in force .in: @sed \ @@ -30,16 +30,19 @@ -e 's|@PROFILE_DIR_DEFAULT[@]|$(PROFILE_DIR_DEFAULT)|g' \ < $< > $@ -install-exec-hook: opensc.conf +install-exec-hook: opensc.conf.example $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" if [ -f "$(DESTDIR)$(sysconfdir)/opensc.conf" ]; then \ - $(INSTALL_DATA) opensc.conf "$(DESTDIR)$(sysconfdir)/opensc.conf.new"; \ + $(INSTALL_DATA) $(srcdir)/opensc.conf "$(DESTDIR)$(sysconfdir)/opensc.conf.new"; \ else \ - $(INSTALL_DATA) opensc.conf "$(DESTDIR)$(sysconfdir)/opensc.conf"; \ + $(INSTALL_DATA) $(srcdir)/opensc.conf "$(DESTDIR)$(sysconfdir)/opensc.conf"; \ fi + $(MKDIR_P) "$(DESTDIR)$(docdir)" + $(INSTALL_DATA) opensc.conf.example "$(DESTDIR)$(docdir)/opensc.conf"; -uninstall-hook: opensc.conf +uninstall-hook: opensc.conf.example rm -f "$(DESTDIR)$(sysconfdir)/opensc.conf.new" "$(DESTDIR)$(sysconfdir)/opensc.conf" + rm -f "$(DESTDIR)$(docdir)/opensc.conf" if ENABLE_OPENPACE install-data-local: diff -Nru opensc-0.17.0/etc/opensc.conf opensc-0.19.0/etc/opensc.conf --- opensc-0.17.0/etc/opensc.conf 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/etc/opensc.conf 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,7 @@ +app default { + # debug = 3; + # debug_file = opensc-debug.txt; + framework pkcs15 { + # use_file_caching = true; + } +} diff -Nru opensc-0.17.0/etc/opensc.conf.example.in opensc-0.19.0/etc/opensc.conf.example.in --- opensc-0.17.0/etc/opensc.conf.example.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/etc/opensc.conf.example.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1111 @@ +# Configuration file for OpenSC +# Example configuration file + +# NOTE: All key-value pairs must be terminated by a semicolon. + +# Default values for any application +# These can be overridden by an application +# specific configuration block. +app default { + # Amount of debug info to print + # + # A greater value means more debug info. + # Default: 0 + # + #debug = 3; + + # The file to which debug output will be written + # + # Special values 'stdout' and 'stderr' are recognized. + # Default: stderr + # + # debug_file = @DEBUG_FILE@ + + # PKCS#15 initialization / personalization + # profiles directory for pkcs15-init. + # Default: @PROFILE_DIR_DEFAULT@ + # + # profile_dir = @PROFILE_DIR@; + + # Disable pop-ups of built-in GUI + # + # Default: false + # disable_popups = true; + + # Enable default card driver + # Default card driver is explicitly enabled for the 'opensc-explorer' and 'opensc-tool'. + # + # Default: false + # enable_default_driver = true; + + # List of readers to ignore + # If any of the strings listed below is matched in a reader name (case + # sensitive, partial matching possible), the reader is ignored by OpenSC. + # Use `opensc-tool --list-readers` to see all currently connected readers. + # + # Default: empty + # ignored_readers = "CardMan 1021", "SPR 532"; + + # CT-API module configuration. + reader_driver ctapi { + # module @LIBDIR@@LIB_PRE@towitoko@DYN_LIB_EXT@ { + # CT-API ports: + # 0..3 COM1..4 + # 4 Printer + # 5 Modem + # 6..7 LPT1..2 + # ports = 0; + # } + } + + # The following section shows definitions for PC/SC readers. + reader_driver pcsc { + # Limit command and response sizes. Some Readers don't propagate their + # transceive capabilities correctly. max_send_size and max_recv_size + # allow setting the limits manually, for example to enable extended + # length capabilities. + # Default: max_send_size = 255, max_recv_size = 256; + # max_send_size = 65535; + # max_recv_size = 65536; + # + # Connect to reader in exclusive mode? + # Default: false + # connect_exclusive = true; + # + # What to do when disconnecting from a card (SCardDisconnect) + # Valid values: leave, reset, unpower. + # Default: leave + # disconnect_action = reset; + # + # What to do at the end of a transaction (SCardEndTransaction) + # Valid values: leave, reset, unpower. + # Default: leave + # transaction_end_action = reset; + # + # What to do when reconnection to a card (SCardReconnect) + # Valid values: leave, reset, unpower. + # Note that this affects only the internal reconnect (after a SCARD_W_RESET_CARD). + # A forced reset via sc_reset() always does a full powerup. + # Default: leave + # reconnect_action = reset; + # + # Enable pinpad if detected (PC/SC v2.0.2 Part 10) + # Default: true + # enable_pinpad = false; + # + # Some pinpad readers can only handle one exact length of the PIN. + # fixed_pinlength sets this value so that OpenSC expands the padding to + # this length. + # Default: 0 (i.e. not fixed) + # fixed_pinlength = 6; + # + # Detect reader capabilities with escape commands (wrapped APDUs with + # CLA=0xFF as defined by PC/SC pt. 3 and BSI TR-03119, e.g. for getting + # the UID, escaped PIN commands and the reader's firmware version) + # Default: false + # enable_escape = true; + # + # Use specific pcsc provider. + # Default: @DEFAULT_PCSC_PROVIDER@ + # provider_library = @DEFAULT_PCSC_PROVIDER@ + } + + # Options for OpenCT support + reader_driver openct { + # Virtual readers to allocate. + # Default: 2 + # readers = 5; + # + # Limit command and response sizes. + # Default: n/a + # max_send_size = 255; + # max_recv_size = 256; + } + + # Options for CryptoTokenKit support + reader_driver cryptotokenkit { + # Limit command and response sizes. Some Readers don't propagate their + # transceive capabilities correctly. max_send_size and max_recv_size + # allow setting the limits manually, for example to enable extended + # length capabilities. + # Default: autodetect + # max_send_size = 65535; + # max_recv_size = 65536; + } + + # Whitelist of card drivers to load at start-up + # + # The supported internal card driver names can be retrieved + # from the output of: + # $ opensc-tool --list-drivers + # + # A special value of 'old' will load all + # statically linked drivers that may be removed in the future. + # + # A special value of 'internal' will load all + # statically linked drivers. If an unknown (i.e. not + # internal) driver is supplied, a separate configuration + # configuration block has to be written for the driver. + # Default: internal + # NOTE: When "internal" keyword is used, must be last entry + # + #card_drivers = old, internal; + + # Card driver configuration blocks. + + # For card drivers loaded from an external shared library/DLL, + # you need to specify the path name of the module + # + # card_driver customcos { + # The location of the driver library + # module = @LIBDIR@@LIB_PRE@card_customcos@DYN_LIB_EXT@; + # } + + card_driver npa { + # German ID card requires the CAN to be verified before QES PIN. This, + # however, is not part of the PKCS#15 profile of the card. So for + # verifying the QES PIN we actually need both. The CAN may be given + # here. If the CAN is not given here, it will be prompted on the + # command line or on the reader (depending on the reader's + # capabilities). + # + #can = 222222; + + # QES is only possible with a Comfort Reader (CAT-K), which holds a + # cryptographic key to authenticate itself as signature terminal (ST). + # We usually will use the reader's capability to sign the data. + # However, during developement you may specify soft certificates and + # keys for a ST below. + # The following example EAC PKI can be found in vicc's example data: + # https://github.com/frankmorgner/vsmartcard/tree/master/virtualsmartcard/npa-example-data + # + #st_dv_certificate = ZZSTDVCA00001.cvcert; + #st_certificate = ZZSTTERM00001.cvcert; + #st_key = ZZSTTERM00001.pkcs8; + } + + # Configuration block for DNIe + # + # Card DNIe has an option to show an extra warning before + # issuing a signature. + + card_driver dnie { + # Disable / enable warning message when performing a + # signature operation with the DNIe. + # Only used if compiled with --enable-dnie-ui + # user_consent_enabled = yes; + + # Specify the pinentry application to use if warning + # is configured to be displayed using pinentry. + # Default: /usr/bin/pinentry + # Only used if compiled with --enable-dnie-ui + # user_consent_app = "/usr/bin/pinentry"; + } + + # In addition to the built-in list of known cards in the + # card driver, you can configure a new card for the driver + # using the card_atr block. The goal is to centralize + # everything related to a certain card to card_atr. + # + # The supported internal card driver names can be retrieved + # from the output of: + # $ opensc-tool --list-drivers + + # Generic format: card_atr + + # New card entry for the flex card driver + # card_atr 3b:f0:0d:ca:fe { + # All parameters for the context are + # optional unless specified otherwise. + + # Context: global, card driver + # + # ATR mask value + # + # The mask is logically AND'd with an + # card ATR prior to comparison with the + # ATR reference value above. Using mask + # allows identifying and configuring + # multiple ATRs as the same card model. + # atrmask = "ff:ff:ff:ff:ff"; + + # Context: card driver + # + # Specify used card driver (REQUIRED). + # + # When enabled, overrides all possible + # settings from the card drivers built-in + # card configuration list. + # driver = "flex"; + + # Set card name for card drivers that allows it. + # name = "My CryptoFlex card"; + + # Card type as an integer value. + # + # Depending on card driver, this allows + # tuning the behaviour of the card driver + # for your card. + # type = "2002"; + + # Card flags as an hex value. + # Multiple values are OR'd together. + # + # Depending on card driver, this allows + # fine-tuning the capabilities in + # the card driver for your card. + # + # Optionally, some known parameters + # can be specified as strings: + # + # rng - On-board random number source + # keep_alive - Request the card driver to send a "keep alive" command before each transaction to make sure that the required applet is still selected. + # + # flags = "rng", "keep_alive", "0x80000000"; + + # + # Context: PKCS#15 emulation layer + # + # When using PKCS#15 emulation, force + # the emulation driver for specific cards. + # + # Required for external drivers, but can + # be used with built-in drivers, too. + # pkcs15emu = "custom"; + + # + # Context: reader driver + # + # Force protocol selection for specific cards. + # Known parameters: t0, t1, raw + # force_protocol = "t0"; + + # Context: minidriver + # + # md_read_only: Mark card as read/only card in Minidriver/BaseCSP interface (Default: false) + # md_supports_X509_enrollment: Indicate X509 enrollment support at Minidriver/BaseCSP interface (Default: false) + # md_guid_as_id: Use the GUID generated for the key as id in the PKCS#15 structure (Default: false, i.e. auto generated) + # md_guid_as_label: Use the GUID generated for the key as label in the PKCS#15 structure (Default: false, i.e. no label set) + # md_supports_container_key_gen: Card allows generating key pairs on the card (Default: false) + # md_supports_container_key_import: Card allows importing private keys (Default: false) + # + # Window title of the PIN pad dialog + # Default: "Windows Security" + # md_pinpad_dlg_title = "Title"; + # + # Filename of the icon for the PIN pad dialog; use "" for no icon + # Default: Built-in smart card icon + # md_pinpad_dlg_icon = ""; + # + # Main instruction of the PIN pad dialog + # Default: "OpenSC Smart Card Provider" + # md_pinpad_dlg_main = "Main"; + # + # Content of the PIN pad dialog for role "user" + # Default: "Please verify your fingerprint or PIN on the card." + # md_pinpad_dlg_content_user = "Content User"; + # + # Content of the PIN pad dialog for role "user+signature" + # Default: "Please verify your fingerprint or PIN for the digital signature PIN on the card." + # md_pinpad_dlg_content_user_sign = "Content User+Sign"; + # + # Content of the PIN pad dialog for role "admin" + # Default: "Please enter your PIN to unblock the user PIN on the PINPAD." + # md_pinpad_dlg_content_admin = "Content Admin"; + # + # Expanded information of the PIN pad dialog + # Default: "This window will be closed automatically after the PIN has been submitted on the PINPAD (timeout typically after 30 seconds)." + # md_pinpad_dlg_expanded = "Expanded Information"; + # + # Allow the user to cancel the PIN pad dialog by not immediately requesting the PIN on the PIN pad + # Default: false + # md_pinpad_dlg_enable_cancel = true; + # + # Content of the verification of the PIN pad dialog + # Default: "Automatically request PIN immediately on PIN-Pad" + # md_pinpad_dlg_verification = "Verification"; + # + # Time in seconds for the progress bar of the PIN pad dialog to tick. "0" removes the progress bar. + # Default: 30 + # md_pinpad_dlg_timeout = 0; + + # Notification title and text when card was inserted + # Default: "Smart card detected" + # notify_card_inserted = "inserted title"; + # Default: ATR of the card + # notify_card_inserted_text = "inserted text"; + # + # Notification title and text when card was removed + # Default: "Smart card removed" + # notify_card_removed = "card removed"; + # Default: Name of smart card reader + # notify_card_removed_text = "removed text"; + # + # Notification title and text when PIN was verified + # Default: "PIN verified" + # notify_pin_good = "good PIN"; + # Default: "Smart card is unlocked" + # notify_pin_good_text = "good text"; + # + # Notification title and text when PIN was wrong + # Default: "PIN not verified" + # notify_pin_bad = "bad PIN"; + # Default: "Smart card is locked" + # notify_pin_bad_text = "bad text"; + # } + + # Yubikey is known to have the PIV applet and the OpenPGP applet. OpenSC + # can handle both to access keys and certificates, but only one at a time. + card_atr 3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4 { + name = "Yubikey 4"; + # Select the PKI applet to use ("PIV-II" or "openpgp") + driver = "PIV-II"; + # Recover from other applications accessing a different applet + flags = "keep_alive"; + } + card_atr 3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1 { + name = "Yubikey Neo"; + # Select the PKI applet to use ("PIV-II" or "openpgp") + driver = "PIV-II"; + # Recover from other applications accessing a different applet + flags = "keep_alive"; + } + card_atr 3b:8c:80:01:59:75:62:69:6b:65:79:4e:45:4f:72:33:58 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00"; + name = "Yubikey Neo"; + # Select the PKI applet to use ("PIV-II" or "openpgp") + driver = "PIV-II"; + # Recover from other applications accessing a different applet + flags = "keep_alive"; + } + + # Oberthur's AuthentIC v3.2.2 + card_atr 3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:00:70:0A:90:00:8B { + type = 11100; + driver = "authentic"; + name = "AuthentIC v3.1"; + + # Name of SM configuration sub-section + # secure_messaging = local_authentic; + } + + # IAS/ECC cards + card_atr 3B:7F:96:00:00:00:31:B9:64:40:70:14:10:73:94:01:80:82:90:00 { + type = 25001; + driver = "iasecc"; + name = "Gemalto MultiApp IAS/ECC v1.0.1"; + secure_messaging = local_gemalto_iam; + # secure_messaging = local_adele; + md_read_only = false; + md_supports_X509_enrollment = true; + } + card_atr 3B:7F:96:00:00:00:31:B8:64:40:70:14:10:73:94:01:80:82:90:00 { + type = 25001; + driver = "iasecc"; + name = "Gemalto MultiApp IAS/ECC v1.0.1"; + secure_messaging = local_gemalto_iam; + md_read_only = false; + md_supports_X509_enrollment = true; + } + #card_atr 3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:08:00:07:90:00:FE { + # type = 25002; + # driver = "iasecc"; + # name = "Oberthur IAS/ECC v1.0.1"; + # # No 'admin' application for this card -- no secure messaging + #} + #card_atr 3B:7F:18:00:00:00:31:B8:64:50:23:EC:C1:73:94:01:80:82:90:00 { + # type = 25003; + # driver = "iasecc"; + # name = "Morpho YpsID S3 IAS/ECC"; + # # secure_messaging = local_morpho_YpsID_S3; + #} + #card_atr 3B:DF:96:00:80:31:FE:45:00:31:B8:64:04:1F:EC:C1:73:94:01:80:82:90:00:EC { + # type = 25005; + # driver = "iasecc"; + # name = "Morpho MI IAS/ECC v1.0.1"; + # md_read_only = false; + # md_supports_X509_enrollment = true; + # secure_messaging = local_morpho_mi; + #} + card_atr 3B:DF:18:FF:81:91:FE:1F:C3:00:31:B8:64:0C:01:EC:C1:73:94:01:80:82:90:00:B3 { + type = 25004; + driver = "iasecc"; + name = "Amos IAS/ECC v1.0.1"; + md_read_only = false; + md_supports_X509_enrollment = true; + secure_messaging = local_amos; + } + card_atr 3B:DC:18:FF:81:91:FE:1F:C3:80:73:C8:21:13:66:01:0B:03:52:00:05:38 { + type = 25004; + driver = "iasecc"; + name = "Amos IAS/ECC v1.0.1"; + md_read_only = false; + md_supports_X509_enrollment = true; + secure_messaging = local_amos_eid; + } + + # SmartCard-HSM with contact-based interface or USB-Stick + card_atr 3B:FE:18:00:00:81:31:FE:45:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:FA { + driver = "sc-hsm"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + } + + # SmartCard-HSM with contact-less interface + card_atr 3B:8E:80:01:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:18 { + driver = "sc-hsm"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + } + + # SmartCard-HSM with fingerprint sensor and PIN pad + card_atr 3B:80:80:01:01 { + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + + # GoID with fingerprint sensor and PIN pad + card_atr 3B:84:80:01:47:6f:49:44:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:85:80:01:47:6f:49:44:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:86:80:01:47:6f:49:44:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:87:80:01:47:6f:49:44:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:88:80:01:47:6f:49:44:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:89:80:01:47:6f:49:44:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8A:80:01:47:6f:49:44:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8B:80:01:47:6f:49:44:00:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8C:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8D:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8E:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + + # GoID with fingerprint sensor and PIN pad + card_atr 3B:8F:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00:00:00 { + atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00:00:00"; + driver = "sc-hsm"; + force_protocol = "t1"; + md_read_only = false; + md_supports_X509_enrollment = true; + md_supports_container_key_gen = true; + md_guid_as_label = true; + md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben"; + md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte."; + md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte."; + md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen."; + md_pinpad_dlg_timeout = 30; + notify_card_inserted = "GoID erkannt"; + notify_card_inserted_text = ""; + notify_card_removed = "GoID entfernt"; + notify_pin_good = "Fingerabdruck bzw. PIN verifiziert"; + notify_pin_good_text = "GoID ist entsperrt"; + notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert"; + notify_pin_bad_text = "GoID ist gesperrt"; + } + + secure_messaging local_authentic { + # name of external SM module + # module_name = @DEFAULT_SM_MODULE@; + # directory with external SM module + # Default: @DEFAULT_SM_MODULE_PATH@ + # module_path = @DEFAULT_SM_MODULE_PATH@; + + # specific data to tune the module initialization + # module_data = "Here can be your SM module init data"; + + # SM mode: + # 'transmit' -- in this mode the procedure to securize an APDU is called by the OpenSC general + # APDU transmit procedure. + # In this mode all APDUs, except the ones filtered by the card specific procedure, + # are securized. + # 'acl' -- in this mode APDU are securized only if needed by the ACLs of the command to be executed. + # + #mode = transmit; + + # SM type specific flags + # flags = 0x78; # 0x78 -- level 3, channel 0 + + # Default KMC of the GP Card Manager for the Oberthur's Java cards + # kmc = "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"; + } + + secure_messaging local_gemalto_iam { + module_name = @DEFAULT_SM_MODULE@; + # module_path = @DEFAULT_SM_MODULE_PATH@; + # module_data = ""; + type = acl; # transmit, acl + + ifd_serial = "11:22:33:44:55:66:77:88"; + + # Keyset values from IAM profiles of the Gemalto IAS/ECC cards + keyset_02_enc = "RW_PRIV_ENC_TEST"; + keyset_02_mac = "RW_PRIV_MAC_TEST"; + + keyset_E828BD080FD2504543432D654944_01_enc = "RO_ENC_TEST_KEY_"; + keyset_E828BD080FD2504543432D654944_01_mac = "RO_MAC_TEST_KEY_"; + + keyset_E828BD080FD2504543432D654944_03_enc = "RW_PUBL_ENC_TEST"; + keyset_E828BD080FD2504543432D654944_03_mac = "RW_PUBL_MAC_TEST"; + } + + secure_messaging local_amos { + module_name = @DEFAULT_SM_MODULE@; + # module_path = @DEFAULT_SM_MODULE_PATH@; + # module_data = ""; + mode = acl; + ifd_serial = "11:22:33:44:55:66:77:88"; + keyset_02_enc = "ENCROECHANTILLON"; + keyset_02_mac = "MACROECHANTILLON"; + } + + secure_messaging local_amos_eid { + module_name = @DEFAULT_SM_MODULE@; + # module_path = @DEFAULT_SM_MODULE_PATH@; + # module_data = ""; + mode = acl; + ifd_serial = "11:22:33:44:55:66:77:88"; + keyset_E828BD080FD2504543432D654944_03_enc = "RW_PUBL_ENC_TEST"; + keyset_E828BD080FD2504543432D654944_03_mac = "RW_PUBL_MAC_TEST"; + } + + secure_messaging local_adele { + module_name = @DEFAULT_SM_MODULE@; + # module_path = @DEFAULT_SM_MODULE_PATH@; + # module_data = ""; + type = acl; # transmit, acl + + ifd_serial = "11:22:33:44:55:66:77:88"; + + # Keyset values from 'Adele' profiles of the IAS/ECC cards + keyset_01_enc = "EMENCECHANTILLON"; + keyset_01_mac = "EMMACECHANTILLON"; + + keyset_02_enc = "AAENCECHANTILLON"; + keyset_02_mac = "AAMACECHANTILLON"; + + keyset_E828BD080FD2500000040301_02_enc = "E2ENCECHANTILLON"; + keyset_E828BD080FD2500000040301_02_mac = "E2MACECHANTILLON"; + + keyset_D2500000044164E86C650101_02_enc = "E1ENCECHANTILLON"; + keyset_D2500000044164E86C650101_02_mac = "E1MACECHANTILLON"; + + keyset_D2500000044164E86C650101_03_enc = "SIENCECHANTILLON"; + keyset_D2500000044164E86C650101_03_mac = "SIMACECHANTILLON"; + } + + # Below are the framework specific configuration blocks. + + # PKCS #15 + framework pkcs15 { + # Whether to use the cache files in the user's + # home directory. + # + # Note: If caching is done by a system process, caching may be placed + # inaccessible from the user account. Use a global caching directory if + # you wish to share the cached information. + # + # Default: false + # use_file_caching = true; + # + # set a path for caching + # so you do not use the env variables and for pam_pkcs11 + # (with certificate check) where $HOME is not set + # Default: path in user home + # file_cache_dir = /var/lib/opensc/cache + # + # Use PIN caching? + # Default: true + # use_pin_caching = false; + # + # How many times to use a PIN from cache before re-authenticating it? + # Default: 10 + # pin_cache_counter = 3; + # + # Older PKCS#11 applications not supporting CKA_ALWAYS_AUTHENTICATE + # may need to set this to get signatures to work with some cards. + # Default: false + # pin_cache_ignore_user_consent = true; + # + # Enable pkcs15 emulation. + # Default: yes + # enable_pkcs15_emulation = no; + # + # Prefer pkcs15 emulation code before + # the normal pkcs15 processing. + # Some cards (like esteid and pteid) work in emu-only mode, + # and do not depend on this option. + # + # Default: no + # try_emulation_first = yes; + + # Enable builtin emulators. + # Default: yes + # enable_builtin_emulation = no; + # + # List of the builtin pkcs15 emulators to test + # Default: esteid, openpgp, tcos, starcert, itacns, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II; + # builtin_emulators = openpgp; + + # additional settings per driver + # + # For pkcs15 emulators loaded from an external shared + # library/DLL, you need to specify the path name of the module + # and customize the card_atr example above correctly. + # + # emulate custom { + # The location of the driver library + # module = @LIBDIR@@LIB_PRE@p15emu_custom@DYN_LIB_EXT@; + # } + + # Enable initialization and card recognition in PKCS#11 layer. + # Default: no + # pkcs11_enable_InitToken = yes; + + # some additional application parameters: + # - type (generic, protected) used to distinguish the common access application + # and application for which authentication to perform some operation cannot be + # obtained with the common procedures (ex. object creation protected by secure messaging). + # Used by PKCS#11 module configured to expose restricted number of slots. + # (for ex. configured to expose only User PIN slot, User and Sign PINs slots, ...) + # + # - disable: do not expose application in PKCS15 framework + # default 'false' + application E828BD080FD25047656E65726963 { + type = generic; + model = "ECC Generic PKI"; + # disable = true + } + + application E828BD080FD2500000040301 { + type = generic; + model = "Adèle Générique"; + } + + application E828BD080FD2504543432D654944 { + type = protected; + model = "ECC eID"; + } + + application E828BD080FD2500000040201 { + type = protected; + model = "Adèle Admin-2"; + } + } +} + +# Parameters for the OpenSC PKCS11 module +app opensc-pkcs11 { + pkcs11 { + # Maximum Number of virtual slots. + # If there are more slots than defined here, + # the remaining slots will be hidden from PKCS#11. + # Default: 16 + # max_virtual_slots = 32; + + # Maximum number of slots per smart card. + # If the card has fewer keys than defined here, + # the remaining number of slots will be empty. + # Default: 4 + # slots_per_card = 2; + + # (max_virtual_slots/slots_per_card) limits the number of readers + # that can be used on the system. Default is then 16/4=4 readers. + + # By default, the OpenSC PKCS#11 module will not lock your card + # once you authenticate to the card via C_Login. + # + # Thus the other users or other applications is not prevented + # from connecting to the card and perform crypto operations + # (which may be possible because you have already authenticated + # with the card). This setting is not very secure. + # + # Also, if your card is not locked, you can enconter problems + # due to limitation of the OpenSC framework, that still is not + # thoroughly tested in the multi threads environment. + # + # Your settings will be more secure if you choose to lock your + # card. Nevertheless this behavior is a known violation of PKCS#11 + # specification. Now once one application has started using your + # card with C_Login, no other application can use it, until + # the first is done and calls C_Logout or C_Finalize. In the case + # of many PKCS#11 application this does not happen until you exit + # the application. + # Thus it is impossible to use several smart card aware applications + # at the same time, e.g. you cannot run both Firefox and Thunderbird at + # the same time, if both are configured to use your smart card. + # + # Default: false + # lock_login = true; + + # By default, interacting with the OpenSC PKCS#11 module may change the + # state of the token, e.g. whether a user is logged in or not. + # + # Thus other users or other applications may change or use the state of + # the token unknowingly. Other applications may create signatures + # abusing an existing login or they may logout unnoticed. + # + # With this setting enabled the login state of the token is tracked and + # cached (including the PIN). Every transaction is preceded by + # restoring the login state. After every transaction a logout is + # performed. This setting by default also enables `lock_login` (see + # above) to disable access for other applications during the atomic + # transactions. + # + # Please note that any PIN-pad should be disabled (see `enable_pinpad` + # above), because the user would have to input his PIN for every + # transaction. + # + # Default: false + # atomic = true; + + # With this setting disabled, the OpenSC PKCS#11 module will initialize + # the slots available when the application calls `C_GetSlotList`. With + # this setting enabled, the slots will also get initialized when + # C_GetSlotInfo is called. + # + # This setting is a workaround for Java which does not call + # `C_GetSlotList` when configured with a static `slot` instead of + # `slotListIndex`. + # + # Default: true + # init_sloppy = false; + + # User PIN unblock style + # none: PIN unblock is not possible with PKCS#11 API; + # set_pin_in_unlogged_session: C_SetPIN() in unlogged session: + # PUK is passed as the 'OldPin' argument of the C_SetPIN() call. + # set_pin_in_specific_context: C_SetPIN() in the CKU_SPECIFIC_CONTEXT logged session: + # PUK is passed as the 'OldPin' argument of the C_SetPIN() call. + # init_pin_in_so_session: C_InitPIN() in CKU_SO logged session: + # User PIN 'UNBLOCK' is protected by SOPIN. (PUK == SOPIN). + # # Actually this style works only for the PKCS15 contents without SOPIN. + # # For those with SOPIN, this mode will be usefull for the cards without + # # modes 00 and 01 of ISO command 'RESET RETRY COUNTER'. --vt + # + # Default: none + # user_pin_unblock_style = set_pin_in_unlogged_session; + + # Create slot for unblocking PIN with PUK + # This way PKCS#11 API can be used to login with PUK and + # change a PIN. + # Warning: causes problems with some applications like + # firefox and thunderbird. Thus turned off by default + # + # Default: false + # create_puk_slot = true; + + # Symbolic names of PINs for which slots are created + # Card can contain more then one PINs or more then one on-card application with + # its own PINs. Normally, to access all of them with the PKCS#11 API a slot has to be + # created for all of them. Many slots could be ennoying for some of widely used application, + # like FireFox. This configuration parameter allows to select the PIN(s) + # for which PKCS#11 slot will be created. + # Actually recognised following symbolic names: + # 'user', 'sign', 'all' + # Only PINs initialised, non-SoPIN, non-unblocking are associated with symbolic name. + # 'user' is identified as first global or first local PIN. + # 'sign' is identified as second PIN: first local, second global or second local. + # 'all' slot created for all non-sopin, non-unblocking PINs, + # optionally for PUK (see option 'create_puk_slot') + # + # Default: all + # create_slots_for_pins = "user,sign"; + # create_slots_for_pins = "sign"; + # + # For the module to simulate the opensc-onepin module behavior the following option + # must be set: + # create_slots_for_pins = "user" + } +} + +app onepin-opensc-pkcs11 { + pkcs11 { + slots_per_card = 1; + } +} + +# Used by OpenSC.tokend on Mac OS X only +app tokend { + # The file to which debug log will be written + # Default: /tmp/opensc-tokend.log + # + # debug_file = /Library/Logs/OpenSC.tokend.log + + framework tokend { + # Score for OpenSC.tokend + # The tokend with the highest score shall be used. + # Default: 300 + # + # score = 10; + + # Tokend ignore to read PIN protected certificate that is set SC_PKCS15_CO_FLAG_PRIVATE flag. + # Default: true + # + # ignore_private_certificate = false; + } +} + +# Used by OpenSC minidriver on Windows only +app cardmod { +} diff -Nru opensc-0.17.0/etc/opensc.conf.in opensc-0.19.0/etc/opensc.conf.in --- opensc-0.17.0/etc/opensc.conf.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/etc/opensc.conf.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,790 +0,0 @@ -# Configuration file for OpenSC -# Example configuration file - -# NOTE: All key-value pairs must be terminated by a semicolon. - -# Default values for any application -# These can be overridden by an application -# specific configuration block. -app default { - # Amount of debug info to print - # - # A greater value means more debug info. - # Default: 0 - # - #debug = 3; - - # The file to which debug output will be written - # - # Special values 'stdout' and 'stderr' are recognized. - # Default: stderr - # - # debug_file = @DEBUG_FILE@ - - # Reopen debug file at the every debug message. - # - # For Windows it's forced to 'true'. The reason is that - # in Windows file handles can not be shared between DLL-s, - # each DLL has a separate file handle table. - # - # Default: false - # reopen_debug_file = true; - - # PKCS#15 initialization / personalization - # profiles directory for pkcs15-init. - # Default: @PROFILE_DIR_DEFAULT@ - # - # profile_dir = @PROFILE_DIR@; - - # Paranoid memory allocation. - # - # If set to 'true', then refuse to continue when locking of non-pageable - # memory fails. This can cause subtle failures but is more secure when - # you have a swap disk. - # Default: false - # - # paranoid_memory = false; - - # Dsiable pop-ups of built-in GUI - # - # Default: false - # disable_popups = true; - - # Enable default card driver - # Default card driver is explicitely enabled for the 'opensc-explorer' and 'opensc-tool'. - # - # Default: false - # enable_default_driver = true; - - # CT-API module configuration. - reader_driver ctapi { - # module @LIBDIR@@LIB_PRE@towitoko@DYN_LIB_EXT@ { - # CT-API ports: - # 0..3 COM1..4 - # 4 Printer - # 5 Modem - # 6..7 LPT1..2 - # ports = 0; - # } - } - - # The following section shows definitions for PC/SC readers. - reader_driver pcsc { - # Limit command and response sizes. Some Readers don't propagate their - # transceive capabilities correctly. max_send_size and max_recv_size - # allow setting the limits manually, for example to enable extended - # length capabilities. - # Default: max_send_size = 255, max_recv_size = 256; - # max_send_size = 65535; - # max_recv_size = 65536; - # - # Connect to reader in exclusive mode? - # Default: false - # connect_exclusive = true; - # - # What to do when disconnecting from a card (SCardDisconnect) - # Valid values: leave, reset, unpower. - # Default: reset - # disconnect_action = unpower; - # - # What to do at the end of a transaction (SCardEndTransaction) - # Valid values: leave, reset, unpower. - # Default: leave - # transaction_end_action = reset; - # - # What to do when reconnection to a card (SCardReconnect) - # Valid values: leave, reset, unpower. - # Note that this affects only the internal reconnect (after a SCARD_W_RESET_CARD). - # A forced reset via sc_reset() always does a full powerup. - # Default: leave - # reconnect_action = reset; - # - # Enable pinpad if detected (PC/SC v2.0.2 Part 10) - # Default: true - # enable_pinpad = false; - # - # Detect reader capabilities with escape commands (wrapped APDUs with - # CLA=0xFF as defined by PC/SC pt. 3 and BSI TR-03119, e.g. for getting - # the UID, escaped PIN commands and the reader's firmware version) - # Default: false - # enable_escape = true; - # - # Use specific pcsc provider. - # Default: @DEFAULT_PCSC_PROVIDER@ - # provider_library = @DEFAULT_PCSC_PROVIDER@ - } - - # Options for OpenCT support - reader_driver openct { - # Virtual readers to allocate. - # Default: 2 - # readers = 5; - # - # Limit command and response sizes. - # Default: n/a - # max_send_size = 255; - # max_recv_size = 256; - } - - # Options for CryptoTokenKit support - reader_driver cryptotokenkit { - # Limit command and response sizes. Some Readers don't propagate their - # transceive capabilities correctly. max_send_size and max_recv_size - # allow setting the limits manually, for example to enable extended - # length capabilities. - # Default: autodetect - # max_send_size = 65535; - # max_recv_size = 65536; - } - - # Whitelist of card drivers to load at start-up - # - # The supported internal card driver names can be retrieved - # from the output of: - # $ opensc-tool --list-drivers - # - # A special value of 'internal' will load all - # statically linked drivers. If an unknown (ie. not - # internal) driver is supplied, a separate configuration - # configuration block has to be written for the driver. - # Default: internal - # NOTE: When "internal" keyword is used, must be last entry - # - card_drivers = npa, internal; - - # Card driver configuration blocks. - - # For card drivers loaded from an external shared library/DLL, - # you need to specify the path name of the module - # - # card_driver customcos { - # The location of the driver library - # module = @LIBDIR@@LIB_PRE@card_customcos@DYN_LIB_EXT@; - # } - - card_driver npa { - # German ID card requires the CAN to be verified before QES PIN. This, - # however, is not part of the PKCS#15 profile of the card. So for - # verifying the QES PIN we actually need both. The CAN may be given - # here. If the CAN is not given here, it will be prompted on the - # command line or on the reader (depending on the reader's - # capabilities). - # - #can = 222222; - - # QES is only possible with a Comfort Reader (CAT-K), which holds a - # cryptographic key to authenticate itself as signature terminal (ST). - # We usually will use the reader's capability to sign the data. - # However, during developement you may specify soft certificates and - # keys for a ST below. - # The following example EAC PKI can be found in vicc's example data: - # https://github.com/frankmorgner/vsmartcard/tree/master/virtualsmartcard/npa-example-data - # - #st_dv_certificate = ZZSTDVCA00001.cvcert; - #st_certificate = ZZSTTERM00001.cvcert; - #st_key = ZZSTTERM00001.pkcs8; - } - - # Force using specific card driver - # - # If this option is present, OpenSC will use the supplied - # driver with all inserted cards. - # - # Default: autodetect - # - # force_card_driver = customcos; - - # Configuration block for DNIe - # - # Card DNIe has an option to show an extra warning before - # issuing a signature. - - card_driver dnie { - # Disable / enable warning message when performing a - # signature operation with the DNIe. - # Only used if compiled with --enable-dnie-ui - # user_consent_enabled = yes; - - # Specify the pinentry application to use if warning - # is configured to be displayed using pinentry. - # Default: /usr/bin/pinentry - # Only used if compiled with --enable-dnie-ui - # user_consent_app = "/usr/bin/pinentry"; - } - - # In addition to the built-in list of known cards in the - # card driver, you can configure a new card for the driver - # using the card_atr block. The goal is to centralize - # everything related to a certain card to card_atr. - # - # The supported internal card driver names can be retrieved - # from the output of: - # $ opensc-tool --list-drivers - - # Generic format: card_atr - - # New card entry for the flex card driver - # card_atr 3b:f0:0d:ca:fe { - # All parameters for the context are - # optional unless specified otherwise. - - # Context: global, card driver - # - # ATR mask value - # - # The mask is logically AND'd with an - # card ATR prior to comparison with the - # ATR reference value above. Using mask - # allows identifying and configuring - # multiple ATRs as the same card model. - # atrmask = "ff:ff:ff:ff:ff"; - - # Context: card driver - # - # Specify used card driver (REQUIRED). - # - # When enabled, overrides all possible - # settings from the card drivers built-in - # card configuration list. - # driver = "flex"; - - # Set card name for card drivers that allows it. - # name = "My CryptoFlex card"; - - # Card type as an integer value. - # - # Depending on card driver, this allows - # tuning the behaviour of the card driver - # for your card. - # type = "2002"; - - # Card flags as an hex value. - # Multiple values are OR'd together. - # - # Depending on card driver, this allows - # fine-tuning the capabilities in - # the card driver for your card. - # - # Optionally, some known parameters - # can be specified as strings: - # - # rng - On-board random number source - # - # flags = "rng", "0x80000000"; - - # Enable pkcs11 initialization. - # Default: no - # pkcs11_enable_InitToken = yes; - - # - # Context: PKCS#15 emulation layer - # - # When using PKCS#15 emulation, force - # the emulation driver for specific cards. - # - # Required for external drivers, but can - # be used with built-in drivers, too. - # pkcs15emu = "custom"; - - # - # Context: reader driver - # - # Force protocol selection for specific cards. - # Known parameters: t0, t1, raw - # force_protocol = "t0"; - - # Context: minidriver - # - # md_read_only: Mark card as read/only card in Minidriver/BaseCSP interface (Default: false) - # md_supports_X509_enrollment: Indicate X509 enrollment support at Minidriver/BaseCSP interface (Default: false) - # md_guid_as_id: Use the GUID generated for the key as id in the PKCS#15 structure (Default: false - auto generated) - # md_guid_as_label: Use the GUID generated for the key as label in the PKCS#15 structure (Default: false - no label set) - # md_supports_container_key_gen: Card allows generating key pairs on the card (Default: false) - # md_supports_container_key_import: Card allows importing private keys (Default: false) - # } - - # PIV cards need an entry similar to this one: - # card_atr 3B:7D:96:00:00:80:31:80:65:B0:83:11:00:AC:83:00:90:00 { - # name = "PIV-II"; - # driver = "piv"; - # } - - # Estonian ID card and Micardo driver sometimes only play together with T=0 - # In theory only the 'cold' ATR should be specified, as T=0 will - # be the preferred protocol once you boot it up with T=0, but be - # paranoid. - # - # Warm ATR v1 - card_atr 3b:6e:00:ff:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 { - force_protocol = t0; - } - # Cold ATR v1 - card_atr 3b:fe:94:00:ff:80:b1:fa:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:43 { - force_protocol = t0; - } - # Warm ATR v2 - card_atr 3b:5e:11:ff:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 { - force_protocol = t0; - } - # Cold ATR v2 - card_atr 3b:de:18:ff:c0:80:b1:fe:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:2b { - force_protocol = t0; - } - # Digi-ID cold ATR. The same card has the same warm ATR as "Cold ATR v1" above - # The card is claimed to only support T=0 but in fact (sometimes) works with T=1, even if not advertised in ATR. - card_atr 3b:6e:00:00:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 { - force_protocol = t0; - } - - # D-Trust cards are also based on micardo and need T=0 for some reason - card_atr 3b:ff:94:00:ff:80:b1:fe:45:1f:03:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00:23 { - force_protocol = t0; - } - card_atr 3b:ff:11:00:ff:80:b1:fe:45:1f:03:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00:a6 { - force_protocol = t0; - } - - # Oberthur's AuthentIC v3.2.2 - card_atr 3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:00:70:0A:90:00:8B { - type = 11100; - driver = "authentic"; - name = "AuthentIC v3.1"; - - # Name of SM configuration sub-section - # secure_messaging = local_authentic; - } - - # IAS/ECC cards - card_atr 3B:7F:96:00:00:00:31:B9:64:40:70:14:10:73:94:01:80:82:90:00 { - type = 25001; - driver = "iasecc"; - name = "Gemalto MultiApp IAS/ECC v1.0.1"; - secure_messaging = local_gemalto_iam; - # secure_messaging = local_adele; - md_read_only = false; - md_supports_X509_enrollment = true; - } - card_atr 3B:7F:96:00:00:00:31:B8:64:40:70:14:10:73:94:01:80:82:90:00 { - type = 25001; - driver = "iasecc"; - name = "Gemalto MultiApp IAS/ECC v1.0.1"; - secure_messaging = local_gemalto_iam; - md_read_only = false; - md_supports_X509_enrollment = true; - } - #card_atr 3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:08:00:07:90:00:FE { - # type = 25002; - # driver = "iasecc"; - # name = "Oberthur IAS/ECC v1.0.1"; - # # No 'admin' application for this card -- no secure messaging - #} - #card_atr 3B:7F:18:00:00:00:31:B8:64:50:23:EC:C1:73:94:01:80:82:90:00 { - # type = 25003; - # driver = "iasecc"; - # name = "Morpho YpsID S3 IAS/ECC"; - # # secure_messaging = local_morpho_YpsID_S3; - #} - #card_atr 3B:DF:96:00:80:31:FE:45:00:31:B8:64:04:1F:EC:C1:73:94:01:80:82:90:00:EC { - # type = 25005; - # driver = "iasecc"; - # name = "Morpho MI IAS/ECC v1.0.1"; - # md_read_only = false; - # md_supports_X509_enrollment = true; - # secure_messaging = local_morpho_mi; - #} - card_atr 3B:DF:18:FF:81:91:FE:1F:C3:00:31:B8:64:0C:01:EC:C1:73:94:01:80:82:90:00:B3 { - type = 25004; - driver = "iasecc"; - name = "Amos IAS/ECC v1.0.1"; - md_read_only = false; - md_supports_X509_enrollment = true; - secure_messaging = local_amos; - } - card_atr 3B:DC:18:FF:81:91:FE:1F:C3:80:73:C8:21:13:66:01:0B:03:52:00:05:38 { - type = 25004; - driver = "iasecc"; - name = "Amos IAS/ECC v1.0.1"; - md_read_only = false; - md_supports_X509_enrollment = true; - secure_messaging = local_amos_eid; - } - - # SmartCard-HSM with contact-based interface or USB-Stick - card_atr 3B:FE:18:00:00:81:31:FE:45:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:FA { - driver = "sc-hsm"; - md_read_only = false; - md_supports_X509_enrollment = true; - md_supports_container_key_gen = true; - md_guid_as_label = true; - } - - # SmartCard-HSM with contact-less interface - card_atr 3B:8E:80:01:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:18 { - driver = "sc-hsm"; - md_read_only = false; - md_supports_X509_enrollment = true; - md_supports_container_key_gen = true; - md_guid_as_label = true; - } - - secure_messaging local_authentic { - # name of external SM module - # module_name = @DEFAULT_SM_MODULE@; - # directory with external SM module - # Default: defined by windows register - @DEFAULT_SM_MODULE_PATH@ - - # specific data to tune the module initialization - # module_data = "Here can be your SM module init data"; - - # SM mode: - # 'transmit' -- in this mode the procedure to securize an APDU is called by the OpenSC general - # APDU transmit procedure. - # In this mode all APDUs, except the ones filtered by the card specific procedure, - # are securized. - # 'acl' -- in this mode APDU are securized only if needed by the ACLs of the command to be executed. - # - #mode = transmit; - - # SM type specific flags - # flags = 0x78; # 0x78 -- level 3, channel 0 - - # Default KMC of the GP Card Manager for the Oberthur's Java cards - # kmc = "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"; - } - - secure_messaging local_gemalto_iam { - module_name = @DEFAULT_SM_MODULE@; - @DEFAULT_SM_MODULE_PATH@ - # module_data = ""; - type = acl; # transmit, acl - - ifd_serial = "11:22:33:44:55:66:77:88"; - - # Keyset values from IAM profiles of the Gemalto IAS/ECC cards - keyset_02_enc = "RW_PRIV_ENC_TEST"; - keyset_02_mac = "RW_PRIV_MAC_TEST"; - - keyset_E828BD080FD2504543432D654944_01_enc = "RO_ENC_TEST_KEY_"; - keyset_E828BD080FD2504543432D654944_01_mac = "RO_MAC_TEST_KEY_"; - - keyset_E828BD080FD2504543432D654944_03_enc = "RW_PUBL_ENC_TEST"; - keyset_E828BD080FD2504543432D654944_03_mac = "RW_PUBL_MAC_TEST"; - } - - secure_messaging local_amos { - module_name = @DEFAULT_SM_MODULE@; - @DEFAULT_SM_MODULE_PATH@ - # module_data = ""; - mode = acl; - ifd_serial = "11:22:33:44:55:66:77:88"; - keyset_02_enc = "ENCROECHANTILLON"; - keyset_02_mac = "MACROECHANTILLON"; - } - - secure_messaging local_amos_eid { - module_name = @DEFAULT_SM_MODULE@; - @DEFAULT_SM_MODULE_PATH@ - # module_data = ""; - mode = acl; - ifd_serial = "11:22:33:44:55:66:77:88"; - keyset_E828BD080FD2504543432D654944_03_enc = "RW_PUBL_ENC_TEST"; - keyset_E828BD080FD2504543432D654944_03_mac = "RW_PUBL_MAC_TEST"; - } - - secure_messaging local_adele { - module_name = @DEFAULT_SM_MODULE@; - @DEFAULT_SM_MODULE_PATH@ - # module_data = ""; - type = acl; # transmit, acl - - ifd_serial = "11:22:33:44:55:66:77:88"; - - # Keyset values from 'Adele' profiles of the IAS/ECC cards - keyset_01_enc = "EMENCECHANTILLON"; - keyset_01_mac = "EMMACECHANTILLON"; - - keyset_02_enc = "AAENCECHANTILLON"; - keyset_02_mac = "AAMACECHANTILLON"; - - keyset_E828BD080FD2500000040301_02_enc = "E2ENCECHANTILLON"; - keyset_E828BD080FD2500000040301_02_mac = "E2MACECHANTILLON"; - - keyset_D2500000044164E86C650101_02_enc = "E1ENCECHANTILLON"; - keyset_D2500000044164E86C650101_02_mac = "E1MACECHANTILLON"; - - keyset_D2500000044164E86C650101_03_enc = "SIENCECHANTILLON"; - keyset_D2500000044164E86C650101_03_mac = "SIMACECHANTILLON"; - } - - # Below are the framework specific configuration blocks. - - # PKCS #15 - framework pkcs15 { - # Whether to use the cache files in the user's - # home directory. - # - # At the moment you have to 'teach' the card - # to the system by running command: pkcs15-tool -L - # - # WARNING: Caching shouldn't be used in setuid root - # applications. - # Default: false - # use_file_caching = true; - # - # set a path for caching - # so you do not use the env variables and for pam_pkcs11 - # (with certificate check) where $HOME is not set - # Default: path in user home - # file_cache_dir = /var/lib/opensc/cache - # - # Use PIN caching? - # Default: true - # use_pin_caching = false; - # - # How many times to use a PIN from cache before re-authenticating it? - # Default: 10 - # pin_cache_counter = 3; - # - # Older PKCS#11 applications not supporting CKA_ALWAYS_AUTHENTICATE - # may need to set this to get signatures to work with some cards. - # Default: false - # pin_cache_ignore_user_consent = true; - # - # Enable pkcs15 emulation. - # Default: yes - # enable_pkcs15_emulation = no; - # - # Prefer pkcs15 emulation code before - # the normal pkcs15 processing. - # Some cards (like esteid and pteid) work in emu-only mode, - # and do not depend on this option. - # - # Default: no - # try_emulation_first = yes; - - # Enable builtin emulators. - # Default: yes - # enable_builtin_emulation = no; - # - # List of the builtin pkcs15 emulators to test - # Default: esteid, openpgp, tcos, starcert, itacns, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II; - # builtin_emulators = openpgp; - - # additional settings per driver - # - # For pkcs15 emulators loaded from an external shared - # library/DLL, you need to specify the path name of the module - # and customize the card_atr example above correctly. - # - # emulate custom { - # The location of the driver library - # module = @LIBDIR@@LIB_PRE@p15emu_custom@DYN_LIB_EXT@; - # } - - # some additional application parameters: - # - type (generic, protected) used to distinguish the common access application - # and application for which authentication to perform some operation cannot be - # obtained with the common procedures (ex. object creation protected by secure messaging). - # Used by PKCS#11 module configurated to expose restricted number of slots. - # (for ex. configurated to expose only User PIN slot, User and Sign PINs slots, ...) - # - # - disable: do not expose application in PKCS15 framework - # default 'false' - application E828BD080FD25047656E65726963 { - type = generic; - model = "ECC Generic PKI"; - # disable = true - } - - application E828BD080FD2500000040301 { - type = generic; - model = "Adèle Générique"; - } - - application E828BD080FD2504543432D654944 { - type = protected; - model = "ECC eID"; - } - - application E828BD080FD2500000040201 { - type = protected; - model = "Adèle Admin-2"; - } - } -} - -# Parameters for the OpenSC PKCS11 module -app opensc-pkcs11 { - pkcs11 { - # Maximum Number of virtual slots. - # If there are more slots than defined here, - # the remaining slots will be hidden from PKCS#11. - # Default: 16 - # max_virtual_slots = 32; - - # Maximum number of slots per smart card. - # If the card has fewer keys than defined here, - # the remaining number of slots will be empty. - # Default: 4 - # slots_per_card = 2; - - # (max_virtual_slots/slots_per_card) limits the number of readers - # that can be used on the system. Default is then 16/4=4 readers. - - # Normally, the pkcs11 module will create - # the full number of slots defined above by - # num_slots. If there are fewer pins/keys on - # the card, the remaining keys will be empty - # (and you will be able to create new objects - # within them). - # Default: true - # hide_empty_tokens = false; - - # By default, the OpenSC PKCS#11 module will not lock your card - # once you authenticate to the card via C_Login. - # - # Thus the other users or other applications is not prevented - # from connecting to the card and perform crypto operations - # (which may be possible because you have already authenticated - # with the card). This setting is not very secure. - # - # Also, if your card is not locked, you can enconter problems - # due to limitation of the OpenSC framework, that still is not - # thoroughly tested in the multi threads environment. - # - # Your settings will be more secure if you choose to lock your - # card. Nevertheless this behavior is a known violation of PKCS#11 - # specification. Now once one application has started using your - # card with C_Login, no other application can use it, until - # the first is done and calls C_Logout or C_Finalize. In the case - # of many PKCS#11 application this does not happen until you exit - # the application. - # Thus it is impossible to use several smart card aware applications - # at the same time, e.g. you cannot run both Firefox and Thunderbird at - # the same time, if both are configured to use your smart card. - # - # Default: false - # lock_login = true; - - # By default, interacting with the OpenSC PKCS#11 module may change the - # state of the token, e.g. whether a user is logged in or not. - # - # Thus other users or other applications may change or use the state of - # the token unknowingly. Other applications may create signatures - # abusing an existing login or they may logout unnoticed. - # - # With this setting enabled the login state of the token is tracked and - # cached (including the PIN). Every transaction is preceeded by - # restoring the login state. After every transaction a logout is - # performed. This setting by default also enables `lock_login` (see - # above) to disable access for other applications during the atomic - # transactions. - # - # Please note that any PIN-pad should be disabled (see `enable_pinpad` - # above), because the user would have to input his PIN for every - # transaction. - # - # Default: false - # atomic = true; - - # With this setting disabled, the OpenSC PKCS#11 module will initialize - # the slots available when the application calls `C_GetSlotList`. With - # this setting enabled, the slots will also get initialized when - # C_GetSlotInfo is called. - # - # This setting is a workaround for Java which does not call - # `C_GetSlotList` when configured with a static `slot` instead of - # `slotListIndex`. - # - # Default: true - # init_sloppy = false; - - # User PIN unblock style - # none: PIN unblock is not possible with PKCS#11 API; - # set_pin_in_unlogged_session: C_SetPIN() in unlogged session: - # PUK is passed as the 'OldPin' argument of the C_SetPIN() call. - # set_pin_in_specific_context: C_SetPIN() in the CKU_SPECIFIC_CONTEXT logged session: - # PUK is passed as the 'OldPin' argument of the C_SetPIN() call. - # init_pin_in_so_session: C_InitPIN() in CKU_SO logged session: - # User PIN 'UNBLOCK' is protected by SOPIN. (PUK == SOPIN). - # # Actually this style works only for the PKCS15 contents without SOPIN. - # # For those with SOPIN, this mode will be usefull for the cards without - # # modes 00 and 01 of ISO command 'RESET RETRY COUNTER'. --vt - # - # Default: none - # user_pin_unblock_style = set_pin_in_unlogged_session; - - # Create slot for unblocking PIN with PUK - # This way PKCS#11 API can be used to login with PUK and - # change a PIN. - # Warning: causes problems with some applications like - # firefox and thunderbird. Thus turned off by default - # - # Default: false - # create_puk_slot = true; - - # Report as 'zero' the CKA_ID attribute of CA certificate - # For the unknown reason the middleware of the manufacturer of gemalto (axalto, gemplus) - # card reports as '0' the CKA_ID of CA cartificates. - # Maybe someone else will need it. (Would be nice to know who and what for -- VTA) - # - # Default: false - # zero_ckaid_for_ca_certs = true; - - # List of readers to ignore - # If any of the strings listed below is matched (case sensitive) in a reader name, - # the reader is ignored by the PKCS#11 module. - # - # Default: empty - # ignored_readers = "CardMan 1021", "SPR 532"; - - # Symbolic names of PINs for which slots are created - # Card can contain more then one PINs or more then one on-card application with - # its own PINs. Normally, to access all of them with the PKCS#11 API a slot has to be - # created for all of them. Many slots could be ennoying for some of widely used application, - # like FireFox. This configuration parameter allows to select the PIN(s) - # for which PKCS#11 slot will be created. - # Actually recognised following symbolic names: - # 'user', 'sign', 'all' - # Only PINs initialised, non-SoPIN, non-unblocking are associated with symbolic name. - # 'user' is identified as first global or first local PIN. - # 'sign' is identified as second PIN: first local, second global or second local. - # 'all' slot created for all non-sopin, non-unblocking PINs, - # optionally for PUK (see option 'create_puk_slot') - # - # Default: all - # create_slots_for_pins = "user,sign"; - # create_slots_for_pins = "sign"; - # - # For the module to simulate the opensc-onepin module behavior the following option - # must be set: - # create_slots_for_pins = "user" - } -} - -app onepin-opensc-pkcs11 { - pkcs11 { - slots_per_card = 1; - } -} - -# Used by OpenSC.tokend on Mac OS X only -app tokend { - # The file to which debug log will be written - # Default: /tmp/opensc-tokend.log - # - # debug_file = /Library/Logs/OpenSC.tokend.log - - framework tokend { - # Score for OpenSC.tokend - # The tokend with the highest score shall be used. - # Default: 300 - # - # score = 10; - } -} - -# Used by OpenSC minidriver on Windows only -app cardmod { -} diff -Nru opensc-0.17.0/.github/ISSUE_TEMPLATE.md opensc-0.19.0/.github/ISSUE_TEMPLATE.md --- opensc-0.17.0/.github/ISSUE_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/.github/ISSUE_TEMPLATE.md 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,29 @@ +### Problem Description + + + +### Proposed Resolution + +### Steps to reproduce + +### Logs + + diff -Nru opensc-0.17.0/.github/PULL_REQUEST_TEMPLATE.md opensc-0.19.0/.github/PULL_REQUEST_TEMPLATE.md --- opensc-0.17.0/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/.github/PULL_REQUEST_TEMPLATE.md 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,17 @@ + + +##### Checklist + +- [ ] Documentation is added or updated +- [ ] New files have a LGPL 2.1 license statement +- [ ] PKCS#11 module is tested +- [ ] Windows minidriver is tested +- [ ] macOS tokend is tested diff -Nru opensc-0.17.0/.github/push_artifacts.sh opensc-0.19.0/.github/push_artifacts.sh --- opensc-0.17.0/.github/push_artifacts.sh 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/.github/push_artifacts.sh 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,27 @@ +#!/bin/bash + +set -ex -o xtrace + +BUILDPATH=${PWD} +BRANCH="`git log --max-count=1 --date=short --abbrev=8 --pretty=format:"%cd_%h"`" + +git clone https://${GH_TOKEN}@github.com/OpenSC/Nightly.git > /dev/null 2>&1 +cd Nightly +git checkout -b "${BRANCH}" + +for file in ${BUILDPATH}/win32/Output/OpenSC*.exe ${BUILDPATH}/opensc*.tar.gz ${BUILDPATH}/OpenSC*.dmg ${BUILDPATH}/OpenSC*.msi ${BUILDPATH}/OpenSC*.zip +do + if [ -f ${file} ] + then + cp ${file} . + git add `basename ${file}` + fi +done + +git commit --message "$1" +if ! git push --quiet --set-upstream origin "${BRANCH}" +then + sleep $[ ( $RANDOM % 32 ) + 1 ]s + git pull --rebase origin "${BRANCH}" + git push --quiet --set-upstream origin "${BRANCH}" +fi diff -Nru opensc-0.17.0/.gitignore opensc-0.19.0/.gitignore --- opensc-0.17.0/.gitignore 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/.gitignore 2018-09-13 11:47:21.000000000 +0000 @@ -49,7 +49,6 @@ *.gz *.bz2 *.[0-9] -*.html *.gif *.css *.out @@ -57,6 +56,7 @@ *.obj *.exp *.res +*.ggo ChangeLog doc/tools/cardos-tool @@ -76,9 +76,13 @@ doc/tools/sc-hsm-tool doc/tools/westcos-tool doc/tools/dnie-tool +doc/tools/egk-tool +doc/tools/npa-tool +doc/tools/opensc-asn1 +doc/tools/opensc-notify +doc/files/opensc.conf.5.xml -etc/opensc.conf.win -etc/opensc.conf +etc/opensc.conf.example src/common/compat_getopt_main src/minidriver/opensc-minidriver.inf src/tools/cardos-tool @@ -102,6 +106,10 @@ src/tools/dnie-tool src/tools/npa-tool src/tools/sceac-example +src/tools/opensc-notify +src/tools/org.opensc.notify.desktop +src/tools/opensc-asn1 +src/tools/egk-tool win32/OpenSC.iss win32/OpenSC.wxs @@ -128,5 +136,6 @@ src/tests/p15dump src/tests/pintest src/tests/prngtest +src/tests/p11test/p11test version.m4.ci diff -Nru opensc-0.17.0/ISSUE_TEMPLATE.md opensc-0.19.0/ISSUE_TEMPLATE.md --- opensc-0.17.0/ISSUE_TEMPLATE.md 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/ISSUE_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -### Expected behaviour - -What should happen? - - -### Actual behaviour - -What happens instead? - - -### Steps to reproduce - -1. -2. -3. - - -### Logs - -Debug output is essential to identify the problem. You can enable debugging by -editing the file `opensc.conf`: -``` - # A debug level of 3 catches most problems - # Some sensitive data may be logged, too, (e.g. PIN codes) - debug = 3; - - # Where to write the debug output (default: `stdout`) - #debug_file = opensc-debug.log -``` - -Please use Gist (https://gist.github.com/) or a similar code paster for longer -logs. Before pasting here, remove your sensitive data from your log (e.g. PIN -code or certificates). - -``` -Paste Log output with less than 10 lines here -``` diff -Nru opensc-0.17.0/m4/ax_check_compile_flag.m4 opensc-0.19.0/m4/ax_check_compile_flag.m4 --- opensc-0.17.0/m4/ax_check_compile_flag.m4 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/m4/ax_check_compile_flag.m4 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff -Nru opensc-0.17.0/MacOSX/build-package.in opensc-0.19.0/MacOSX/build-package.in --- opensc-0.17.0/MacOSX/build-package.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/MacOSX/build-package.in 2018-09-13 11:47:21.000000000 +0000 @@ -1,10 +1,13 @@ #!/bin/bash -# Building the installer is only tested and supported on 10.9+ with Xcode 6.0.1 -# Built package targets 10.10 -# Building should also work on older versions with older revisions or slight changes, YMMV +# Build the macOS installer for the tokend and command line tools. +# +# This is only tested and supported on macOS 10.10 or later, using Xcode 6.0.1. +# Building should also work on older macOS versions with slight changes; YMMV. -# You need to have the following from homebrew or macports or fink: -# autoconf automake libtool pkg-config +# You need to install the following packages from homebrew or macports or fink: +# autoconf automake libtool pkg-config help2man gengetopt + +export MACOSX_DEPLOYMENT_TARGET="10.10" set -ex test -x ./configure || ./bootstrap @@ -14,7 +17,7 @@ SDK_PATH=$(xcrun --sdk macosx --show-sdk-path) # Set SDK path -export CFLAGS="$CFLAGS -isysroot $SDK_PATH -arch x86_64 -mmacosx-version-min=10.10" +export CFLAGS="$CFLAGS -isysroot $SDK_PATH -arch x86_64" export SED=/usr/bin/sed PREFIX=/Library/OpenSC @@ -28,7 +31,7 @@ git clone --depth=1 https://github.com/openssl/openssl.git -b OpenSSL_1_0_2-stable fi cd openssl - KERNEL_BITS=64 ./config --prefix=$PREFIX -mmacosx-version-min=10.10 + KERNEL_BITS=64 ./config --prefix=$PREFIX make clean make update make depend @@ -49,8 +52,8 @@ ./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" + export OPENPACE_CFLAGS="`env PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig:$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/openssl_bin/$PREFIX/lib/pkgconfig:$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 @@ -60,7 +63,7 @@ --enable-x509dir=$PREFIX/etc/x509 \ --disable-dependency-tracking \ --enable-shared \ - --disable-static \ + --enable-static \ --enable-strict \ --disable-assert \ --enable-sm # TODO: remove this (must be sensible default in master) @@ -72,14 +75,15 @@ make -j 2 # copy files - rm -rf target + rm -rf ${BUILDPATH}/target make install DESTDIR=${BUILDPATH}/target # remove garbage - rm -f target/$PREFIX/lib/*.la + rm -f ${BUILDPATH}/target/$PREFIX/lib/*.la + rm -f ${BUILDPATH}/target/$PREFIX/lib/*.a # generate .bundle (required by Adobe Acrobat) - ./MacOSX/libtool-bundle target/$PREFIX/lib/opensc-pkcs11.so target/$PREFIX/lib + ./MacOSX/libtool-bundle ${BUILDPATH}/target/$PREFIX/lib/opensc-pkcs11.so ${BUILDPATH}/target/$PREFIX/lib fi # Check out OpenSC.tokend, if not already fetched. @@ -91,25 +95,44 @@ test -L OpenSC.tokend/build/opensc-src || ln -sf ${BUILDPATH}/src OpenSC.tokend/build/opensc-src # Build and copy OpenSC.tokend -xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj install DSTROOT=${PWD}/target +xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj install DSTROOT=${BUILDPATH}/target + +#if ! test -e $BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications/terminal-notifier.app; then + #if ! test -e terminal-notifier-1.7.1.zip; then + #curl -L https://github.com/julienXX/terminal-notifier/releases/download/1.7.1/terminal-notifier-1.7.1.zip > terminal-notifier-1.7.1.zip + #fi + #if ! test -e terminal-notifier-1.7.1; then + #unzip terminal-notifier-1.7.1.zip + #fi + #mkdir -p $BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications + #cp -r terminal-notifier-1.7.1/terminal-notifier.app $BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications +#fi + +if ! test -e NotificationProxy; then + git clone http://github.com/frankmorgner/NotificationProxy.git +fi +xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/ +mkdir -p "$BUILDPATH/target/Applications" +osacompile -o "$BUILDPATH/target/Applications/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript" + +imagedir=$(mktemp -d) # Prepare target root -# The "UnInstaller" -mkdir -p target/usr/local/bin -cp MacOSX/opensc-uninstall target/usr/local/bin +mkdir -p ${BUILDPATH}/target/usr/local/bin +cp MacOSX/opensc-uninstall ${BUILDPATH}/target/usr/local/bin # Build package -pkgbuild --root target --scripts MacOSX/scripts --identifier org.opensc-project.mac --version @PACKAGE_VERSION@ --install-location / OpenSC.pkg +pkgbuild --root ${BUILDPATH}/target --scripts MacOSX/scripts --identifier org.opensc-project.mac --version @PACKAGE_VERSION@ --install-location / OpenSC.pkg # Build product -productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "OpenSC @PACKAGE_VERSION@.pkg" +productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION@.pkg" -# Build "uninstaller" -osacompile -o "OpenSC Uninstaller.app" "MacOSX/OpenSC_Uninstaller.applescript" +# Build "Uninstaller" +osacompile -o "${imagedir}/OpenSC Uninstaller.app" "MacOSX/OpenSC_Uninstaller.applescript" # Create .dmg rm -f OpenSC-@PACKAGE_VERSION@.dmg i=0 -while ! hdiutil create -srcfolder "OpenSC @PACKAGE_VERSION@.pkg" -srcfolder "OpenSC Uninstaller.app" -volname "@PACKAGE_NAME@" OpenSC-@PACKAGE_VERSION@.dmg +while ! hdiutil create -srcfolder "${imagedir}" -volname "@PACKAGE_NAME@" -fs JHFS+ OpenSC-@PACKAGE_VERSION@.dmg do i=$[$i+1] if [ $i -gt 2 ] @@ -117,3 +140,4 @@ exit 1 fi done +rm -rf ${imagedir} diff -Nru opensc-0.17.0/MacOSX/OpenSC_Notify.applescript opensc-0.19.0/MacOSX/OpenSC_Notify.applescript --- opensc-0.17.0/MacOSX/OpenSC_Notify.applescript 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/MacOSX/OpenSC_Notify.applescript 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,2 @@ +do shell script "killall opensc-notify || true" +do shell script "nohup /Library/OpenSC/bin/opensc-notify > /dev/null 2>&1 &" diff -Nru opensc-0.17.0/MacOSX/opensc-uninstall opensc-0.19.0/MacOSX/opensc-uninstall --- opensc-0.17.0/MacOSX/opensc-uninstall 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/MacOSX/opensc-uninstall 2018-09-13 11:47:21.000000000 +0000 @@ -16,6 +16,7 @@ rm -f /usr/local/lib/onepin-opensc-pkcs11.so # Remove installed files +rm -rf "/Applications/OpenSC Notify.app" rm -rf /Library/OpenSC rm -rf /Library/Security/tokend/OpenSC.tokend rm -rf /System/Library/Security/tokend/OpenSC.tokend diff -Nru opensc-0.17.0/Makefile.am opensc-0.19.0/Makefile.am --- opensc-0.17.0/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -13,12 +13,12 @@ $(srcdir)/packaged EXTRA_DIST = Makefile.mak +DISTCHECK_CONFIGURE_FLAGS = --with-completiondir=/tmp + SUBDIRS = etc src win32 doc MacOSX dist_noinst_SCRIPTS = bootstrap bootstrap.ci dist_noinst_DATA = README \ - solaris/Makefile solaris/README solaris/checkinstall.in \ - solaris/opensc.conf-dist solaris/pkginfo.in solaris/proto \ packaging/debian.templates/changelog \ packaging/debian.templates/compat \ packaging/debian.templates/control \ diff -Nru opensc-0.17.0/NEWS opensc-0.19.0/NEWS --- opensc-0.17.0/NEWS 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/NEWS 2018-09-13 11:47:21.000000000 +0000 @@ -1,6 +1,210 @@ NEWS for OpenSC -- History of user visible changes -# New in 0.17.0; 2016-07-18 +# New in 0.19.0; 2018-09-13 +## General Improvements +* fixed multiple security problems (out of bound writes/reads, #1447): + * CVE-2018-16391 + * CVE-2018-16392 + * CVE-2018-16393 + * CVE-2018-16418 + * CVE-2018-16419 + * CVE-2018-16420 + * CVE-2018-16421 + * CVE-2018-16422 + * CVE-2018-16423 + * CVE-2018-16424 + * CVE-2018-16425 + * CVE-2018-16426 + * CVE-2018-16427 +* Improved documentation: + * New manual page for opensc.conf(5) + * Added several missing switches in manual pages and fixed formatting +* Win32 installer: + * automatically start SCardSvr + * added newer OpenPGP ATRs +* macOS installer: use HFS+ for backward compatibility +* Remove outdated solaris files +* PC/SC driver: + * Workaround OMNIKEY 3x21 and 6121 Smart Card Readers wrongly identified as pinpad readers in macOS +* Workaround cards returning short signatures without leading zeroes +* bash completion + * make location directory configurable + * Use a new correct path by default +* build: support for libressl-2.7+ +* Configuration + * Distribute minimal opensc.conf + * `pkcs11_enable_InitToken made` global configuration option + * Modify behavior of `OPENSC_DRIVER` environment variable to restrict driver list instead of forcing one driver and skipping vital parts of configuration + * Removed configuration options `zero_ckaid_for_ca_certs`, `force_card_driver`, `reopen_debug_file`, `paranoid-memory` + * Generalized configuration option `ignored_readers` +* If card initialization fails, continue card detection with other card drivers (#1251) +* Fixed long term card operations on Windows 8 and later (#1043) +* reader-pcsc: allow fixing the length of a PIN +* fixed multithreading issue on Window with OpenPACE OIDs +## PKCS#11 +* fixed crash during `C_WaitForSlotEvent` (#1335) +## Minidriver +* Allow cancelling the PIN pad prompt before starting the reader transaction. Whether to start the transaction immediately or not is user-configurable for each application +## OpenSC tools +* `opensc-notify` + * add Exit button to tray icon + * User better description (GenericName) and a generic application icon + * Do not display in the application list +* `pkcs15-tool` + * added support for reading ECDSA ssh keys +* `p11test` + * Filter certificates other than `CKC_X_509` +* `opengpg-tool` + * allow calling -d multiple times + * clarify usage text +## sc-hsm +* Implement RSA PSS +* Add support for SmartCard-HSM 4K (V3.0) +## CAC +* Remove support for CAC1 cards +* Ignore unknown tags in properties buffer +* Use GET PROPERTIES to recognize buffer formats +* Unbreak encoding last tag-len-value in the data objects +* Support HID Alt tokens without CCC + * They present certificates in OIDs of first AID and use other undocumented applets + * Inspect the tokens through the ACA applet and GET ACR APDU +## Coolkey +* Unbreak Get Challenge functionality +* Make uninitialized cards working as expected with ESC +## OpenPGP +* add serial number to card name +* include detailed version into card name +* define & set LCS (lifecycle support) as extended capability +* extend manufacturer list in pkcs15-openpgp.c +* correctly parse hist_bytes +* Make deciphering with AUT-key possible for OpenPGP Card >v3.2 (fixes #1352) +* Add supported algorithms for OpenPGP Card (Fixes #1432) +## Starcos +* added support for 2nd generation eGK (#1451) +## CardOS +* create PIN in MF (`pkcs15init`) +## German ID card +* fixed identifying unknown card as German ID card (#1360) +## PIV +* Context Specific Login Using Pin Pad Reader Fix +* Better Handling of Reset using Discovery Object + +# New in 0.18.0; 2018-05-16 +## General Improvements +* PKCS#15 + * fixed parsing ECC parameters from TokenInfo (#1134) + * Added PKCS#15 emulator for DIN 66291 profile + * Cope with empty serial number in TokenInfo +* Build Environment + * Treat compiler warnings as errors (use `--disable-strict` to avoid) + * MacOS + * optionally use CTK in package builder + * fixed detection of OpenPACE package + * macOS High Sierra: fixed dmg creation + * fixed DNIe UI compatibility +* Windows: Use Dedicated md/pkcs11 installation folders instead of installing to System32/SysWOW64 +* fixed (possible) memory leaks for PIV, JPKI, PKCS#11, Minidriver +* fixed many issues reported via compiler warnings, coverity scan and clang's static analyzer +* beautify printed ASN.1 data, add support for ASN.1 time types +* SimpleTLV: Skip correctly two bytes after reading 2b size (#1231) +* added support for `keep_alive` commands for cards with multiple applets to be enabled via `opensc.conf` +* added support for bash completion for arguments that expect filenames +* added keyword `old` for selecting `card_drivers` via `opensc.conf` +* improved documentation manuals for OpenSC tools +* use `leave` as default for `disconnect_action` for PC/SC readers +## PKCS#11 +* Make OpenSC PKCS#11 Vendor Defined attributes, mechanisms etc unique +## Minidriver +* added CNS ATR (#1153) +* Add multiple PINs support to minidriver +* protect MD entry points with `CriticalSection` +## Tokend +* Configuration value for not propagating certificates that require user authentication (`ignore_private_certificate`) +## CryptoTokenKit +* Added support for PIN pad +* fixed codesigning of opensc tools +* Added complete support for system integration with https://github.com/frankmorgner/OpenSCToken +## OpenSC Tools +* `cardos-tool` + * List human-readable version for CardOS 5.3 +* `pkcs11-tool` + * fixed overwriting digestinfo + hash for RSA-PKCS Signature + * Enable support for RSA-PSS signatures in pkcs11-tool + * Add support for RSA-OAEP + * Fixed #1286 + * Add missing pkcs11-tool options to man page + * allow mechanism to be specified in hexadecimal + * fixed default module path on Windows to use opensc-pkcs11.dll +* `pkcs11-spy` + * Add support for RSA-OAEP + * Add support for RSA-PSS +* `pkcs15init` + * Fix rutokenS FCP parsing (#1259) +* `egk-tool` + * Read data from German Health Care Card (Elektronische Gesundheitskarte, eGK) +* `opensc-asn1` + * Parse ASN.1 from files +* `opensc-tool`/`opensc-explorer` + * Allow extended APDUs +## Authentic +* Correctly handle APDUs with more than 256 bytes (#1205) +## Coolkey +* Copy labels from certificate objects to the keys +## Common Access Card +* Fixed infinite reading of certificate +* Added support for Alt token card +## MyEID +* support for RAW RSA signature for 2048 bit keys +## IAS/ECC +* Support for new MinInt agent card +## PIV +* Get cardholder name from the first certificate if token label not specified +* implemented keep alive command (#1256) +* fixed signature creation with `CKA_ALWAYS_AUTHENTICATE` (i.e. PKCS#11 `C_Login(CKU_CONTEXT_SPECIFIC)`) +## CardOS +* fixed card name for CardOS 5 +* added ATR `"3b:d2:18:00:81:31:fe:58:c9:02:17"` +* Try forcing `max_send_size` for PSO:DEC +## DNIe +* DNIe: card also supports 1920 bits (#1247) +## GIDS +* Fix GIDS admin authentication +## epass 3000 +* Add ECC support +* Fix #1073 +* Fix #1115 +* Fix buffer underrun in decipher +* Fix #1306 +## Starcos +* added serial number for 3.4 +* fixed setting key reference for 3.4 +* added support for PIN status queries for 3.4 +## EstEID +* ECDSA/ECDH token support +* Fix crash when certificate read failed (#1176) +* Cleanup expired EstEID card ATR-s +* Fix reading EstEID certificates with T=0 (#1193) +## OpenPGP +* Added support for PIN logout and status +* factory reset is possible if LCS is supported +* Added support for OpenPGP card V3 +* fixed selecting Applet +* implemented keep alive command +* Retrieve OpenPGP applet version from OpenPGP applet on YubiKey token (#1262) +## German ID card +* fixed recognition of newer cards +## SC-HSM +* Don't block generic contactless ATR +* changed default labels of GoID +* added PIN commands for GoID 1.0 +## Starcos +* Added Support for Starcos 3.4 and 3.5 +## MioCOS +* disabled by default, use `card_drivers = old;` to enable; driver will be removed soon. +## BlueZ PKCS#15 applet +* disabled by default, use `card_drivers = old;` to enable; driver will be removed soon. + +# New in 0.17.0; 2017-07-18 ## Support for new Cards * CAC (Common Access Card) * GoID (SC-HSM with built-in PIN pad and fingerprint sensor) @@ -180,7 +384,7 @@ first support for Gids smart card * dnie * Feitian PKI card - new ATRs + new ATRs * IsoApplet (fixes) * starcos @@ -323,7 +527,7 @@ ECC public key encoding ECC ecpointQ * pkcs15init - introduce 'max-unblocks' PIN init parameter + introduce 'max-unblocks' PIN init parameter keep cert. blob in cert-info data file 'content' and 'prop-attrs' in the card profile in profile more AC operations are parsed @@ -345,7 +549,7 @@ documentation for --list-token-slots * default driver do not send possibly arbitrary APDU-s to an unknown card. - by default 'default' card driver is disabled + by default 'default' card driver is disabled * sc-hsm Added support for persistent EC public keys generated from certificate signing requests @@ -383,7 +587,7 @@ * myeid fixed file-id in myeid.profile * entersafe - fix a bug when writing public key + fix a bug when writing public key * EstEID match card only based on presence of application. * pteid @@ -483,7 +687,7 @@ card initialized by Siemens software. Removed "--split-key" option, as it is no longer needed. * Improved debugging support: debug level 3 will show everything - except of ASN1 and card matching debugging (usualy not needed). + except of ASN1 and card matching debugging (usually not needed). * Massive changes to libopensc. This library is now internal, only used by opensc-pkcs11.so and command line tools. Header files are no longer installed, library should not be used by other applications. @@ -498,7 +702,7 @@ certificate for card label. * Possibility to change the default behavior for card resets via opensc.conf. - + New in 0.11.12; 2009-12-18; Andreas Jellinghaus * Document integer problem in OpenSC and implement workaround * Improve entersafe profile to support private data objects @@ -529,12 +733,12 @@ New in 0.11.6; 2008-08-27; Andreas Jellinghaus * Improved security fix: don't match for "OpenSC" in the card label. * New support for Feitian ePass3000 by Weitao Sun. -* GemSafeV1 improved to handle key_ref other than 3 by Douglas E. Engert +* GemSafeV1 improved to handle key_ref other than 3 by Douglas E. Engert New in 0.11.5; 2008-07-31; Andreas Jellinghaus * Apply security fix for cardos driver and extend pkcs15-tool to test cards for the security vulnerability and update them. -* Build system rewritten (NOTICE: configure options was modified). +* Build system rewritten (NOTICE: configure options was modified). The build system can produce outputs for *NIX, cygwin and native windows (using mingw). * ruToken now supported. diff -Nru opensc-0.17.0/README opensc-0.19.0/README --- opensc-0.17.0/README 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/README 2018-09-13 11:47:21.000000000 +0000 @@ -4,4 +4,11 @@ Please take a look at the documentation before trying to use OpenSC. -[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) +[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC/branches) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) + +Build and test status of specific cards: + +| Cards | Status | +|-----------------------|--------| +| CAC | [![CAC](https://gitlab.com/redhat-crypto/OpenSC/badges/cac/build.svg)](https://gitlab.com/redhat-crypto/OpenSC/pipelines) | +| Coolkey | [![Coolkey](https://gitlab.com/redhat-crypto/OpenSC/badges/coolkey/build.svg)](https://gitlab.com/redhat-crypto/OpenSC/pipelines) | diff -Nru opensc-0.17.0/README.md opensc-0.19.0/README.md --- opensc-0.17.0/README.md 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/README.md 2018-09-13 11:47:21.000000000 +0000 @@ -4,4 +4,11 @@ Please take a look at the documentation before trying to use OpenSC. -[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) +[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC/branches) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) + +Build and test status of specific cards: + +| Cards | Status | +|-----------------------|--------| +| CAC | [![CAC](https://gitlab.com/redhat-crypto/OpenSC/badges/cac/build.svg)](https://gitlab.com/redhat-crypto/OpenSC/pipelines) | +| Coolkey | [![Coolkey](https://gitlab.com/redhat-crypto/OpenSC/badges/coolkey/build.svg)](https://gitlab.com/redhat-crypto/OpenSC/pipelines) | diff -Nru opensc-0.17.0/solaris/checkinstall.in opensc-0.19.0/solaris/checkinstall.in --- opensc-0.17.0/solaris/checkinstall.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/checkinstall.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -#!/bin/sh - -expected_platform="@ARCH@" -platform=`uname -p` -if [ ${platform} != ${expected_platform} ]; then - echo "This package must be installed on ${expected_platform}" - exit 1 -fi -exit 0 diff -Nru opensc-0.17.0/solaris/Makefile opensc-0.19.0/solaris/Makefile --- opensc-0.17.0/solaris/Makefile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -PACKAGE=OSCopensc -PACKAGE_NAME=opensc -VERSION=CVS -PWD=pwd -CONFIGURE_PREFIX=$(PWD:sh)/.. -CONFIGURE=${CONFIGURE_PREFIX}/configure -CONFIGURE_ARGS=--prefix=/usr --sysconfdir=/etc/opensc --mandir=/usr/share/man --enable-pcsc --enable-openct -CONFIG_GUESS=${CONFIGURE_PREFIX}/config.guess -UNAME_ARCH=/usr/bin/uname -p -PLATFORM = $(CONFIG_GUESS:sh) -ARCH = $(UNAME_ARCH:sh) - -build: - @echo "Setup platform specific build directory build-${PLATFORM}" - mkdir -p build-${PLATFORM} - ( cd build-${PLATFORM}; CC=cc PCSC_CFLAGS=-I/usr/include/smartcard ${CONFIGURE} ${CONFIGURE_ARGS}; make ) - -dist: - @echo "Setup platform specific dist directory dist-${PLATFORM}" - mkdir -p dist-${PLATFORM} - @echo "Performing Installing in dist directory" - ( cd build-${PLATFORM}; make DESTDIR=`pwd`/../dist-${PLATFORM} install ) -package: - @echo "Setup package meta files" - -cp proto dist-${PLATFORM} - -sed "s|@ARCH@|${ARCH}|" dist-${PLATFORM}/checkinstall - -sed -e "s|@ARCH@|${ARCH}|" \ - -e "s|@VERSION@|${VERSION}|" \ - -e "s|@PACKAGE@|${PACKAGE}|" \ - -e "s|@PACKAGE_NAME@|${PACKAGE_NAME}|" \ - dist-${PLATFORM}/pkginfo - mkdir -p dist-${PLATFORM}/etc/opensc - -cp opensc.conf-dist dist-${PLATFORM}/etc/opensc/opensc.conf - @echo "Creating package" - ( \ - cd dist-${PLATFORM}; \ - pkgmk -o -r . -d . -f proto; \ - pkgtrans -s . ../OSCopensc-${VERSION}-${PLATFORM}.pkg ${PACKAGE} \ - ) diff -Nru opensc-0.17.0/solaris/opensc.conf-dist opensc-0.19.0/solaris/opensc.conf-dist --- opensc-0.17.0/solaris/opensc.conf-dist 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/opensc.conf-dist 1970-01-01 00:00:00.000000000 +0000 @@ -1,286 +0,0 @@ -# Configuration file for OpenSC -# Example configuration file - -# NOTE: All key-value pairs must be terminated by a semicolon. - -# Default values for any application -# These can be overrided by an application -# specific configuration block. -app default { - # Amount of debug info to print - # - # A greater value means more debug info. - # Default: 0 - # - debug = 0; - - # The file to which debug output will be written - # - # A special value of 'stdout' is recognized. - # Default: stdout - # - # debug_file = /tmp/opensc-debug.log; - - # The file to which errors will be written - # - # A special value of 'stderr' is recognized. - # Default: stderr - # - # error_file = /tmp/opensc-errors.log; - - # Where to find the *.profile files for pkcs15init; - - profile_dir = /usr/share/opensc; - - # What reader drivers to load at start-up - # - # A special value of 'internal' will load all - # statically linked drivers. If an unknown (ie. not - # internal) driver is supplied, a separate configuration - # configuration block has to be written for the driver. - # Default: internal - # NOTE: if "internal" keyword is used, must be the - # last entry in reader_drivers list - # - reader_drivers = openct, pcsc, ctapi; - - reader_driver ctapi { - # module /usr/local/towitoko/lib/libtowitoko.so { - # CT-API ports: - # 0..3 COM1..4 - # 4 Printer - # 5 Modem - # 6..7 LPT1..2 - # ports = 0; - # } - } - - # Define parameters specific to your readers. - # The following section shows definitions for PC/SC readers, - # but the same set of variables are applicatable to ctapi and - # openct readers, simply by using "reader_driver ctapi" and - # "reader_driver openct", respectively. - reader_driver pcsc { - # Whether to transform some APDU's from one case to another - # Possible values: - # none: Don't transform any APDU's - # case4as3: For T=0, send a case 4 APDU as case 3, - # (no Lc byte) the card will send back - # a 61xx SW, and we will follow up with a - # GetResponse command - # The SCM SCR111, Sun SCF, and e-gate readers - # seem to require this. - # case1as2: For T=0, send a case 1 APDU as case 2. - # (append an Le byte of 0) - # The Sun SCF and e-gate readers seem to - # require this - # case1as2_always: for any T=0/1, send a case 1 APDU as - # case 2. - # The Sun SCF reader may require this - # Default: none - # - apdu_masquerade = none; - # - # This sets the maximum send and receive sizes. - # Some IFD handlers do not properly handle APDUs with - # large lc or le bytes. - # - max_send_size = 252; - max_recv_size = 252; - # - # EXPERIMENTAL: Enable CCID pinpad support - # implemented (at least) in the libccid driver. - #use_ccid_pin_cmd = true; - } - - # What card drivers to load at start-up - # - # A special value of 'internal' will load all - # statically linked drivers. If an unknown (ie. not - # internal) driver is supplied, a separate configuration - # configuration block has to be written for the driver. - # Default: internal - # NOTE: When "internal" keyword is used, must be last entry - # - # card_drivers = customcos, internal; - - # Card driver configuration blocks. - - # For all drivers, you can specify ATRs of cards that - # should be handled by this driver (in addition to the - # list of compiled-in ATRs). - # - # The supported internal card driver names are - # flex Cryptoflex/Multiflex - # setcos Setec - # etoken Aladdin eToken and other CardOS based cards - # gpk GPK 4K/8K/16K - # mcrd MICARDO 2.1 - # miocos MioCOS 1.1 - # openpgp OpenPGP card - # tcos TCOS 2.0 - # emv EMV compatible cards - - # GPK card driver additional ATR entry: - card_driver gpk { - # atr = 00:11:22; - } - - # For card drivers loaded from an external shared library/DLL, - # you need to specify the path name of the module - # - # card_driver customcos { - # The location of the driver library - # module = /usr/lib/opensc/drivers/card_customcos.so; - # atr = 00:11:22:33:44; - # atr = 55:66:77:88:99:aa:bb; - # } - - # Force using specific card driver - # - # If this option is present, OpenSC will use the supplied - # driver with all inserted cards. - # - # Default: autodetect - # - # force_card_driver = miocos; - - # Below are the framework specific configuration blocks. - - # PKCS #15 - framework pkcs15 { - # Whether to use the cache files in the user's - # home directory. - # - # At the moment you have to 'teach' the card to the - # system by: - # pkcs15-tool -L - # - # WARNING: Caching shouldn't be used in setuid root - # applications. - # Default: false - # - use_caching = true; - # Enable pkcs15 emulation - # Default: yes - enable_pkcs15_emulation = yes; - # Try pkcs15 emulation code first (before the normal - # pkcs15 processing). - # Default: no - try_emulation_first = no; - # Enable builtin emulators - # Default: yes - enable_builtin_emulation = yes; - # list of the builtin pkcs15 emulators to test - # possible values: esteid, openpgp, netkey, netkey, - # starcert, infocamere, postecert - builtin_emulators = esteid, openpgp, netkey, netkey, starcert, infocamere, postecert; - - # additional pkcs15 emulators (dynamic or builtin with - # a different atr etc.) - # emulate foo { - # module = builtin; - # atr = 11:22:33:44; - #} - } - - # Estonian ID card and Micardo driver currently play together with T=0 only. - # In theory only the 'cold' ATR should be specified, as T=0 will be the preferred - # protocol once you boot it up with T=0, but be paranoid. - - # Generic format: card_atr - # Only parameter currently understood is force_protocol - card_atr 3b:6e:00:ff:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 { - force_protocol = t0; - } - card_atr 3b:fe:94:00:ff:80:b1:fa:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:43 { - force_protocol = t0; - } -} - -# For applications that use SCAM (pam_opensc, sia_opensc) -app scam { - framework pkcs15 { - use_caching = false; - } -} - -# Parameters for the OpenSC PKCS11 module -app opensc-pkcs11 { - pkcs11 { - # Maxmimum number of slots per smart card. - # If the card has fewer keys than defined here, - # the remaining number of slots will be empty. - # - # Note that there is currently a compile time - # maximum on the overall number of slots - # the pkcs11 module is able to handle. - num_slots = 4; - - # Normally, the pkcs11 module will create - # the full number of slots defined above by - # num_slots. If there are fewer pins/keys on - # the card, the remaining keys will be empty - # (and you will be able to create new objects - # within them). - # - # Set this option to true to hide these empty - # slots. - hide_empty_tokens = true; - - # By default, the OpenSC PKCS#11 module will - # try to lock this card once you have authenticated - # to the card via C_Login. This is done so that no - # other user can connect to the card and perform - # crypto operations (which may be possible because - # you have already authenticated with the card). - # - # However, this also means that no other application - # that _you_ run can use the card until your application - # has done a C_Logout or C_Finalize. In the case of - # Netscape or Mozilla, this does not happen until - # you exit the browser. - lock_login = true; - - # Normally, the pkcs11 module will not cache PINs - # presented via C_Login. However, some cards - # may not work properly with OpenSC; for instance - # when you have two keys on your card that get - # stored in two different directories. - # - # In this case, you can turn on PIN caching by setting - # cache_pins = true - # - # Default: false - cache_pins = false; - - # Set this value to false if you want to enfore on-card - # keypair generation - # - # Default: true - soft_keygen_allowed = true; - } -} - -# Parameters for the OpenSC PKCS11-Spy module, that logs all the -# communication between a pkcs11 module and it's calling application: -# app <--> pkcs11-spy <--> pkcs11 module -app pkcs11-spy { - spy { - # Where to log to. - # - # By default, the value of the PKCS11SPY_OUTPUT environment - # variable is used. And if that one isn't defined: stderr - # is used. - # - #output = /tmp/pkcs11-spy.log; - - # Which PKCS11 module to load. - # - # By default, the value of the PKCS11SPY environment - # variable is used. And if that one isn't defined, - # opensc-pkcs11.so is used. - # - #module = opensc-pkcs11.so; - } -} diff -Nru opensc-0.17.0/solaris/pkginfo.in opensc-0.19.0/solaris/pkginfo.in --- opensc-0.17.0/solaris/pkginfo.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/pkginfo.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -PKG="OSCopensc" -NAME="opensc" -VERSION="@VERSION@" -ARCH="@ARCH@" -CLASSES="none" -CATEGORY="drivers" -VENDOR="WW" -PSTAMP="26thFeb2005" -EMAIL="william@wanders.org" -ISTATES="S s 1 2 3" -RSTATES="S s 1 2 3" -BASEDIR="/" diff -Nru opensc-0.17.0/solaris/proto opensc-0.19.0/solaris/proto --- opensc-0.17.0/solaris/proto 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -d none usr 0755 root sys -d none usr/share 0755 root other -d none usr/share/man 0755 root other -d none usr/share/man/man1 0755 root other -f none usr/share/man/man1/pkcs15-crypt.1 0644 root other -f none usr/share/man/man1/pkcs15-init.1 0644 root other -f none usr/share/man/man1/cryptoflex-tool.1 0644 root other -f none usr/share/man/man1/opensc-config.1 0644 root other -f none usr/share/man/man1/opensc-explorer.1 0644 root other -f none usr/share/man/man1/opensc-tool.1 0644 root other -f none usr/share/man/man1/pkcs15-tool.1 0644 root other -f none usr/share/man/man1/pkcs11-tool.1 0644 root other -f none usr/share/man/man1/cardos-info.1 0644 root other -d none usr/share/man/man3 0755 root other -f none usr/share/man/man3/sc_connect_card.3 0644 root other -f none usr/share/man/man3/sc_detect_card_presence.3 0644 root other -f none usr/share/man/man3/sc_disconnect_card.3 0644 root other -f none usr/share/man/man3/sc_establish_context.3 0644 root other -f none usr/share/man/man3/sc_file.3 0644 root other -f none usr/share/man/man3/sc_file_free.3 0644 root other -f none usr/share/man/man3/sc_file_new.3 0644 root other -f none usr/share/man/man3/sc_list_files.3 0644 root other -f none usr/share/man/man3/sc_lock.3 0644 root other -f none usr/share/man/man3/sc_read_binary.3 0644 root other -f none usr/share/man/man3/sc_read_record.3 0644 root other -f none usr/share/man/man3/sc_release_context.3 0644 root other -f none usr/share/man/man3/sc_select_file.3 0644 root other -f none usr/share/man/man3/sc_pkcs15_compute_signature.3 0644 root other -d none usr/share/man/man5 0755 root other -f none usr/share/man/man5/pkcs15-profile.5 0644 root other -d none usr/share/man/man7 0755 root other -f none usr/share/man/man7/opensc.7 0644 root other -f none usr/share/man/man7/pkcs15.7 0644 root other -d none usr/share/opensc 0755 root other -f none usr/share/opensc/opensc.conf.example 0644 root other -f none usr/share/opensc/cyberflex.profile 0644 root other -f none usr/share/opensc/flex.profile 0644 root other -f none usr/share/opensc/gpk.profile 0644 root other -f none usr/share/opensc/miocos.profile 0644 root other -f none usr/share/opensc/etoken.profile 0644 root other -f none usr/share/opensc/jcop.profile 0644 root other -f none usr/share/opensc/oberthur.profile 0644 root other -f none usr/share/opensc/starcos.profile 0644 root other -f none usr/share/opensc/pkcs15.profile 0644 root other -d none usr/lib 0755 root bin -s none usr/lib/libscconf.so.0=libscconf.so.0.0.9 -f none usr/lib/libscconf.so.0.0.9 0755 root bin -s none usr/lib/libscconf.so=libscconf.so.0.0.9 -f none usr/lib/libscconf.la 0755 root bin -f none usr/lib/libscconf.a 0644 root bin -s none usr/lib/libopensc.so.0=libopensc.so.0.0.9 -f none usr/lib/libopensc.so.0.0.9 0755 root bin -s none usr/lib/libopensc.so=libopensc.so.0.0.9 -d none usr/lib/pkgconfig 0755 root bin -f none usr/lib/pkgconfig/libopensc.pc 0644 root bin -f none usr/lib/pkgconfig/libpkcs15init.pc 0644 root bin -f none usr/lib/pkgconfig/libscconf.pc 0644 root bin -f none usr/lib/libopensc.la 0755 root bin -f none usr/lib/libopensc.a 0644 root bin -d none usr/lib/pkcs11 0755 root bin -s none usr/lib/pkcs11/libpkcs11.so.0=libpkcs11.so.0.0.9 -f none usr/lib/pkcs11/opensc-pkcs11.so 0755 root bin -f none usr/lib/pkcs11/opensc-pkcs11.la 0755 root bin -f none usr/lib/pkcs11/opensc-pkcs11.a 0644 root bin -f none usr/lib/pkcs11/libpkcs11.so.0.0.9 0755 root bin -s none usr/lib/pkcs11/libpkcs11.so=libpkcs11.so.0.0.9 -f none usr/lib/pkcs11/libpkcs11.la 0755 root bin -f none usr/lib/pkcs11/libpkcs11.a 0644 root bin -f none usr/lib/pkcs11/pkcs11-spy.so 0755 root bin -f none usr/lib/pkcs11/pkcs11-spy.la 0755 root bin -f none usr/lib/pkcs11/pkcs11-spy.a 0644 root bin -f none usr/lib/libpkcs15init.so.0.0.9 0755 root bin -s none usr/lib/libpkcs15init.so.0=libpkcs15init.so.0.0.9 -s none usr/lib/libpkcs15init.so=libpkcs15init.so.0.0.9 -f none usr/lib/libpkcs15init.la 0755 root bin -f none usr/lib/libpkcs15init.a 0644 root bin -d none usr/lib/opensc 0755 root bin -f none usr/lib/opensc/engine_opensc.so 0755 root bin -f none usr/lib/opensc/engine_opensc.la 0755 root bin -f none usr/lib/opensc/engine_opensc.a 0644 root bin -f none usr/lib/opensc/engine_pkcs11.so 0755 root bin -f none usr/lib/opensc/engine_pkcs11.la 0755 root bin -f none usr/lib/opensc/engine_pkcs11.a 0644 root bin -d none usr/include 0755 root bin -d none usr/include/opensc 0755 root bin -d none usr/include/opensc/rsaref 0755 root bin -f none usr/include/opensc/rsaref/pkcs11.h 0644 root bin -f none usr/include/opensc/rsaref/pkcs11f.h 0644 root bin -f none usr/include/opensc/rsaref/pkcs11t.h 0644 root bin -f none usr/include/opensc/rsaref/unix.h 0644 root bin -f none usr/include/opensc/rsaref/win32.h 0644 root bin -f none usr/include/opensc/scconf.h 0644 root bin -f none usr/include/opensc/opensc.h 0644 root bin -f none usr/include/opensc/pkcs15.h 0644 root bin -f none usr/include/opensc/cardctl.h 0644 root bin -f none usr/include/opensc/asn1.h 0644 root bin -f none usr/include/opensc/log.h 0644 root bin -f none usr/include/opensc/ui.h 0644 root bin -f none usr/include/opensc/errors.h 0644 root bin -f none usr/include/opensc/types.h 0644 root bin -f none usr/include/opensc/pkcs15-init.h 0644 root bin -f none usr/include/opensc/pkcs11.h 0644 root bin -d none usr/bin 0755 root bin -f none usr/bin/opensc-config 0755 root bin -f none usr/bin/opensc-tool 0755 root bin -f none usr/bin/opensc-explorer 0755 root bin -f none usr/bin/pkcs15-tool 0755 root bin -f none usr/bin/pkcs15-crypt 0755 root bin -f none usr/bin/pkcs11-tool 0755 root bin -f none usr/bin/cardos-info 0755 root bin -f none usr/bin/eidenv 0755 root bin -f none usr/bin/cryptoflex-tool 0755 root bin -f none usr/bin/pkcs15-init 0755 root bin -d none etc 0755 root sys -d none etc/opensc 0755 root sys -f none etc/opensc/opensc.conf 0644 root sys -i checkinstall=checkinstall -i pkginfo=pkginfo diff -Nru opensc-0.17.0/solaris/README opensc-0.19.0/solaris/README --- opensc-0.17.0/solaris/README 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/solaris/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Creating an installable package for Solaris 10 -============================================== - -The files in this directory are an attempt to ease -the building of opensc packages for Solaris 10. - -The basic steps to create a Solaris 10 package are: -# make build -# make dist -# make package - -NOTE: If you are using the GNU compiler you will - need to adjust the Makefile accordingly. diff -Nru opensc-0.17.0/src/common/compat_getopt.c opensc-0.19.0/src/common/compat_getopt.c --- opensc-0.17.0/src/common/compat_getopt.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/compat_getopt.c 2018-09-13 11:47:21.000000000 +0000 @@ -41,7 +41,7 @@ /* this is the plain old UNIX getopt, with GNU-style extensions. */ /* if you're porting some piece of UNIX software, this is all you need. */ -/* this supports GNU-style permution and optional arguments */ +/* this supports GNU-style permutation and optional arguments */ int my_getopt(int argc, char * argv[], const char *opts) { diff -Nru opensc-0.17.0/src/common/compat___iob_func.c opensc-0.19.0/src/common/compat___iob_func.c --- opensc-0.17.0/src/common/compat___iob_func.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/compat___iob_func.c 2018-09-13 11:47:21.000000000 +0000 @@ -7,14 +7,20 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1900) // needed for OpenSSL static link // only for vs 2015 or later +// +// this is a horrible hack, the correct fix would be to recompile OpenSSL with +// VS 2015 or later. However, since in OpenSC, we don't need OpenSSL to send +// output to any of these buffers, we don't need to cope with runtime errors +// induced by this hack. See https://stackoverflow.com/a/34655235 for details. +// #pragma comment(lib, "legacy_stdio_definitions.lib") #include FILE * __cdecl __iob_func(void) { - static FILE *my_iob[3]; - my_iob[0] = stdin; - my_iob[1] = stdout; - my_iob[2] = stderr; + static FILE my_iob[3]; + my_iob[0] = *stdin; + my_iob[1] = *stdout; + my_iob[2] = *stderr; return my_iob; } #endif diff -Nru opensc-0.17.0/src/common/compat_strlcat.h opensc-0.19.0/src/common/compat_strlcat.h --- opensc-0.17.0/src/common/compat_strlcat.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/compat_strlcat.h 2018-09-13 11:47:21.000000000 +0000 @@ -4,5 +4,6 @@ */ #ifndef HAVE_STRLCAT +#include size_t strlcat(char *dst, const char *src, size_t siz); #endif diff -Nru opensc-0.17.0/src/common/compat_strlcpy.h opensc-0.19.0/src/common/compat_strlcpy.h --- opensc-0.17.0/src/common/compat_strlcpy.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/compat_strlcpy.h 2018-09-13 11:47:21.000000000 +0000 @@ -32,5 +32,6 @@ */ #ifndef HAVE_STRLCPY +#include size_t strlcpy(char *dst, const char *src, size_t siz); #endif diff -Nru opensc-0.17.0/src/common/compat_strnlen.h opensc-0.19.0/src/common/compat_strnlen.h --- opensc-0.17.0/src/common/compat_strnlen.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/compat_strnlen.h 2018-09-13 11:47:21.000000000 +0000 @@ -4,5 +4,6 @@ */ #ifndef HAVE_STRNLEN +#include size_t strnlen(const char *str, size_t maxlen); #endif diff -Nru opensc-0.17.0/src/common/libpkcs11.c opensc-0.19.0/src/common/libpkcs11.c --- opensc-0.17.0/src/common/libpkcs11.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/libpkcs11.c 2018-09-13 11:47:21.000000000 +0000 @@ -75,8 +75,9 @@ return (void *) mod; else { fprintf(stderr, "C_GetFunctionList failed %lx", rv); - C_UnloadModule((void *) mod); - return NULL; + rv = C_UnloadModule((void *) mod); + if (rv == CKR_OK) + mod = NULL; /* already freed */ } failed: free(mod); diff -Nru opensc-0.17.0/src/common/Makefile.mak opensc-0.19.0/src/common/Makefile.mak --- opensc-0.17.0/src/common/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -9,7 +9,7 @@ common.lib: $(COMMON_OBJECTS) lib $(LIBFLAGS) /out:common.lib $(COMMON_OBJECTS) -libpkcs11.lib: libpkcs11.obj libscdl.obj +libpkcs11.lib: libpkcs11.obj lib $(LIBFLAGS) /out:libpkcs11.lib libpkcs11.obj libscdl.lib: libscdl.obj diff -Nru opensc-0.17.0/src/common/README.compat_getopt opensc-0.19.0/src/common/README.compat_getopt --- opensc-0.17.0/src/common/README.compat_getopt 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/README.compat_getopt 2018-09-13 11:47:21.000000000 +0000 @@ -94,14 +94,14 @@ ======================== I re-implemented getopt, getopt_long, and getopt_long_only because -there were noticable bugs in several versions of the GNU +there were noticeable bugs in several versions of the GNU implementations, and because the GNU versions aren't always available on some systems (*BSD, for example.) Other systems don't include any sort of standard argument parser (Win32 with Microsoft tools, for example, has no getopt.) These should do all the expected Unix- and GNU-style argument -parsing, including permution, bunching, long options with single or +parsing, including permutation, bunching, long options with single or double dashes (double dashes are required if you use my_getopt_long,) and optional arguments for both long and short options. A word with double dashes all by themselves halts argument @@ -112,11 +112,11 @@ As with the GNU versions, a '+' prefix to the short option specification (or the POSIXLY_CORRECT environment variable) disables -permution, a '-' prefix to the short option specification returns 1 +permutation, a '-' prefix to the short option specification returns 1 for non-options, ':' after a short option indicates a required argument, and '::' after a short option specification indicates an optional argument (which must appear in the same word.) If you'd like -to recieve ':' instead of '?' for missing option arguments, prefix the +to receive ':' instead of '?' for missing option arguments, prefix the short option specification with ':'. The original intent was to re-implement the documented behavior of diff -Nru opensc-0.17.0/src/common/README.compat_strlcpy opensc-0.19.0/src/common/README.compat_strlcpy --- opensc-0.17.0/src/common/README.compat_strlcpy 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/README.compat_strlcpy 2018-09-13 11:47:21.000000000 +0000 @@ -1,5 +1,5 @@ strncpy() is unsafe since it does not always add a final NUL-byte. -OpenBSD developped a safer version called strlcpy(). +OpenBSD developed a safer version called strlcpy(). Use "man -l strlcpy.3" to read the manpage. diff -Nru opensc-0.17.0/src/common/simclist.c opensc-0.19.0/src/common/simclist.c --- opensc-0.17.0/src/common/simclist.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/simclist.c 2018-09-13 11:47:21.000000000 +0000 @@ -119,7 +119,7 @@ #include "simclist.h" -/* minumum number of elements for sorting with quicksort instead of insertion */ +/* minimum number of elements for sorting with quicksort instead of insertion */ #define SIMCLIST_MINQUICKSORTELS 24 @@ -199,7 +199,7 @@ * 3. avoid interference with user's RNG * * Facts pro system RNG: - * 1. may be more accurate (irrelevant for SimCList randno purposes) + * 1. may be more accurate (irrelevant for SimCList random purposes) * 2. why reinvent the wheel * * Default to local RNG for user's ease of use. @@ -489,6 +489,12 @@ /* actually append element */ prec = list_findpos(l, pos-1); if (prec == NULL) { + if (l->attrs.copy_data) { + free(lent->data); + } + if (!(l->spareelsnum > 0)) { + free(lent); + } return -1; } succ = prec->next; diff -Nru opensc-0.17.0/src/common/simclist.h opensc-0.19.0/src/common/simclist.h --- opensc-0.17.0/src/common/simclist.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/common/simclist.h 2018-09-13 11:47:21.000000000 +0000 @@ -106,7 +106,7 @@ * -# receives two references to elements a and b * -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef int (*element_comparator)(const void *a, const void *b); @@ -118,7 +118,7 @@ * -# receives a reference to some indicator data * -# returns non-0 if the element matches the indicator, 0 otherwise * - * It is responsability of the function to handle possible NULL values in any + * It is responsibility of the function to handle possible NULL values in any * argument. */ typedef int (*element_seeker)(const void *el, const void *indicator); @@ -130,7 +130,7 @@ * -# receives the reference to an element el * -# returns its size in bytes * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef size_t (*element_meter)(const void *el); @@ -141,7 +141,7 @@ * -# receives the reference to an element el * -# returns a hash value for el * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef list_hash_t (*element_hash_computer)(const void *el); @@ -151,7 +151,7 @@ * A serializer function is one that gets a reference to an element, * and returns a reference to a buffer that contains its serialization * along with the length of this buffer. - * It is responsability of the function to handle possible NULL values, + * It is responsibility of the function to handle possible NULL values, * returning a NULL buffer and a 0 buffer length. * * These functions have 3 goals: @@ -290,7 +290,7 @@ * the list by its actual data is not free()d. With this option, every * deletion causes element data to be freed. * - * It is responsability of this function to correctly handle NULL values, if + * It is responsibility of this function to correctly handle NULL values, if * NULL elements are inserted into the list. * * @param l list to operate @@ -470,7 +470,7 @@ * expunge the first found given element from the list. * * Inspects the given list looking for the given element; if the element - * is found, it is removed. Only the first occurence is removed. + * is found, it is removed. Only the first occurrence is removed. * If a comparator function was not set, elements are compared by reference. * Otherwise, the comparator is used to match the element. * @@ -505,7 +505,7 @@ /** * clear all the elements off of the list. * - * The element datums will not be freed. + * The element data will not be freed. * * @see list_delete_range() * @see list_size() @@ -595,7 +595,7 @@ * user-provided list object, which must be different from both the * lists to concatenate. Attributes from the original lists are not * cloned. - * The destination list referred is threated as virgin room: if it + * The destination list referred is treated as virgin room: if it * is an existing list containing elements, memory leaks will happen. * It is OK to specify the same list twice as source, for "doubling" * it in the destination. @@ -672,7 +672,7 @@ #ifdef SIMCLIST_DUMPRESTORE /** - * get meta informations on a list dump on filedescriptor. + * get meta information on a list dump on filedescriptor. * * [ advanced function ] * @@ -689,7 +689,7 @@ int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *simclist_restrict info); /** - * get meta informations on a list dump on file. + * get meta information on a list dump on file. * * [ advanced function ] * diff -Nru opensc-0.17.0/src/libopensc/apdu.c opensc-0.19.0/src/libopensc/apdu.c --- opensc-0.17.0/src/libopensc/apdu.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/apdu.c 2018-09-13 11:47:21.000000000 +0000 @@ -39,7 +39,7 @@ * @param proto the desired protocol * @return length of the encoded APDU */ -static size_t sc_apdu_get_length(const sc_apdu_t *apdu, unsigned int proto) +size_t sc_apdu_get_length(const sc_apdu_t *apdu, unsigned int proto) { size_t ret = 4; @@ -80,7 +80,7 @@ * @param outlen size of hte output buffer * @return SC_SUCCESS on success and an error code otherwise */ -static int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu, +int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu, unsigned int proto, u8 *out, size_t outlen) { u8 *p = out; @@ -244,7 +244,7 @@ * +-------------------------------+ * | * v - * card->reader->ops->tranmit + * card->reader->ops->transmit */ /** basic consistency check of the sc_apdu_t object @@ -350,7 +350,7 @@ if (apdu->cse == SC_APDU_CASE_2 || apdu->cse == SC_APDU_CASE_3 || apdu->cse == SC_APDU_CASE_4) { int btype = apdu->cse & SC_APDU_SHORT_MASK; - /* if either Lc or Le is bigger than the maximun for + /* if either Lc or Le is bigger than the maximum for * short APDUs and the card supports extended APDUs * use extended APDUs (unless Lc is greater than * 255 and command chaining is activated) */ @@ -443,7 +443,7 @@ if (!card->ops->get_response) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "no GET RESPONSE command"); - /* call GET RESPONSE until we have read all data requested or until the card retuns 0x9000, + /* call GET RESPONSE until we have read all data requested or until the card returns 0x9000, * whatever happens first. */ /* if there are already data in response append a new data to the end of the buffer */ @@ -468,7 +468,7 @@ if (rv < 0) { #ifdef ENABLE_SM if (resp_len) { - sc_log(ctx, "SM response data %s", sc_dump_hex(resp, resp_len)); + sc_log_hex(ctx, "SM response data", resp, resp_len); sc_sm_update_apdu_response(card, resp, resp_len, rv, apdu); } #endif @@ -524,7 +524,7 @@ LOG_TEST_RET(ctx, r, "transmit APDU failed"); /* ok, the APDU was successfully transmitted. Now we have two special cases: - * 1. the card returned 0x6Cxx: in this case APDU will be re-trasmitted with Le set to SW2 + * 1. the card returned 0x6Cxx: in this case APDU will be re-transmitted with Le set to SW2 * (possible only if response buffer size is larger than new Le = SW2) */ if (apdu->sw1 == 0x6C && (apdu->flags & SC_APDU_FLAGS_NO_RETRY_WL) == 0) diff -Nru opensc-0.17.0/src/libopensc/asn1.c opensc-0.19.0/src/libopensc/asn1.c --- opensc-0.17.0/src/libopensc/asn1.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/asn1.c 2018-09-13 11:47:21.000000000 +0000 @@ -22,11 +22,12 @@ #include "config.h" #endif -#include -#include -#include #include +#include +#include +#include #include +#include #include "internal.h" #include "asn1.h" @@ -43,13 +44,13 @@ { static const char *tags[] = { "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */ - "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */ - "ENUMERATED", "", "UTF8STRING", "", /* 10-13 */ - "", "", "SEQUENCE", "SET", /* 15-17 */ - "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", /* 18-20 */ - "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", /* 21-24 */ - "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", /* 25-27 */ - "UNIVERSALSTRING", "", "BMPSTRING" /* 28-30 */ + "NULL", "OBJECT IDENTIFIER", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */ + "ENUMERATED", "Universal 11", "UTF8String", "Universal 13", /* 10-13 */ + "Universal 14", "Universal 15", "SEQUENCE", "SET", /* 15-17 */ + "NumericString", "PrintableString", "T61String", /* 18-20 */ + "VideotexString", "IA5String", "UTCTIME", "GENERALIZEDTIME", /* 21-24 */ + "GraphicString", "VisibleString", "GeneralString", /* 25-27 */ + "UniversalString", "Universal 29", "BMPString" /* 28-30 */ }; if (tag > 30) @@ -64,15 +65,17 @@ size_t left = buflen, len; unsigned int cla, tag, i; - if (left < 2) - return SC_ERROR_INVALID_ASN1_OBJECT; *buf = NULL; + + if (left == 0) + return SC_ERROR_INVALID_ASN1_OBJECT; if (*p == 0xff || *p == 0) { /* end of data reached */ *taglen = 0; *tag_out = SC_ASN1_TAG_EOC; return SC_SUCCESS; } + /* parse tag byte(s) * Resulted tag is presented by integer that has not to be * confused with the 'tag number' part of ASN.1 tag. @@ -85,39 +88,47 @@ /* high tag number */ size_t n = SC_ASN1_TAGNUM_SIZE - 1; /* search the last tag octet */ - while (left-- != 0 && n != 0) { + do { + if (left == 0 || n == 0) + /* either an invalid tag or it doesn't fit in + * unsigned int */ + return SC_ERROR_INVALID_ASN1_OBJECT; tag <<= 8; tag |= *p; - if ((*p++ & 0x80) == 0) - break; + p++; + left--; n--; - } - if (left == 0 || n == 0) - /* either an invalid tag or it doesn't fit in - * unsigned int */ - return SC_ERROR_INVALID_ASN1_OBJECT; + } while (tag & 0x80); } /* parse length byte(s) */ - len = *p & 0x7f; - if (*p++ & 0x80) { + if (left == 0) + return SC_ERROR_INVALID_ASN1_OBJECT; + len = *p; + p++; + left--; + if (len & 0x80) { + len &= 0x7f; unsigned int a = 0; - if (len > 4 || len > left) + if (len > sizeof a || len > left) return SC_ERROR_INVALID_ASN1_OBJECT; - left -= len; for (i = 0; i < len; i++) { a <<= 8; a |= *p; p++; + left--; } len = a; } - if (len > left) - return SC_ERROR_INVALID_ASN1_OBJECT; + *cla_out = cla; *tag_out = tag; *taglen = len; *buf = p; + + if (len > left) + return SC_ERROR_ASN1_END_OF_CONTENTS; + return SC_SUCCESS; } @@ -141,40 +152,81 @@ dest->name = NULL; } -static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen) +static void print_indent(size_t depth) { - size_t i; + for (; depth > 0; depth--) { + putchar(' '); + } +} + +static void print_hex(const u8 * buf, size_t buflen, size_t depth) +{ + size_t lines_len = buflen * 5 + 128; + char *lines = malloc(lines_len); + char *line = lines; + + if (buf == NULL || buflen == 0 || lines == NULL) { + free(lines); + return; + } + + sc_hex_dump(buf, buflen, lines, lines_len); - for (i = 0; i < buflen; i++) - printf("%02X", buf[i]); + while (*line != '\0') { + char *line_end = strchr(line, '\n'); + ptrdiff_t width = line_end - line; + if (!line_end || width <= 1) { + /* don't print empty lines */ + break; + } + if (buflen > 8) { + putchar('\n'); + print_indent(depth); + } else { + printf(": "); + } + printf("%.*s", (int) width, line); + line = line_end + 1; + } + + free(lines); } -static void sc_asn1_print_utf8string(const u8 * buf, size_t buflen) +static void print_ascii(const u8 * buf, size_t buflen) { - size_t i; + for (; 0 < buflen; buflen--, buf++) { + if (isprint(*buf)) + printf("%c", *buf); + else + putchar('.'); + } +} - for (i = 0; i < buflen; i++) - printf("%c", buf[i]); +static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen, size_t depth) +{ + print_hex(buf, buflen, depth); +} + +static void sc_asn1_print_utf8string(const u8 * buf, size_t buflen) +{ + /* FIXME UTF-8 is not ASCII */ + print_ascii(buf, buflen); } static void sc_asn1_print_integer(const u8 * buf, size_t buflen) { -#ifndef _WIN32 - long long a = 0; -#else - __int64 a = 0; -#endif - size_t i; + size_t a = 0; if (buflen > sizeof(a)) { - printf("too long"); - return; - } - for (i = 0; i < buflen; i++) { - a <<= 8; - a |= buf[i]; + printf("0x%s", sc_dump_hex(buf, buflen)); + } else { + size_t i; + for (i = 0; i < buflen; i++) { + a <<= 8; + a |= buf[i]; + } + printf("%"SC_FORMAT_LEN_SIZE_T"u", a); } - printf("%lld", a); } static void sc_asn1_print_boolean(const u8 * buf, size_t buflen) @@ -188,7 +240,7 @@ printf("false"); } -static void sc_asn1_print_bit_string(const u8 * buf, size_t buflen) +static void sc_asn1_print_bit_string(const u8 * buf, size_t buflen, size_t depth) { #ifndef _WIN32 long long a = 0; @@ -198,56 +250,120 @@ int r, i; if (buflen > sizeof(a) + 1) { - printf("too long"); - return; - } - r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a)); - if (r < 0) { - printf("decode error"); - return; + print_hex(buf, buflen, depth); + } else { + r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a)); + if (r < 0) { + printf("decode error"); + return; + } + for (i = r - 1; i >= 0; i--) { + printf("%c", ((a >> i) & 1) ? '1' : '0'); + } } - for (i = r - 1; i >= 0; i--) { - printf("%c", ((a >> i) & 1) ? '1' : '0'); +} + +#ifdef ENABLE_OPENSSL +#include + +static void openssl_print_object_sn(const char *s) +{ + ASN1_OBJECT *obj = OBJ_txt2obj(s, 0); + if (obj) { + int nid = OBJ_obj2nid(obj); + if (nid != NID_undef) { + printf(", %s", OBJ_nid2sn(nid)); + } + ASN1_OBJECT_free(obj); } } +#else +static void openssl_print_object_sn(const char *s) +{ +} +#endif static void sc_asn1_print_object_id(const u8 * buf, size_t buflen) { struct sc_object_id oid; - int i = 0; - char tmp[12]; - char sbuf[(sizeof tmp)*SC_MAX_OBJECT_ID_OCTETS]; + const char *sbuf; if (sc_asn1_decode_object_id(buf, buflen, &oid)) { printf("decode error"); return; } - sbuf[0] = 0; - for (i = 0; (i < SC_MAX_OBJECT_ID_OCTETS) && (oid.value[i] != -1); i++) { + sbuf = sc_dump_oid(&oid); + printf(" %s", sbuf); + openssl_print_object_sn(sbuf); +} - if (i) - strcat(sbuf, "."); - sprintf(tmp, "%d", oid.value[i]); - strcat(sbuf, tmp); +static void sc_asn1_print_utctime(const u8 * buf, size_t buflen) +{ + if (buflen < 8) { + printf("Error in decoding.\n"); + return; + } + + print_ascii(buf, 2); /* YY */ + putchar('-'); + print_ascii(buf+2, 2); /* MM */ + putchar('-'); + print_ascii(buf+4, 2); /* DD */ + putchar(' '); + print_ascii(buf+6, 2); /* hh */ + buf += 8; + buflen -= 8; + if (buflen >= 2 && isdigit(buf[0]) && isdigit(buf[1])) { + putchar(':'); + print_ascii(buf, 2); /* mm */ + buf += 2; + buflen -= 2; + } + if (buflen >= 2 && isdigit(buf[0]) && isdigit(buf[1])) { + putchar(':'); + print_ascii(buf, 2); /* ss */ + buf += 2; + buflen -= 2; + } + if (buflen >= 4 && '.' == buf[0]) { + print_ascii(buf, 4); /* fff */ + buf += 4; + buflen -= 4; + } + + if (buflen >= 1 && 'Z' == buf[0]) { + printf(" UTC"); + } else if (buflen >= 5 && ('-' == buf[0] || '+' == buf[0])) { + putchar(' '); + print_ascii(buf, 3); /* +/-hh */ + putchar(':'); + print_ascii(buf+3, 2); /* mm */ } - printf("%s", sbuf); } static void sc_asn1_print_generalizedtime(const u8 * buf, size_t buflen) { - size_t ii; - for (ii=0; ii> 8*i)) + break; + } + printf("%02X", cla<<(i-1)*8 | tag); + + if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL) { + printf(" %s", tag2str(tag)); + } else { + printf(" %s %-2u", + classes[cla >> 6], + i == 1 ? tag & SC_ASN1_TAG_PRIMITIVE : tag & (((unsigned int) ~0) >> (i + 1) * 8)); + } + if (!((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL + && tag == SC_ASN1_TAG_NULL && len == 0)) { + printf(" (%"SC_FORMAT_LEN_SIZE_T"u byte%s)", + len, + len != 1 ? "s" : ""); } - printf("%02X %s: tag 0x%02X, length %3d: ", - cla | tag, classes[cla >> 6], tag & 0x1f, (int) len); + if (len + hlen > bytesleft) { printf(" Illegal length!\n"); return; } p += hlen + len; bytesleft -= hlen + len; - if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL) - printf("%s", tag2str(tag)); if (cla & SC_ASN1_TAG_CONSTRUCTED) { putchar('\n'); - print_tags_recursive(buf0, tagp, len, depth + 1); + print_tags_recursive(buf0, tagp, len, depth + 2*i + 1); continue; } - if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL) { - printf(" ["); - switch (tag) { + + switch (tag) { case SC_ASN1_TAG_BIT_STRING: - sc_asn1_print_bit_string(tagp, len); + printf(": "); + sc_asn1_print_bit_string(tagp, len, depth + 2*i + 1); break; case SC_ASN1_TAG_OCTET_STRING: - sc_asn1_print_octet_string(tagp, len); + sc_asn1_print_octet_string(tagp, len, depth + 2*i + 1); break; case SC_ASN1_TAG_OBJECT: + printf(": "); sc_asn1_print_object_id(tagp, len); break; case SC_ASN1_TAG_INTEGER: case SC_ASN1_TAG_ENUMERATED: + printf(": "); sc_asn1_print_integer(tagp, len); break; - case SC_ASN1_TAG_T61STRING: + case SC_ASN1_TAG_IA5STRING: case SC_ASN1_TAG_PRINTABLESTRING: + case SC_ASN1_TAG_T61STRING: case SC_ASN1_TAG_UTF8STRING: + printf(": "); sc_asn1_print_utf8string(tagp, len); break; case SC_ASN1_TAG_BOOLEAN: + printf(": "); sc_asn1_print_boolean(tagp, len); break; case SC_ASN1_GENERALIZEDTIME: + printf(": "); sc_asn1_print_generalizedtime(tagp, len); break; - } - printf("]"); + case SC_ASN1_UTCTIME: + printf(": "); + sc_asn1_print_utctime(tagp, len); + break; } - if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_APPLICATION) - printf(" [%s]", sc_dump_hex(tagp, len)); + if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_APPLICATION) { + print_hex(tagp, len, depth + 2*i + 1); + } - if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_CONTEXT) - printf(" [%s]", sc_dump_hex(tagp, len)); + if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_CONTEXT) { + print_hex(tagp, len, depth + 2*i + 1); + } putchar('\n'); } - return; } void sc_asn1_print_tags(const u8 * buf, size_t buflen) { - printf("Printing tags for buffer of length %d\n", (int) buflen); print_tags_recursive(buf, buf, buflen, 0); } @@ -342,16 +480,14 @@ *taglen_in = 0; while (left >= 2) { - unsigned int cla, tag, mask = 0xff00; + unsigned int cla = 0, tag, mask = 0xff00; buf = p; /* read a tag */ - if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS) - return NULL; - if (left < (size_t)(p - buf)) { - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "invalid TLV object\n"); + if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS + || p == NULL) return NULL; - } + left -= (p - buf); /* we need to shift the class byte to the leftmost * byte of the tag */ @@ -368,10 +504,6 @@ return p; } /* otherwise continue reading tags */ - if (left < taglen) { - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "invalid TLV object\n"); - return NULL; - } left -= taglen; p += taglen; } @@ -383,9 +515,10 @@ { const u8 *p = *buf; size_t len = *buflen, taglen; - unsigned int cla, tag; + unsigned int cla = 0, tag; - if (sc_asn1_read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != SC_SUCCESS) + if (sc_asn1_read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != SC_SUCCESS + || p == NULL) return NULL; switch (cla & 0xC0) { case SC_ASN1_TAG_UNIVERSAL: @@ -574,7 +707,7 @@ int a = 0; size_t i; - if (inlen > sizeof(int)) + if (inlen > sizeof(int) || inlen == 0) return SC_ERROR_INVALID_ASN1_OBJECT; if (inbuf[0] & 0x80) a = -1; @@ -1614,44 +1747,56 @@ break; case SC_ASN1_BIT_STRING_NI: case SC_ASN1_BIT_STRING: - assert(len != NULL); - if (entry->type == SC_ASN1_BIT_STRING) - r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 1); - else - r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 0); + if (len != NULL) { + if (entry->type == SC_ASN1_BIT_STRING) + r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 1); + else + r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 0); + } else { + r = SC_ERROR_INVALID_ARGUMENTS; + } break; case SC_ASN1_BIT_FIELD: - assert(len != NULL); - r = encode_bit_field((const u8 *) parm, *len, &buf, &buflen); + if (len != NULL) { + r = encode_bit_field((const u8 *) parm, *len, &buf, &buflen); + } else { + r = SC_ERROR_INVALID_ARGUMENTS; + } break; case SC_ASN1_PRINTABLESTRING: case SC_ASN1_OCTET_STRING: case SC_ASN1_UTF8STRING: - assert(len != NULL); - buf = malloc(*len + 1); - if (buf == NULL) { - r = SC_ERROR_OUT_OF_MEMORY; - break; - } - buflen = 0; - /* If the integer is supposed to be unsigned, insert - * a padding byte if the MSB is one */ - if ((entry->flags & SC_ASN1_UNSIGNED) - && (((u8 *) parm)[0] & 0x80)) { - buf[buflen++] = 0x00; + if (len != NULL) { + buf = malloc(*len + 1); + if (buf == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + break; + } + buflen = 0; + /* If the integer is supposed to be unsigned, insert + * a padding byte if the MSB is one */ + if ((entry->flags & SC_ASN1_UNSIGNED) + && (((u8 *) parm)[0] & 0x80)) { + buf[buflen++] = 0x00; + } + memcpy(buf + buflen, parm, *len); + buflen += *len; + } else { + r = SC_ERROR_INVALID_ARGUMENTS; } - memcpy(buf + buflen, parm, *len); - buflen += *len; break; case SC_ASN1_GENERALIZEDTIME: - assert(len != NULL); - buf = malloc(*len); - if (buf == NULL) { - r = SC_ERROR_OUT_OF_MEMORY; - break; + if (len != NULL) { + buf = malloc(*len); + if (buf == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + break; + } + memcpy(buf, parm, *len); + buflen = *len; + } else { + r = SC_ERROR_INVALID_ARGUMENTS; } - memcpy(buf, parm, *len); - buflen = *len; break; case SC_ASN1_OBJECT: r = sc_asn1_encode_object_id(&buf, &buflen, (struct sc_object_id *) parm); diff -Nru opensc-0.17.0/src/libopensc/aux-data.h opensc-0.19.0/src/libopensc/aux-data.h --- opensc-0.17.0/src/libopensc/aux-data.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/aux-data.h 2018-09-13 11:47:21.000000000 +0000 @@ -1,6 +1,6 @@ /* * aux-data.h: Non PKCS#15, non ISO7816 data - * Used to pass auxiliary data from non PKCS#15, non ISO7816 appliations (like minidriver) + * Used to pass auxiliary data from non PKCS#15, non ISO7816 applications (like minidriver) * to card specific part through the standard PKCS#15 and ISO7816 frameworks * * Copyright (C) 2016 Viktor Tarasov diff -Nru opensc-0.17.0/src/libopensc/card-acos5.c opensc-0.19.0/src/libopensc/card-acos5.c --- opensc-0.17.0/src/libopensc/card-acos5.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-acos5.c 2018-09-13 11:47:21.000000000 +0000 @@ -27,7 +27,7 @@ #include "internal.h" #include "cardctl.h" -static struct sc_atr_table acos5_atrs[] = { +static const struct sc_atr_table acos5_atrs[] = { {"3b:be:96:00:00:41:05:20:00:00:00:00:00:00:00:00:00:90:00", NULL, NULL, SC_CARD_TYPE_ACOS5_GENERIC, 0, NULL}, {"3b:be:18:00:00:41:05:10:00:00:00:00:00:00:00:00:00:90:00", NULL, NULL, @@ -181,7 +181,7 @@ /* * Use CARD GET INFO to fetch the number of files under the - * curently selected DF. + * currently selected DF. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x14, 0x01, 0x00); apdu.cla |= 0x80; diff -Nru opensc-0.17.0/src/libopensc/card-akis.c opensc-0.19.0/src/libopensc/card-akis.c --- opensc-0.17.0/src/libopensc/card-akis.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-akis.c 2018-09-13 11:47:21.000000000 +0000 @@ -43,7 +43,7 @@ NULL, 0, NULL }; -static struct sc_atr_table akis_atrs[] = { +static const struct sc_atr_table akis_atrs[] = { { "3b:ba:11:00:81:31:fe:4d:55:45:4b:41:45:20:56:31:2e:30:ae", NULL, NULL, SC_CARD_TYPE_AKIS_GENERIC, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; diff -Nru opensc-0.17.0/src/libopensc/card-asepcos.c opensc-0.19.0/src/libopensc/card-asepcos.c --- opensc-0.17.0/src/libopensc/card-asepcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-asepcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -37,7 +37,7 @@ NULL, 0, NULL }; -static struct sc_atr_table asepcos_atrs[] = { +static const struct sc_atr_table asepcos_atrs[] = { { "3b:d6:18:00:81:b1:80:7d:1f:03:80:51:00:61:10:30:8f", NULL, NULL, SC_CARD_TYPE_ASEPCOS_GENERIC, 0, NULL}, { "3b:d6:18:00:81:b1:fe:7d:1f:03:41:53:45:37:35:35:01", NULL, NULL, SC_CARD_TYPE_ASEPCOS_JAVA, 0, NULL}, { NULL, NULL, NULL, 0, 0, NULL } @@ -83,7 +83,7 @@ if (card->type == SC_CARD_TYPE_ASEPCOS_JAVA) { int r = asepcos_select_asepcos_applet(card); if (r != SC_SUCCESS) - return r; + return SC_ERROR_INVALID_CARD; } /* Set up algorithm info. */ @@ -140,7 +140,7 @@ { const amode_entry_t *table; - /* CHV with reference '0' is the trasport PIN + /* CHV with reference '0' is the transport PIN * and is presented as 'AUT' key with reference '0'*/ if (meth == SC_AC_CHV && ac == 0) meth = SC_AC_AUT; @@ -169,7 +169,7 @@ while (len != 0) { unsigned int amode, tlen = 3; - if (len < 5 && p[0] != 0x80 && p[1] != 0x01) { + if (len < 5 || p[0] != 0x80 || p[1] != 0x01) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "invalid access mode encoding"); return SC_ERROR_INTERNAL; } @@ -377,7 +377,7 @@ u8 buf[64], *p; int r = SC_SUCCESS; - /* first check wether the security attributes in encoded form + /* first check whether the security attributes in encoded form * are already set. If present use these */ if (file->sec_attr != NULL && file->sec_attr_len != 0) return asepcos_set_sec_attributes(card, file->sec_attr, @@ -420,7 +420,7 @@ *p++ = (st.fileid >> 8 ) & 0xff; *p++ = st.fileid & 0xff; } else { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unknow auth method: '%d'", ent->method); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unknown auth method: '%d'", ent->method); return SC_ERROR_INTERNAL; } } @@ -746,7 +746,7 @@ buf[0] = path->value[path->len-2]; buf[1] = path->value[path->len-1]; } else { - /* presumedly a DF */ + /* presumably a DF */ atype = SC_APDU_CASE_1; ftype = 0x00; } @@ -971,7 +971,6 @@ } if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) { /* unable to verify the old PIN */ - r = sc_check_sw(card, apdu.sw1, apdu.sw2); break; } /* 2, step: use CHANGE KEY to update the PIN */ @@ -981,7 +980,6 @@ r = sc_transmit_apdu(card, &apdu); if (r != SC_SUCCESS) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "APDU transmit failed"); - r = sc_check_sw(card, apdu.sw1, apdu.sw2); break; case SC_PIN_CMD_UNBLOCK: if (pdata->pin_type != SC_AC_CHV) @@ -1008,21 +1006,39 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "APDU transmit failed"); break; } - r = sc_check_sw(card, apdu.sw1, apdu.sw2); break; default: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "error: unknow cmd type"); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "error: unknown cmd type"); return SC_ERROR_INTERNAL; } /* Clear the buffer - it may contain pins */ sc_mem_clear(sbuf, sizeof(sbuf)); /* check for remaining tries if verification failed */ - if (apdu.sw1 == 0x63) { - if ((apdu.sw2 & 0xF0) == 0xC0 && tries_left != NULL) - *tries_left = apdu.sw2 & 0x0F; - return SC_ERROR_PIN_CODE_INCORRECT; + if (r == SC_SUCCESS) { + if (apdu.sw1 == 0x63) { + if ((apdu.sw2 & 0xF0) == 0xC0 && tries_left != NULL) + *tries_left = apdu.sw2 & 0x0F; + r = SC_ERROR_PIN_CODE_INCORRECT; + return r; + } + r = sc_check_sw(card, apdu.sw1, apdu.sw2); } - return sc_check_sw(card, apdu.sw1, apdu.sw2); + + return r; +} + +static int asepcos_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0 && card->type == SC_CARD_TYPE_ASEPCOS_JAVA) { + /* in case of a Java card try to select the ASEPCOS applet */ + r = asepcos_select_asepcos_applet(card); + } + + LOG_FUNC_RETURN(card->ctx, r); } static struct sc_card_driver * sc_get_driver(void) @@ -1041,6 +1057,7 @@ asepcos_ops.list_files = asepcos_list_files; asepcos_ops.card_ctl = asepcos_card_ctl; asepcos_ops.pin_cmd = asepcos_pin_cmd; + asepcos_ops.card_reader_lock_obtained = asepcos_card_reader_lock_obtained; return &asepcos_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-atrust-acos.c opensc-0.19.0/src/libopensc/card-atrust-acos.c --- opensc-0.17.0/src/libopensc/card-atrust-acos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-atrust-acos.c 2018-09-13 11:47:21.000000000 +0000 @@ -467,7 +467,7 @@ if ( card->cache.valid && bMatch >= 0 ) { if ( pathlen - bMatch == 2 ) - /* we are in the rigth directory */ + /* we are in the right directory */ return atrust_acos_select_fid(card, path[bMatch], path[bMatch+1], file_out); else if ( pathlen - bMatch > 2 ) { @@ -551,7 +551,7 @@ /* copy key reference, if present */ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; diff -Nru opensc-0.17.0/src/libopensc/card-authentic.c opensc-0.19.0/src/libopensc/card-authentic.c --- opensc-0.17.0/src/libopensc/card-authentic.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-authentic.c 2018-09-13 11:47:21.000000000 +0000 @@ -80,7 +80,7 @@ struct sc_cplc cplc; }; -static struct sc_atr_table authentic_known_atrs[] = { +static const struct sc_atr_table authentic_known_atrs[] = { { "3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:00:70:0A:90:00:8B", NULL, "Oberthur AuthentIC 3.2.2", SC_CARD_TYPE_OBERTHUR_AUTHENTIC_3_2, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } @@ -413,7 +413,7 @@ struct sc_context *ctx = card->ctx; int i; - sc_log(ctx, "try to match card with ATR %s", sc_dump_hex(card->atr.value, card->atr.len)); + sc_log_hex(ctx, "try to match card with ATR", card->atr.value, card->atr.len); i = _sc_match_atr(card, authentic_known_atrs, &card->type); if (i < 0) { sc_log(ctx, "card not matched"); @@ -463,7 +463,7 @@ authentic_init(struct sc_card *card) { struct sc_context *ctx = card->ctx; - int ii, rv = SC_ERROR_NO_CARD_SUPPORT; + int ii, rv = SC_ERROR_INVALID_CARD; LOG_FUNC_CALLED(ctx); for(ii=0;authentic_known_atrs[ii].atr;ii++) { @@ -475,7 +475,7 @@ } if (!authentic_known_atrs[ii].atr) - LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_CARD); card->cla = 0x00; card->drv_data = (struct authentic_private_data *) calloc(sizeof(struct authentic_private_data), 1); @@ -485,13 +485,15 @@ if (card->type == SC_CARD_TYPE_OBERTHUR_AUTHENTIC_3_2) rv = authentic_init_oberthur_authentic_3_2(card); - if (!rv) + if (rv != SC_SUCCESS) rv = authentic_get_serialnr(card, NULL); + if (rv != SC_SUCCESS) + rv = SC_ERROR_INVALID_CARD; + LOG_FUNC_RETURN(ctx, rv); } - static int authentic_erase_binary(struct sc_card *card, unsigned int offs, size_t count, unsigned long flags) { @@ -558,6 +560,9 @@ sc_file_dup(&card->cache.current_df, file); if (cur_df_path.len) { + if (cur_df_path.len + card->cache.current_df->path.len > sizeof card->cache.current_df->path.value + || cur_df_path.len > sizeof card->cache.current_df->path.value) + LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); memcpy(card->cache.current_df->path.value + cur_df_path.len, card->cache.current_df->path.value, card->cache.current_df->path.len); @@ -807,96 +812,46 @@ LOG_FUNC_RETURN(ctx, SC_SUCCESS); } - -static int -authentic_apdus_allocate(struct sc_apdu **head, struct sc_apdu **new) -{ - struct sc_apdu *allocated_apdu = NULL, *tmp_apdu = NULL; - - if (!head) - return SC_ERROR_INVALID_ARGUMENTS; - - allocated_apdu = calloc(1, sizeof(struct sc_apdu)); - if (!allocated_apdu) - return SC_ERROR_OUT_OF_MEMORY; - - if (*head == NULL) - *head = allocated_apdu; - - if (new) - *new = allocated_apdu; - - tmp_apdu = *head; - while(tmp_apdu->next) - tmp_apdu = tmp_apdu->next; - - tmp_apdu->next = allocated_apdu; - - return 0; -} - - -static void -authentic_apdus_free(struct sc_apdu *apdu) -{ - while(apdu) { - struct sc_apdu *tmp_apdu = apdu->next; - free(apdu); - apdu = tmp_apdu; - } -} - - static int authentic_read_binary(struct sc_card *card, unsigned int idx, unsigned char *buf, size_t count, unsigned long flags) { struct sc_context *ctx = card->ctx; - struct sc_apdu *apdus = NULL, *cur_apdu = NULL; - size_t sz, rest; - int rv; + struct sc_apdu apdu; + size_t sz, rest, ret_count = 0; + int rv = SC_SUCCESS; LOG_FUNC_CALLED(ctx); sc_log(ctx, "offs:%i,count:%"SC_FORMAT_LEN_SIZE_T"u,max_recv_size:%"SC_FORMAT_LEN_SIZE_T"u", idx, count, card->max_recv_size); - /* Data size more then 256 bytes can happen when card reader is - * configurated with max_send/recv_size more then 255/256 bytes - * (for ex. 'remote-access' reader) . - * In this case create chained 'read-binary' APDUs. - */ - sc_log(ctx, "reader flags 0x%lX", card->reader->flags); - if (count > 256 && !(card->reader->flags & SC_READER_HAS_WAITING_AREA)) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Invalid size of the data to read"); - rest = count; while(rest) { - if (authentic_apdus_allocate(&apdus, &cur_apdu)) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cannot allocate APDU"); - sz = rest > 256 ? 256 : rest; - sc_format_apdu(card, cur_apdu, SC_APDU_CASE_2_SHORT, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF); - cur_apdu->le = sz; - cur_apdu->resplen = count; - cur_apdu->resp = buf; + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF); + apdu.le = sz; + apdu.resplen = sz; + apdu.resp = (buf + ret_count); + + rv = sc_transmit_apdu(card, &apdu); + if(!rv) + ret_count += apdu.resplen; + else + break; idx += sz; rest -= sz; } - if (!apdus) { + if (rv) { LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "authentic_read_binary() failed"); LOG_FUNC_RETURN(ctx, count); } - rv = sc_transmit_apdu(card, apdus); - if (!rv) - rv = sc_check_sw(card, apdus->sw1, apdus->sw2); + rv = sc_check_sw(card, apdu.sw1, apdu.sw2); if (!rv) - count = apdus->resplen; - - authentic_apdus_free(apdus); + count = ret_count; LOG_TEST_RET(ctx, rv, "authentic_read_binary() failed"); LOG_FUNC_RETURN(ctx, count); @@ -908,46 +863,38 @@ const unsigned char *buf, size_t count, unsigned long flags) { struct sc_context *ctx = card->ctx; - struct sc_apdu *apdus = NULL, *cur_apdu = NULL; + struct sc_apdu apdu; size_t sz, rest; - int rv; + int rv = SC_SUCCESS; LOG_FUNC_CALLED(ctx); sc_log(ctx, "offs:%i,count:%"SC_FORMAT_LEN_SIZE_T"u,max_send_size:%"SC_FORMAT_LEN_SIZE_T"u", idx, count, card->max_send_size); - /* see comments for authentic_read_binary() */ - sc_log(ctx, "reader flags 0x%lX", card->reader->flags); - if (count > 255 && !(card->reader->flags & SC_READER_HAS_WAITING_AREA)) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Invalid size of the data to read"); - rest = count; while(rest) { - if (authentic_apdus_allocate(&apdus, &cur_apdu)) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cannot allocate APDU"); - sz = rest > 255 ? 255 : rest; - sc_format_apdu(card, cur_apdu, SC_APDU_CASE_3_SHORT, 0xD0, (idx >> 8) & 0x7F, idx & 0xFF); - cur_apdu->lc = sz; - cur_apdu->datalen = sz; - cur_apdu->data = buf + count - rest; + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD0, (idx >> 8) & 0x7F, idx & 0xFF); + apdu.lc = sz; + apdu.datalen = sz; + apdu.data = buf + count - rest; + + rv = sc_transmit_apdu(card, &apdu); + if(rv) + break; idx += sz; rest -= sz; } - if (!apdus) + if (rv) { LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "authentic_write_binary() failed"); LOG_FUNC_RETURN(ctx, count); } - rv = sc_transmit_apdu(card, apdus); - if (!rv) - rv = sc_check_sw(card, apdus->sw1, apdus->sw2); - - authentic_apdus_free(apdus); + rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "authentic_write_binary() failed"); LOG_FUNC_RETURN(ctx, count); @@ -959,46 +906,38 @@ const unsigned char *buf, size_t count, unsigned long flags) { struct sc_context *ctx = card->ctx; - struct sc_apdu *apdus = NULL, *cur_apdu = NULL; + struct sc_apdu apdu; size_t sz, rest; - int rv; + int rv = SC_SUCCESS; LOG_FUNC_CALLED(ctx); sc_log(ctx, "offs:%i,count:%"SC_FORMAT_LEN_SIZE_T"u,max_send_size:%"SC_FORMAT_LEN_SIZE_T"u", idx, count, card->max_send_size); - /* see comments for authentic_read_binary() */ - sc_log(ctx, "reader flags 0x%lX", card->reader->flags); - if (count > 255 && !(card->reader->flags & SC_READER_HAS_WAITING_AREA)) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Invalid size of the data to read"); - rest = count; while(rest) { - if (authentic_apdus_allocate(&apdus, &cur_apdu)) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cannot allocate APDU"); - sz = rest > 255 ? 255 : rest; - sc_format_apdu(card, cur_apdu, SC_APDU_CASE_3_SHORT, 0xD6, (idx >> 8) & 0x7F, idx & 0xFF); - cur_apdu->lc = sz; - cur_apdu->datalen = sz; - cur_apdu->data = buf + count - rest; + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, (idx >> 8) & 0x7F, idx & 0xFF); + apdu.lc = sz; + apdu.datalen = sz; + apdu.data = buf + count - rest; + + rv = sc_transmit_apdu(card, &apdu); + if(rv) + break; idx += sz; rest -= sz; } - if (!apdus) + if (rv) { LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "authentic_update_binary() failed"); LOG_FUNC_RETURN(ctx, count); } - rv = sc_transmit_apdu(card, apdus); - if (!rv) - rv = sc_check_sw(card, apdus->sw1, apdus->sw2); - - authentic_apdus_free(apdus); + rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "authentic_update_binary() failed"); LOG_FUNC_RETURN(ctx, count); @@ -1041,9 +980,7 @@ LOG_TEST_RET(ctx, rv, "ISO parse FCI failed"); if (!file->sec_attr_len) { - sc_log(ctx, - "ACLs not found in data(%"SC_FORMAT_LEN_SIZE_T"u) %s", - buflen, sc_dump_hex(buf, buflen)); + sc_log_hex(ctx, "ACLs not found in data", buf, buflen); sc_log(ctx, "Path:%s; Type:%X; PathType:%X", sc_print_path(&file->path), file->type, file->path.type); if (file->path.type == SC_PATH_TYPE_DF_NAME || file->type == SC_FILE_TYPE_DF) { file->type = SC_FILE_TYPE_DF; @@ -1053,9 +990,8 @@ } } - sc_log(ctx, "ACL data(%"SC_FORMAT_LEN_SIZE_T"u):%s", file->sec_attr_len, - sc_dump_hex(file->sec_attr, file->sec_attr_len)); - for (ii = 0; ii < file->sec_attr_len / 2; ii++) { + sc_log_hex(ctx, "ACL data", file->sec_attr, file->sec_attr_len); + for (ii = 0; ii < file->sec_attr_len / 2 && ii < sizeof ops_DF; ii++) { unsigned char op = file->type == SC_FILE_TYPE_DF ? ops_DF[ii] : ops_EF[ii]; unsigned char acl = *(file->sec_attr + ii*2); unsigned char cred_id = *(file->sec_attr + ii*2 + 1); @@ -1731,40 +1667,27 @@ } -/* 'GET CHALLENGE' returns always 24 bytes */ static int authentic_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len) { - struct sc_context *ctx = card->ctx; - struct sc_apdu apdu; + /* 'GET CHALLENGE' returns always 24 bytes */ unsigned char rbuf[0x18]; - int rv, nn; - - LOG_FUNC_CALLED(ctx); - if (!rnd && len) - return SC_ERROR_INVALID_ARGUMENTS; - - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = sizeof(rbuf); + size_t out_len; + int r; - while (len > 0) { - rv = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed"); - rv = sc_check_sw(card, apdu.sw1, apdu.sw2); - LOG_TEST_RET(ctx, rv, "PIN cmd failed"); + LOG_FUNC_CALLED(card->ctx); - if (apdu.resplen != sizeof(rbuf)) - return sc_check_sw(card, apdu.sw1, apdu.sw2); + r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); - nn = len > apdu.resplen ? apdu.resplen : len; - memcpy(rnd, apdu.resp, nn); - len -= nn; - rnd += nn; + if (len < (size_t) r) { + out_len = len; + } else { + out_len = (size_t) r; } + memcpy(rnd, rbuf, out_len); - LOG_FUNC_RETURN(ctx, SC_SUCCESS); + LOG_FUNC_RETURN(card->ctx, out_len); } @@ -1908,7 +1831,7 @@ free(data); - sc_log(ctx, "encoded SDO operation data %s", sc_dump_hex(*out, *out_len)); + sc_log_hex(ctx, "encoded SDO operation data", *out, *out_len); LOG_FUNC_RETURN(ctx, rv); } @@ -2118,6 +2041,21 @@ } +static int authentic_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0 + && card->type == SC_CARD_TYPE_OBERTHUR_AUTHENTIC_3_2) { + r = authentic_select_aid(card, aid_AuthentIC_3_2, sizeof(aid_AuthentIC_3_2), NULL, NULL); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + /* SM related */ #ifdef ENABLE_SM static int @@ -2252,7 +2190,7 @@ if (plain) { if (plain->resplen < (*sm_apdu)->resplen) - LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Unsufficient plain APDU response size"); + LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Insufficient plain APDU response size"); memcpy(plain->resp, (*sm_apdu)->resp, (*sm_apdu)->resplen); plain->resplen = (*sm_apdu)->resplen; plain->sw1 = (*sm_apdu)->sw1; @@ -2370,6 +2308,7 @@ authentic_ops.card_ctl = authentic_card_ctl; authentic_ops.process_fci = authentic_process_fci; authentic_ops.pin_cmd = authentic_pin_cmd; + authentic_ops.card_reader_lock_obtained = authentic_card_reader_lock_obtained; return &authentic_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-belpic.c opensc-0.19.0/src/libopensc/card-belpic.c --- opensc-0.17.0/src/libopensc/card-belpic.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-belpic.c 2018-09-13 11:47:21.000000000 +0000 @@ -20,14 +20,14 @@ /* About the Belpic (Belgian Personal Identity Card) card * - * The Belpic card is a Cyberflex Java card, so you normaly communicate + * The Belpic card is a Cyberflex Java card, so you normally communicate * with an applet running on the card. In order to support a pkcs15 file * structure, an applet (the Belpic applet) has been build that emulates * this. So the card's behaviour is specific for this Belpic applet, that's * why a separate driver has been made. * * The card contains the citizen's ID data (name, address, photo, ...) and - * her keys and certs. The ID data are in a seperate directory on the card and + * her keys and certs. The ID data are in a separate directory on the card and * are not handled by this software. For the cryptographic data (keys and certs) * a pkcs#15 structure has been chosen and they can be accessed and used * by the OpenSC software. @@ -35,20 +35,20 @@ * The current situation about the cryptographic data is: there is 1 PIN * that protects 2 private keys and corresponding certs. Then there is a * CA cert and the root cert. The first key (Auth Key) can be used for - * authentication, the second one (NonRep Key) for non repudation purposes + * authentication, the second one (NonRep Key) for non repudiation purposes * (so it can be used as an alternative to manual signatures). * * There are some special things to note, which all have some consequences: * (1) the SELECT FILE command doesn't return any FCI (file length, type, ...) * (2) the NonRep key needs a VERIFY PIN before a signature can be done with it - * (3) pin pad readers had to be supported by a proprietory interface (as at - * that moment no other solution was known/avaiable/ready) + * (3) pin pad readers had to be supported by a proprietary interface (as at + * that moment no other solution was known/available/ready) * The consequences are: * * For (1): we let the SELECT FILE command return that the file length is - * a fixed large number and that each file is a transparant working EF + * a fixed large number and that each file is a transparent working EF * (except the root dir 3F 00). This way however, there is a problem with the - * sc_read_binary() function that will only stop reading untill it receivces + * sc_read_binary() function that will only stop reading until it receives * a 0. Therefore, we use the 'next_idx' trick. Or, if that might fail * and so a READ BINARY past the end of file is done, length 0 is returned * instead of an error code. @@ -58,11 +58,11 @@ * causes other problems and is less user-friendly). A GUI being popped up * by the pkcs11 lib before each NonRep signature has another important * security advantage: applications that cache the PIN can't silently do - * a NonRep signature because there will allways be the GUI. + * a NonRep signature because there will always be the GUI. * * For (3), we link dynamically against a pin pad lib (DLL) that implements the - * proprietory API for a specific pin pad. For each pin pad reader (identified - * by it's PC/SC reader name), a pin pad lib correspondends. Some reader/lib + * proprietary API for a specific pin pad. For each pin pad reader (identified + * by it's PC/SC reader name), a pin pad lib corresponds. Some reader/lib * name pairs are hardcoded, and others can be added in the config file. * Note that there's also a GUI used in this case: if a signature with the * NonRep key is done: a dialog box is shown that asks the user to enter @@ -90,27 +90,6 @@ #include "internal.h" #include "log.h" -#ifdef BELPIC_PIN_PAD -#ifndef HAVE_GUI -#define HAVE_GUI -#endif -#endif - -#ifdef BELPIC_PIN_PAD -#include "winscard.h" -#include "scr.h" -#endif - -#ifdef HAVE_GUI -#include "scgui.h" -#ifndef SCR_USAGE_SIGN -#define SCR_USAGE_SIGN 2 /* in scr.h */ -#endif -#ifndef SCR_USAGE_AUTH -#define SCR_USAGE_AUTH 1 -#endif -#endif - /* To be removed */ #include static long t1, t2, tot_read = 0, tot_dur = 0, dur; @@ -166,7 +145,7 @@ /* Used for a trick in select file and read binary */ static size_t next_idx = (size_t)-1; -static struct sc_atr_table belpic_atrs[] = { +static const struct sc_atr_table belpic_atrs[] = { /* Applet V1.1 */ { "3B:98:13:40:0A:A5:03:01:01:01:AD:13:11", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL }, /* Applet V1.0 with new EMV-compatible ATR */ @@ -176,26 +155,6 @@ { NULL, NULL, NULL, 0, 0, NULL } }; -struct belpic_priv_data { - int lang; - int options; -#ifdef BELPIC_PIN_PAD - FARPROC scr_init; - FARPROC scr_verify_pin; - FARPROC scr_change_pin; - char szPinPadDll[64]; -#endif -}; - -#define DRVDATA(card) ((struct belpic_priv_data *) ((card)->drv_data)) - -/* Single Sign On */ -#ifdef HAVE_ALLOW_SSO -#define SSO_OK(drv) ((drv)->allow_sso) -#else -#define SSO_OK(drv) 0 -#endif - static struct sc_card_operations belpic_ops; static struct sc_card_driver belpic_drv = { "Belpic cards", @@ -205,414 +164,6 @@ }; static const struct sc_card_operations *iso_ops = NULL; -#define LNG_ENG 0 -#define LNG_DUTCH 1 -#define LNG_FRENCH 2 -#define LNG_GERMAN 3 -#define LNG_NONE 0xFFFF - -#ifdef BELPIC_PIN_PAD - -/* Option flags from the config file */ -#define PP_MSG_AUTH_PIN 0x00000001 -#define PP_MSG_WRONG_PIN 0x00000002 -#define PP_MSG_CHANGEPIN_MISMATCH 0x00000004 -#define PP_MSG_PIN_BLOCKED 0x00000008 - -/* Hardcoded pin pad reader names (PC/SC) and their pin pad lib */ -static char *pp_reader_names[] = { - "Xiring X Pass Serial", - NULL -}; -static char *pp_reader_libs[] = { - "xireid", - NULL -}; - -static BYTE aid_belpic[] = { 0xA0, 0x00, 0x00, 0x01, 0x77, 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 }; -static SCR_Application scr_app_belpic = { - {aid_belpic, sizeof(aid_belpic)}, - "ID", - NULL -}; -static char *app_id_longstr[] = { - "Identity", - "Identiteit", - "Identit", - "Identitt" -}; -#endif /* BELPIC_PIN_PAD */ - -#if defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) -static char *pin_usg_sig[] = { - "Signature", - "Handtekening", - "Signature", - "Signatur" -}; -static char *pin_usg_auth[] = { - "Authentication", - "Authentificatie", - "Authentification", - "Authentifizierung" -}; -#endif /* defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) */ - -#ifdef BELPIC_PIN_PAD -static char *lang_codes[4] = { - "en", - "nl", - "fr", - "de" -}; -static char *pp_msg_auth_sh[] = { - "Authentication", - "Authentificatie", - "Authentification", - "Kennzeichnung" -}; -static char *pp_msg_auth[] = { - "Enter your PIN on the reader, in order to authenticate yourself", - "Geef uw PIN in op de lezer, om u te authentificeren", - "Entrez votre PIN sur le lecteur, pour vous authentifier", - "Bitte geben Sie Ihre PIN am Kartenlesegert ein, um sich zu authentifizieren" -}; -static char *pp_msg_sign_sh[] = { - "Signature", - "Handtekening", - "Signature", - "Signatur" -}; -static char *pp_msg_sign[] = { - "Caution: You are about to make a legally binding electronic signature with your identity card.\nPlease enter your PIN on the card reader to continue or click the Cancel button.\n\nIf you only want to log on to a web site or server, do NOT enter your PIN and click the Cancel button.", - "Let op: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart.\nGeef uw PIN in op de kaartlezer om verder te gaan of klik op Stoppen.\n\nAls u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.", - "Attention: vous allez apposer une signature lectronique juridiquement valide avec votre carte d'identit.\nVeuillez entrer votre PIN sur le lecteur externe pour continuer ou cliquez sur Annuler.\n\nSi vous dsirez seulement vous connecter un site ou un serveur, n'entrez PAS votre PIN et cliquez sur Annuler.", - "Achtung: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen.\nBitte geben Sie Ihre PIN am Kartenlesgert ein zum weitergehen oder klicken Sie auf Abbrechen.\n\nWenn Sie nur auf das Internet gehen mchten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen." -}; -static char *pp_msg_change_sh[] = { - "PIN change", - "PIN verandering", - "Modification du PIN ", - "PIN ndern" -}; -static char *pp_msg_change[] = { - "Change your PIN on the reader", - "Verander uw PIN op de lezer", - "Modifiez votre PIN sur le lecteur", - "Bitte ndern Sie Ihre PIN am Kartenlesegert" -}; -static char *pp_msg_pin_mismatch[] = { - "The new PINs you entered were different.\n\nRetry or cancel?", - "De ingevoerde nieuwe PINs zijn verschillend.\n\nOpnieuw proberen of stoppen?", - "Les nouveaux PIN entrs sont diffrents.\n\nRessayer ou annuler?", - "Die von Ihnen eingegebenen PINs unterscheiden sich.\n\nErneut versuchen oder abbrechen?" -}; - -#define PCSC_ERROR(ctx, desc, rv) sc_debug(ctx, SC_LOG_DEBUG_NORMAL, desc ": %lx\n", rv); - -#endif /* BELPIC_PIN_PAD */ - -/* Language support for the GUI messages */ -#ifdef HAVE_GUI - -#ifdef WIN32 -#define BTN_KEYB_SHORTCUT "&" -#else -#define BTN_KEYB_SHORTCUT "_" -#endif - -static char *app_msg[] = { - "Identity", - "Identiteit", -#ifdef _WIN32 - "Identit", -#else - "Identite", -#endif -#ifdef _WIN32 - "Identitt" -#else - "Identitat", -#endif -}; -static char *btn_msg_retry[4] = { - BTN_KEYB_SHORTCUT"Try again", - BTN_KEYB_SHORTCUT"Opnieuw proberen", - BTN_KEYB_SHORTCUT"Ressayer", - BTN_KEYB_SHORTCUT"Erneut versuchen" -}; -static char *btn_msg_cancel[4] = { - BTN_KEYB_SHORTCUT"Cancel", - BTN_KEYB_SHORTCUT"Stoppen", - BTN_KEYB_SHORTCUT"Annuler", - BTN_KEYB_SHORTCUT"Abbrechen" -}; -static char *btn_msg_ok[4] = { - BTN_KEYB_SHORTCUT"OK", - BTN_KEYB_SHORTCUT"OK", - BTN_KEYB_SHORTCUT"OK", - BTN_KEYB_SHORTCUT"OK" -}; -static char *btn_msg_close[4] = { - BTN_KEYB_SHORTCUT"Close", - BTN_KEYB_SHORTCUT"Sluiten", - BTN_KEYB_SHORTCUT"Fermer", - BTN_KEYB_SHORTCUT"Schliessen" -}; -static char *enter_pin_msg_auth[] = { - "Enter your PIN, in order to authenticate yourself", - "Geef uw PIN in, om u te authentificeren", - "Entrez votre PIN, pour vous authentifier", - "Bitte geben Sie Ihre PIN ein, um sich zu authentifizieren" -}; -static char *enter_pin_msg_sign[4] = { -#ifdef _WIN32 - "Caution: You are about to make a legally binding electronic signature with your identity card.\nPlease enter your PIN to continue or click the Cancel button.\n\nWarning: if you only want to log on to a web site or server, do NOT enter your PIN and click the Cancel button.", - "Let op: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart.\nGeef uw PIN in om verder te gaan of klik op Stoppen.\n\nWaarschuwing: als u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.", - "Attention: vous allez apposer une signature lectronique juridiquement valide avec votre carte d'identit.\nVeuillez entrer votre PIN pour continuer ou cliquez sur Annuler.\n\nPrcaution: si vous dsirez seulement vous connecter un site ou un serveur, n'entrez PAS votre PIN et cliquez sur Annuler.", - "Achtung: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen.\nBitte geben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen.\n\nWarnung: Wenn Sie nur auf das Internet gehen mchten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen." -#else -#ifdef __APPLE__ - "CAUTION: you are about to make a legally binding electronic signature with your identity card. Please enter your PIN to continue or press the Cancel button. If you only want to log on to a web site or a server, do NOT enter your PIN and press the Cancel button.", - "LET OP: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart. Geef uw PIN in om verder te gaan of klik op Stoppen. Als u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.", - "ATTENTION: vous allez apposer une signature electronique\njuridiquement valide avec votre carte d'identite.Veuillez entrer votre PIN pour continuer ou cliquez sur Annuler. Si vous desirez seulement vous connecter a un site ou un serveur, n' entrez PAS votre PIN et cliquez sur Annuler.", - "ACHTUNG: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen. Geben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen. Warnung: Wenn Sie nur auf das Internet gehen mochten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen." -#else - "Caution: you are about to make a legally binding electronic\nsignature with your identity card.\nPlease enter your PIN to continue or press the Cancel button.\n\nIf you only want to log on to a web site or a server,\ndo NOT enter your PIN and press the Cancel button.", - "Let op: u gaat een wettelijk bindende electronische handtekening\nplaatsen met uw identiteitskaart.\nGeef uw PIN in om verder te gaan of klik op Stoppen.\n\nAls u enkel wil aanloggen op een web site\nof een server, geef uw PIN NIET in en klik op Stoppen.", - "Attention: vous allez apposer une signature electronique\njuridiquement valide avec votre carte d'identite.\nVeuillez entrer votre PIN pour continuer ou cliquez sur Annuler.\n\nSi vous desirez seulement vous connecter a un site\nou un serveur, n'entrez PAS votre PIN et cliquez sur Annuler.", - "Achtung: Mit Ihrem Personalausweis werden Sie eine rechtlich\r\nbindende elektronische Signatur setzen.\r\nGeben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen.\r\n\r\nWarnung: Wenn Sie nur auf das Internet gehen mochten, geben\r\nSie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen." -#endif -#endif -}; -static char *wrong_pin_len_msgs[4] = { - "Wrong PIN length", - "Foute PIN lengte", - "Longueur de PIN erron", - "Falsche PIN-Lnge" -}; -static char *wrong_pin_msgs[4] = { - "Wrong PIN, %d tries left\n\nRetry or cancel?", - "Foute PIN, nog %d pogingen\n\nOpnieuw proberen of stoppen?", - "PIN erron, %d essais restants\n\nRessayer ou annuler?", - "Falsche PIN, %d verbleibende Versuche\n\nErneut versuchen oder abbrechen?" -}; -static char *pin_blocked_msgs[4] = { - "PIN blocked", - "PIN geblokkeerd", - "PIN bloqu ", - "PIN gesperrt" -}; - -#endif /* HAVE_GUI */ - -#ifdef BELPIC_PIN_PAD - -#define SCR_INIT_ID 100 -#define SCR_VERIFY_ID 101 -#define SCR_CHANGE_ID 102 -#define SCR_CARD_HANDLE 999 - -struct tTLV { - unsigned char *base; - unsigned char *end; - unsigned char *current; - unsigned char *next; -}; - -static void TLVInit(struct tTLV *tlv, u8 * base, size_t size) -{ - tlv->base = base; - tlv->end = base + size; - tlv->current = tlv->next = base; -} - -static void TLVNext(struct tTLV *tlv, u8 tag) -{ - assert(tlv->next + 2 < tlv->end); - tlv->current = tlv->next; - *(tlv->next++) = tag; - *(tlv->next++) = 0; -} - -static void TLVAdd(struct tTLV *tlv, u8 val) -{ - assert(tlv->next + 1 < tlv->end); - *(tlv->next++) = val; - tlv->current[1]++; -} - -static void TLVAddBuffer(struct tTLV *tlv, u8 * val, size_t size) -{ - assert(tlv->next + size < tlv->end); - memcpy(tlv->next, val, size); - tlv->current[1] = size; - tlv->next = tlv->next + size; -} - -static size_t TLVLen(struct tTLV *tlv) -{ - return tlv->next - tlv->base; -} - -static LONG SCR_SCardInit(LPCTSTR szPinPadDll, LPCTSTR szReader, DWORD version, - SCR_SupportConstants * supported) -{ - LONG rv; - unsigned char sendbuf[256]; - unsigned char recvbuf[2]; - char szTemp[32]; - DWORD dwRecvLength; - struct tTLV tlv; - - memset(szTemp, 0, sizeof(szTemp)); - memset(sendbuf, 0, sizeof(sendbuf)); - memset(recvbuf, 0, sizeof(recvbuf)); - dwRecvLength = sizeof(recvbuf); - - /* Make TLV buffer */ - TLVInit(&tlv, sendbuf, sizeof(sendbuf)); - TLVNext(&tlv, 0x01); /* Function ID */ - sprintf(szTemp, "%ld", SCR_INIT_ID); - TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp)); - TLVNext(&tlv, 0x02); /* PinPad Dll */ - TLVAddBuffer(&tlv, (u8 *) szPinPadDll, strlen(szPinPadDll)); - TLVNext(&tlv, 0x03); /* Reader Name */ - TLVAddBuffer(&tlv, (u8 *) szReader, strlen(szReader)); - TLVNext(&tlv, 0x04); /* Version */ - sprintf(szTemp, "%ld", version); - TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp)); - -#ifdef HAVE_PCSC_OLD - rv = SCardControl(SCR_CARD_HANDLE, sendbuf, TLVLen(&tlv), recvbuf, &dwRecvLength); -#else - rv = SCardControl(SCR_CARD_HANDLE, 0, sendbuf, TLVLen(&tlv), - recvbuf, dwRecvLength, &dwRecvLength); -#endif - if (dwRecvLength > 0) { - *supported = recvbuf[0]; - } else { - rv = SC_ERROR_UNKNOWN_DATA_RECEIVED; - } - - return rv; -} - -static LONG SCR_SCardPIN(long lAction, LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID, - const SCR_PinUsage * pUsage, const SCR_Application * pApp, - BYTE * pCardStatus) -{ - LONG rv; - unsigned char sendbuf[256]; - unsigned char recvbuf[2]; - char szTemp[32]; - DWORD dwRecvLength; - struct tTLV tlv; - - memset(szTemp, 0, sizeof(szTemp)); - memset(recvbuf, 0, sizeof(recvbuf)); - dwRecvLength = sizeof(recvbuf); - - /* Make TLV buffer */ - TLVInit(&tlv, sendbuf, sizeof(sendbuf)); - TLVNext(&tlv, 0x01); /* Function ID */ - sprintf(szTemp, "%ld", lAction); - TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp)); - TLVNext(&tlv, 0x02); /* PinPad Dll */ - TLVAddBuffer(&tlv, (u8 *) szPinPadDll, strlen(szPinPadDll)); - TLVNext(&tlv, 0x03); /* SCR_Card Handle */ - sprintf(szTemp, "%ld", pCard->hCard); - TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp)); - if (pCard->language != NULL) { - TLVNext(&tlv, 0x04); /* SCR_Card language */ - TLVAddBuffer(&tlv, (u8 *) pCard->language, strlen(pCard->language)); - } - if (pCard->id.data != NULL) { - TLVNext(&tlv, 0x05); /* SCR_Card id */ - TLVAddBuffer(&tlv, pCard->id.data, pCard->id.length); - } - TLVNext(&tlv, 0x06); /* PinID */ - TLVAdd(&tlv, pinID); - if (pUsage != NULL) { - TLVNext(&tlv, 0x07); /* SCR_PinUsage code */ - sprintf(szTemp, "%ld", pUsage->code); - TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp)); - if (pUsage->shortString != NULL) { - TLVNext(&tlv, 0x08); /* SCR_PinUsage shortstring */ - TLVAddBuffer(&tlv, (u8 *) pUsage->shortString, strlen(pUsage->shortString)); - } - if (pUsage->longString != NULL) { - TLVNext(&tlv, 0x09); /* SCR_PinUsage longstring */ - TLVAddBuffer(&tlv, (u8 *) pUsage->longString, strlen(pUsage->longString)); - } - } - if (pApp->id.data != NULL) { - TLVNext(&tlv, 0x0A); /* SCR_Application id */ - TLVAddBuffer(&tlv, (u8 *) pApp->id.data, pApp->id.length); - } - if (pApp->shortString != NULL) { - TLVNext(&tlv, 0x0B); /* SCR_Application shortstring */ - TLVAddBuffer(&tlv, (u8 *) pApp->shortString, strlen(pApp->shortString)); - } - if (pApp->longString != NULL) { - TLVNext(&tlv, 0x0C); /* SCR_Application longstring */ - TLVAddBuffer(&tlv, (u8 *) pApp->longString, strlen(pApp->longString)); - } -#ifdef HAVE_PCSC_OLD - rv = SCardControl(SCR_CARD_HANDLE, sendbuf, TLVLen(&tlv), recvbuf, &dwRecvLength); -#else - rv = SCardControl(SCR_CARD_HANDLE, 0, sendbuf, TLVLen(&tlv), - recvbuf, dwRecvLength, &dwRecvLength); -#endif - if (dwRecvLength < 2) { - rv = SC_ERROR_UNKNOWN_DATA_RECEIVED; - } else { - memcpy(pCardStatus, recvbuf, 2); - } - - return rv; -} - -static LONG SCR_SCardVerifyPIN(LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID, - const SCR_PinUsage * pUsage, const SCR_Application * pApp, - BYTE * pCardStatus) -{ - return SCR_SCardPIN(SCR_VERIFY_ID, szPinPadDll, pCard, pinID, pUsage, pApp, pCardStatus); -} - -static LONG SCR_SCardChangePIN(LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID, - const SCR_Application * pApp, BYTE * pCardStatus) -{ - return SCR_SCardPIN(SCR_CHANGE_ID, szPinPadDll, pCard, pinID, NULL, pApp, pCardStatus); -} - -#endif /* BELPIC_PIN_PAD */ - -#if defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) - -static int belpic_calculate_lang(sc_card_t *card) -{ - struct belpic_priv_data *priv = DRVDATA(card); - int lang = priv->lang; - return lang; -} - -#endif /* defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) */ - -static int str2lang(sc_context_t *ctx, char *lang) -{ - if (memcmp(lang, "en", 2) == 0) - return LNG_ENG; - else if (memcmp(lang, "nl", 2) == 0) - return LNG_DUTCH; - else if (memcmp(lang, "fr", 2) == 0) - return LNG_FRENCH; - else if (memcmp(lang, "de", 2) == 0) - return LNG_GERMAN; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unknown/unsupported language code: %c%c\n", lang[0], lang[1]); - return -1; -} - static int get_carddata(sc_card_t *card, u8* carddata_loc, unsigned int carddataloc_len) { sc_apdu_t apdu; @@ -651,258 +202,6 @@ return 0; } -#ifdef GET_LANG_FROM_CARD - -/* str is in lower case, the case of buf can be both, and buf is large enough */ -static int match_string(const char *str, const char *buf) -{ - int i = 0; - - while (str[i] != '\0') { - if (str[i] != ((buf[i] >= 'A' && buf[i] <= 'Z') ? buf[i] + 32 : buf[i])) - return 0; - i++; - } - return 1; /* match */ -} - -static int get_pref(const char *prefs, int prefs_len, const char *title, const char *key, int *len) -{ - int i = 0; - int title_len = strlen(title); - int key_len = strlen(key); - - while (prefs[i] != '\0' && i < prefs_len) - i++; - prefs_len = i; - - i = 0; - while (i < prefs_len) { - while (i < prefs_len && prefs[i] != '[') - i++; - if (i + title_len >= prefs_len) - return -1; - if (!match_string(title, prefs + i)) { - i++; - continue; - } - i += title_len; - while (i < prefs_len) { - while (i < prefs_len && (prefs[i] == '\r' || prefs[i] == '\n')) - i++; - if (i < prefs_len && prefs[i] == '[') - break; - if (i + key_len + 1 >= prefs_len) - return -2; - if (!match_string(key, prefs + i)) { - i++; - continue; - } - i += key_len; - if (prefs[i] != '=') - return -3; - *len = ++i; - while (*len < prefs_len && prefs[*len] != '\r' && prefs[*len] != '\n') - (*len)++; - *len -= i; - return i; - } - } - - return -1; -} - -static int get_language(sc_card_t *card) -{ - sc_apdu_t apdu; - u8 prefs[240], *lg_value; - u8 path[] = { 0x3F, 0x00, 0xDF, 0x01, 0x40, 0x39 }; - int r, i, len; - - /* Get the language from the card's preferences file */ - assert(card != NULL); - - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C); - apdu.lc = sizeof(path); - apdu.data = path; - apdu.datalen = sizeof(path); - apdu.resplen = 0; - apdu.le = 0; - - r = sc_lock(card); - if (r < 0) - goto prefs_error; - - r = sc_transmit_apdu(card, &apdu); - if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Select_File[prefs_file] command failed: %d\n", r); - sc_unlock(card); - goto prefs_error; - } - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Select_File[prefs_file]: card returned %d\n", r); - sc_unlock(card); - goto prefs_error; - } - - r = iso_ops->read_binary(card, 0, prefs, sizeof(prefs), 0); - sc_unlock(card); - if (r <= 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Read_Binary[prefs_file] returned %d\n", r); - goto prefs_error; - } - i = get_pref(prefs, r, "[gen]", "lg", &len); - if (i <= 0 || len < 2) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Couldn't find language in prefs file: %d\n", i); - goto prefs_error; - } - lg_value = prefs + i; /* language code(s) found, starts here */ - i = 0; - while (1) { - while (i <= len - 2 && (lg_value[i] == ' ' || lg_value[i] == '|')) - i++; - if (i > len - 2) - goto prefs_error; - r = str2lang(card->ctx, lg_value + i); - if (r >= 0) - return r; - i += 2; - } - - prefs_error: - /* If troubles with the card's prefs file, get the language from the OS */ -#ifdef _WIN32 - switch (GetUserDefaultLangID() & 0x00FF) { - case 0x13: - return LNG_DUTCH; - case 0x0C: - return LNG_FRENCH; - case 0x07: - return LNG_GERMAN; - default: - return LNG_ENG; - } -#endif - return LNG_ENG; /* default */ -} - -#endif /* GET_LANG_FROM_CARD */ - -static scconf_block *get_belpic_conf(sc_context_t *ctx, const char *name) -{ - scconf_block *conf_block = NULL, **blocks; - int i; - - for (i = 0; ctx->conf_blocks[i] != NULL; i++) { - blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], name, NULL); - if (!blocks) - return NULL; - conf_block = blocks[0]; - free(blocks); - if (conf_block != NULL) - break; - } - - return conf_block; -} - -#ifdef BELPIC_PIN_PAD - -static void load_pin_pad_err(const char *reader_name, const char *pp_reader_lib, char *msg) -{ - char buf[300]; - void *hDlg; - - if (strlen(reader_name) + strlen(pp_reader_lib) > 200) - return; - - sprintf(buf, "Error while loading library \"%s\" for pin pad reader \"%s\": %s\n", - pp_reader_lib, reader_name, msg); - scgui_ask_message(app_msg[0], "Pin pad library error", buf, btn_msg_close[0], NULL, - reader_name); -} - -static int belpic_load_pin_pad_lib(sc_card_t *card, struct belpic_priv_data *priv_data, - const char *reader_name, const char *pp_reader_lib) -{ - LONG r; - DWORD supported; - - memset(priv_data->szPinPadDll, 0, sizeof(priv_data->szPinPadDll)); - strcpy(priv_data->szPinPadDll, pp_reader_lib); - - priv_data->scr_init = (FARPROC) SCR_SCardInit; - priv_data->scr_verify_pin = (FARPROC) SCR_SCardVerifyPIN; - priv_data->scr_change_pin = (FARPROC) SCR_SCardChangePIN; - - if (priv_data->scr_init == NULL || priv_data->scr_verify_pin == NULL) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Function not found in \"%s\" err = 0x%0x\n", - pp_reader_lib, GetLastError()); - load_pin_pad_err(reader_name, pp_reader_lib, - "unsufficient functionality found in library"); - return SC_ERROR_READER; - } - - r = priv_data->scr_init(pp_reader_lib, reader_name, 1, &supported); - if (r != SCARD_S_SUCCESS) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SCR_Init() returned 0x%0x\n", r); - load_pin_pad_err(reader_name, pp_reader_lib, "Initialization of library failed"); - return SC_ERROR_READER; - } - if (supported) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SCR_init() returned not supported code 0x%0x\n", supported); - load_pin_pad_err(reader_name, pp_reader_lib, - "Initialization of library returned UNSUPPORTED"); - return SC_ERROR_READER; - } - return 1; -} - -static int belpic_detect_pin_pad(sc_card_t *card, struct belpic_priv_data *priv_data) -{ - int i = 0; - char *reader_name = card->reader->name, *conf_reader, *conf_lib; - scconf_block *conf_block = NULL; - char *reader_i = "reader ", *lib_i = "lib "; - int rn_len = strlen(reader_name); - - /* Hardcoded readers */ - for (i = 0; pp_reader_names[i] != NULL; i++) { - int pp_rn_len = strlen(pp_reader_names[i]); - if (rn_len >= pp_rn_len && strncmp(reader_name, pp_reader_names[i], pp_rn_len) == 0) { - return belpic_load_pin_pad_lib(card, priv_data, - reader_name, pp_reader_libs[i]); - } - } - - /* From the config file */ - conf_block = get_belpic_conf(card->ctx, "belpic_pin_pad"); - if (conf_block == NULL) - return 0; - for (i = 0; i < 10; i++) { - reader_i[6] = (char) (0x30 + i); - conf_reader = (char *) scconf_get_str(conf_block, reader_i, NULL); - if (conf_reader != NULL && rn_len >= strlen(conf_reader) && - strncmp(reader_name, conf_reader, strlen(conf_reader)) == 0) { - lib_i[3] = (char) (0x30 + i); - conf_lib = (char *) scconf_get_str(conf_block, lib_i, NULL); - if (conf_lib != NULL) - return belpic_load_pin_pad_lib(card, priv_data, - reader_name, conf_lib); - } - } - - return 0; -} -#endif /* BELPIC_PIN_PAD */ - -static int belpic_finish(sc_card_t *card) -{ - free(DRVDATA(card)); - return 0; -} - static int belpic_match_card(sc_card_t *card) { int i; @@ -915,86 +214,34 @@ static int belpic_init(sc_card_t *card) { - struct belpic_priv_data *priv = NULL; - scconf_block *conf_block; - u8 applet_version; - u8 carddata[BELPIC_CARDDATA_RESP_LEN]; int key_size = 1024; int r; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Belpic V%s", BELPIC_VERSION); -#ifdef HAVE_GUI - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " with GUI support"); -#endif -#ifdef BELPIC_PIN_PAD - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " with support for pin pad reader libs"); -#endif - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "\n"); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Belpic V%s\n", BELPIC_VERSION); if (card->type < 0) card->type = SC_CARD_TYPE_BELPIC_EID; /* Unknown card: assume it's the Belpic Card */ - priv = calloc(1, sizeof(struct belpic_priv_data)); - if (priv == NULL) - return SC_ERROR_OUT_OF_MEMORY; - card->drv_data = priv; card->cla = 0x00; if (card->type == SC_CARD_TYPE_BELPIC_EID) { + u8 carddata[BELPIC_CARDDATA_RESP_LEN]; + memset(carddata, 0, sizeof(carddata)); + if((r = get_carddata(card, carddata, sizeof(carddata))) < 0) { - return r; + return SC_ERROR_INVALID_CARD; } - applet_version = carddata[BELPIC_CARDDATA_OFF_APPLETVERS]; - if(applet_version >= 0x17) { + if (carddata[BELPIC_CARDDATA_OFF_APPLETVERS] >= 0x17) { key_size = 2048; } _sc_card_add_rsa_alg(card, key_size, - SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE, 0); + SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE, 0); } /* State that we have an RNG */ card->caps |= SC_CARD_CAP_RNG; - /* Language prefences */ - priv->lang = -1; - conf_block = get_belpic_conf(card->ctx, "belpic_general"); - if (conf_block != NULL) { - char *lang = (char *) scconf_get_str(conf_block, "force_language", NULL); - if (lang != NULL && strlen(lang) == 2) - priv->lang = str2lang(card->ctx, lang); - } -#ifdef GET_LANG_FROM_CARD - if (priv->lang == -1) - priv->lang = get_language(card); -#endif - card->max_pin_len = BELPIC_MAX_USER_PIN_LEN; -#ifdef HAVE_GUI - r = scgui_init(); - if (r != 0) - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "scgui_init() returned error %d\n", i); -#endif - -#ifdef BELPIC_PIN_PAD - r = belpic_detect_pin_pad(card, priv); - if (r == 1) - card->reader->capabilities |= SC_READER_CAP_PIN_PAD; - else if (r < 0) - return r; /* error loading/initing pin pad lib */ - - conf_block = get_belpic_conf(card->ctx, "belpic_pin_pad"); - if (conf_block != NULL) { - if (scconf_get_bool(conf_block, "msg_auth_pin", 1)) - priv->options |= PP_MSG_AUTH_PIN; - if (scconf_get_bool(conf_block, "msg_wrong_pin", 1)) - priv->options |= PP_MSG_WRONG_PIN; - if (scconf_get_bool(conf_block, "msg_changepin_mismatch", 1)) - priv->options |= PP_MSG_CHANGEPIN_MISMATCH; - if (scconf_get_bool(conf_block, "msg_pin_blocked", 1)) - priv->options |= PP_MSG_PIN_BLOCKED; - } -#endif - return 0; } @@ -1074,192 +321,8 @@ return r; } -#ifdef BELPIC_PIN_PAD - -/* Test the result code of the pin pad reader + the card's status bytes */ -static int belpic_pp_test_res(sc_card_t *card, int r, const u8 * card_status, int *tries_left) -{ - if (r != SCARD_S_SUCCESS) { - switch (r) { - case SCARD_E_CANCELLED: - return SC_ERROR_KEYPAD_CANCELLED; - case SCARD_W_REMOVED_CARD: - return SC_ERROR_CARD_REMOVED; - case SCR_I_PIN_CHECK_FAILED: - return SC_ERROR_KEYPAD_PIN_MISMATCH; - default: - return SC_ERROR_TRANSMIT_FAILED; - } - } - if (card_status[0] == 0xEC && card_status[1] == 0xD2) - return SC_ERROR_KEYPAD_TIMEOUT; - if (card_status[0] == 0xEC && card_status[1] == 0xD6) - return SC_ERROR_KEYPAD_CANCELLED; - if (card_status[0] == 0x63) { - if ((card_status[1] & 0xF0) == 0xC0 && tries_left != NULL) - *tries_left = card_status[1] & 0x0F; - return SC_ERROR_PIN_CODE_INCORRECT; - } - return sc_check_sw(card, card_status[0], card_status[1]); -} - -/* Send the verify pin command to the pin pad reader + optionally show message */ -static int belpic_pp_verify(sc_card_t *card, SCR_Card * scr_card, - struct belpic_priv_data *priv, int pin_ref, - int pin_usage, int *tries_left) -{ - BYTE card_status[2]; - void *hDlg; - int first_time = 1, r = SC_ERROR_PIN_CODE_INCORRECT; - int lang = belpic_calculate_lang(card); - SCR_PinUsage scr_pin_usage = { - pin_usage, - pin_usage == SCR_USAGE_SIGN ? "SIG" : "AUT", - pin_usage == SCR_USAGE_SIGN ? pin_usg_sig[lang] : pin_usg_auth[lang] - }; - char *reader_name = card->reader->name; - char *pp_msg_login_sh = - (pin_usage == SCR_USAGE_SIGN ? pp_msg_sign_sh[lang] : pp_msg_auth_sh[lang]); - char *pp_msg_login = (pin_usage == SCR_USAGE_SIGN ? pp_msg_sign[lang] : pp_msg_auth[lang]); - scgui_param_t icon = (pin_usage == SCR_USAGE_SIGN ? SCGUI_SIGN_ICON : SCGUI_NO_ICON); - int mesg_on_screen = (priv->options & PP_MSG_AUTH_PIN) || - (pin_usage != SCR_USAGE_AUTH) || SSO_OK(card->ctx); - - while (r == SC_ERROR_PIN_CODE_INCORRECT) { - if (!first_time) { - if (priv->options & PP_MSG_WRONG_PIN) { - int r1; - char msg[200]; - - sprintf(msg, wrong_pin_msgs[lang], *tries_left); - r1 = scgui_ask_message(app_msg[lang], pp_msg_login_sh, msg, - btn_msg_retry[lang], btn_msg_cancel[lang], - reader_name); - if (r1 == SCGUI_CANCEL) - return r; - else if (r1 != SCGUI_OK) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "scgui_ask_message returned %d\n", r1); - return SC_ERROR_INTERNAL; - } - } else - return r; - } - first_time = 0; - - if (mesg_on_screen) { - scgui_display_message(app_msg[lang], pp_msg_login_sh, pp_msg_login, - NULL, &hDlg, icon, reader_name); - } - r = priv->scr_verify_pin(priv->szPinPadDll, scr_card, pin_ref, - &scr_pin_usage, &scr_app_belpic, card_status); - if (mesg_on_screen) - scgui_remove_message(hDlg); - - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SCR_Verify_PIN(): res = 0x%0x, status = %2X %2X\n", - r, card_status[0], card_status[1]); - r = belpic_pp_test_res(card, r, card_status, tries_left); - } - - return r; -} - -/* Send the change pin command to the pin pad reader + show message */ -static int belpic_pp_change(sc_card_t *card, SCR_Card * scr_card, - struct belpic_priv_data *priv, int pin_ref, int *tries_left) -{ - BYTE card_status[2]; - void *hDlg; - int first_time = 1, r = SC_ERROR_KEYPAD_PIN_MISMATCH, r1; - int lang = belpic_calculate_lang(card); - char *reader_name = card->reader->name; - - while (r == SC_ERROR_KEYPAD_PIN_MISMATCH || r == SC_ERROR_PIN_CODE_INCORRECT) { - if (!first_time) { - int r1 = SCGUI_OK; - if (r == SC_ERROR_KEYPAD_PIN_MISMATCH) { - if (!(priv->options & PP_MSG_CHANGEPIN_MISMATCH)) - return r; - r1 = scgui_ask_message(app_msg[lang], pp_msg_change_sh[lang], - pp_msg_pin_mismatch[lang], - btn_msg_retry[lang], btn_msg_cancel[lang], - reader_name); - } - if (r == SC_ERROR_PIN_CODE_INCORRECT) { - char msg[200]; - - if (!(priv->options & PP_MSG_WRONG_PIN)) - return r; - sprintf(msg, wrong_pin_msgs[lang], *tries_left); - r1 = scgui_ask_message(app_msg[lang], pp_msg_change_sh[lang], - msg, btn_msg_retry[lang], - btn_msg_cancel[lang], reader_name); - } - if (r1 == SCGUI_CANCEL) - return r; - else if (r1 != SCGUI_OK) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "scgui_ask_message returned %d\n", r1); - return SC_ERROR_INTERNAL; - } - } - first_time = 0; - - scgui_display_message(app_msg[lang], pp_msg_change_sh[lang], - pp_msg_change[lang], NULL, &hDlg, SCGUI_NO_ICON, reader_name); - r = priv->scr_change_pin(priv->szPinPadDll, scr_card, pin_ref, - &scr_app_belpic, card_status); - scgui_remove_message(hDlg); - - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SCR_Change_PIN(): res = 0x%0x, status = %2X %2X\n", - r, card_status[0], card_status[1]); - r = belpic_pp_test_res(card, r, card_status, tries_left); - } - - return r; -} - -#endif /* BELPIC_PIN_PAD */ - -static int belpic_pin_cmd_usage(sc_card_t *card, struct sc_pin_cmd_data *data, - int *tries_left, int pin_usage) +static int belpic_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) { -#ifdef BELPIC_PIN_PAD - sc_apdu_t apdu; - int r; - - struct belpic_priv_data *priv = DRVDATA(card); - int lang = belpic_calculate_lang(card); - if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) { - LONG r; - SCR_Card scr_card = { - priv->pcsc_card, - lang_codes[lang], - {NULL, 0} - , - NULL - }; - - scr_app_belpic.longString = app_id_longstr[lang]; - - switch (data->cmd) { - case SC_PIN_CMD_VERIFY: - r = belpic_pp_verify(card, &scr_card, - priv, data->pin_reference, pin_usage, tries_left); - break; - case SC_PIN_CMD_CHANGE: - r = belpic_pp_change(card, &scr_card, - priv, data->pin_reference, tries_left); - break; - default: - r = SC_ERROR_NOT_SUPPORTED; - } - - if (r == SC_ERROR_AUTH_METHOD_BLOCKED && (priv->options & PP_MSG_PIN_BLOCKED)) - scgui_ask_message(app_msg[lang], " ", pin_blocked_msgs[lang], - btn_msg_close[lang], NULL, card->reader->name); - return r; - } -#endif /* BELPIC_PIN_PAD */ - data->pin1.encoding = data->pin2.encoding = BELPIC_PIN_ENCODING; data->pin1.pad_char = data->pin2.pad_char = BELPIC_PAD_CHAR; data->pin1.min_length = data->pin2.min_length = BELPIC_MIN_USER_PIN_LEN; @@ -1269,107 +332,6 @@ return iso_ops->pin_cmd(card, data, tries_left); } -static int belpic_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) -{ - if (SSO_OK(card->ctx) && data->cmd == SC_PIN_CMD_VERIFY) - return 0; /* Don't log in right now, just say it's OK */ - else - return belpic_pin_cmd_usage(card, data, tries_left, 1); /* SCR_USAGE_AUTH = 1 */ -} - -#ifdef HAVE_GUI - -/* Called by belpic_set_security_env() when a NonRep signature will be done, - * or by belpic-compute_signature the first fime an auth signature is done - * and the allow_sso is true - */ -static int belpic_askpin_verify(sc_card_t *card, int pin_usage) -{ - struct sc_pin_cmd_data data; - sc_apdu_t apdu; - u8 pin_data[BELPIC_MAX_USER_PIN_LEN + 1]; - int pin_len; - int tries_left; - int r; - struct belpic_priv_data *priv = DRVDATA(card); - int lang = belpic_calculate_lang(card); - char *enter_pin_msg = (pin_usage == SCR_USAGE_AUTH ? - enter_pin_msg_auth[lang] : enter_pin_msg_sign[lang]); - scgui_param_t icon = (pin_usage == SCR_USAGE_AUTH ? SCGUI_NO_ICON : SCGUI_SIGN_ICON); - - data.pin1.encoding = BELPIC_PIN_ENCODING; - data.pin1.pad_char = BELPIC_PAD_CHAR; - data.pin1.min_length = BELPIC_MIN_USER_PIN_LEN; - data.pin1.max_length = BELPIC_MAX_USER_PIN_LEN; - - data.cmd = SC_PIN_CMD_VERIFY; - data.flags = 0; - data.pin_type = SC_AC_CHV; - data.pin_reference = 1; - - -#ifdef BELPIC_PIN_PAD - /* In case of a pinpad reader */ - if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) { - data.pin1.data = NULL; - data.pin1.len = 0; - - return belpic_pin_cmd_usage(card, &data, &tries_left, pin_usage); - } -#endif - - pin_len = BELPIC_MAX_USER_PIN_LEN + 1; - r = scgui_enterpin(app_msg[lang], enter_pin_msg, pin_data, &pin_len, - btn_msg_ok[lang], btn_msg_cancel[lang], wrong_pin_len_msgs[lang], icon); - if (r == SCGUI_CANCEL) - return SC_ERROR_KEYPAD_CANCELLED; - if (r != SCGUI_OK) - return SC_ERROR_INTERNAL; - - data.pin1.data = pin_data; - data.pin1.len = pin_len; - r = belpic_pin_cmd_usage(card, &data, &tries_left, pin_usage); - - /* card->ctx->allow_sso = true: we do PIN mgmnt ourselves */ - while (r == SC_ERROR_PIN_CODE_INCORRECT && SSO_OK(card->ctx)) { - int r1; - char msg[200]; - - sprintf(msg, wrong_pin_msgs[lang], tries_left); - r1 = scgui_ask_message(app_msg[lang], pin_usg_auth[lang], msg, - btn_msg_retry[lang], btn_msg_cancel[lang], - card->reader->name); - if (r1 == SCGUI_CANCEL) - return r; - else if (r1 != SCGUI_OK) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "scgui_ask_message returned %d\n", r1); - return SC_ERROR_INTERNAL; - } - - pin_len = BELPIC_MAX_USER_PIN_LEN + 1; - r = scgui_enterpin(app_msg[lang], enter_pin_msg, pin_data, &pin_len, - btn_msg_ok[lang], btn_msg_cancel[lang], wrong_pin_len_msgs[lang], - icon); - if (r == SCGUI_CANCEL) - return SC_ERROR_KEYPAD_CANCELLED; - if (r != SCGUI_OK) - return SC_ERROR_INTERNAL; - - data.pin1.data = pin_data; - data.pin1.len = pin_len; - r = belpic_pin_cmd_usage(card, &data, &tries_left, pin_usage); - if (tries_left == 0) - r = SC_ERROR_AUTH_METHOD_BLOCKED; - } - - if (r == SC_ERROR_AUTH_METHOD_BLOCKED && SSO_OK(card->ctx)) - scgui_ask_message(app_msg[lang], " ", pin_blocked_msgs[lang], - btn_msg_close[lang], NULL, card->reader->name); - - return r; -} -#endif /* HAVE_GUI */ - static int belpic_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) { @@ -1419,7 +381,7 @@ /* If a NonRep signature will be done, ask to enter a PIN. It would be more * logical to put the code below into the compute signature function because - * a Verify Pin call must immediately preceed a Compute Signature call. + * a Verify Pin call must immediately precede a Compute Signature call. * It's not done because the Compute Signature is completely ISO7816 compliant * so we use the iso7816_compute_signature() function, and because this function * doesn't know about the key reference. @@ -1428,58 +390,13 @@ * the next function to be executed will be the compute_signature function. */ if (*env->key_ref == BELPIC_KEY_REF_NONREP) { -#ifdef HAVE_GUI - r = belpic_askpin_verify(card, SCR_USAGE_SIGN); - if (r != 0 && r != SC_ERROR_KEYPAD_CANCELLED) - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Verify PIN in SET command returned %d\n", r); - else - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Verify PIN in SET command returned %d\n", r); -#else sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "No GUI for NonRep key present, signature cancelled\n"); return SC_ERROR_NOT_SUPPORTED; -#endif } return r; } -static int belpic_compute_signature(sc_card_t *card, const u8 * data, - size_t data_len, u8 * out, size_t outlen) -{ - int r; - - r = iso_ops->compute_signature(card, data, data_len, out, outlen); - -#ifdef HAVE_GUI - if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && SSO_OK(card->ctx)) { - r = belpic_askpin_verify(card, SCR_USAGE_AUTH); - if (r == 0) - r = iso_ops->compute_signature(card, data, data_len, out, outlen); - } -#endif - - return r; -} - -static int belpic_update_binary(sc_card_t *card, - unsigned int idx, const u8 *buf, size_t count, - unsigned long flags) -{ - int r; - - r = iso_ops->update_binary(card, idx, buf, count, flags); - -#ifdef HAVE_GUI - if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && SSO_OK(card->ctx)) { - r = belpic_askpin_verify(card, SCR_USAGE_AUTH); - if (r == 0) - r = iso_ops->update_binary(card, idx, buf, count, flags); - } -#endif - - return r; -} - static struct sc_card_driver *sc_get_driver(void) { if (iso_ops == NULL) @@ -1487,15 +404,14 @@ belpic_ops.match_card = belpic_match_card; belpic_ops.init = belpic_init; - belpic_ops.finish = belpic_finish; - belpic_ops.update_binary = belpic_update_binary; + belpic_ops.update_binary = iso_ops->update_binary; belpic_ops.select_file = belpic_select_file; belpic_ops.read_binary = belpic_read_binary; belpic_ops.pin_cmd = belpic_pin_cmd; belpic_ops.set_security_env = belpic_set_security_env; - belpic_ops.compute_signature = belpic_compute_signature; + belpic_ops.compute_signature = iso_ops->compute_signature; belpic_ops.get_challenge = iso_ops->get_challenge; belpic_ops.get_response = iso_ops->get_response; belpic_ops.check_sw = iso_ops->check_sw; diff -Nru opensc-0.17.0/src/libopensc/card.c opensc-0.19.0/src/libopensc/card.c --- opensc-0.17.0/src/libopensc/card.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card.c 2018-09-13 11:47:21.000000000 +0000 @@ -34,10 +34,6 @@ #include "asn1.h" #include "common/compat_strlcpy.h" -/* -#define INVALIDATE_CARD_CACHE_IN_UNLOCK -*/ - #ifdef ENABLE_SM static int sc_card_sm_load(sc_card_t *card, const char *path, const char *module); static int sc_card_sm_unload(sc_card_t *card); @@ -142,7 +138,7 @@ } max_recv_size = card->max_recv_size; - /* initialize max_recv_size to a meaningfull value */ + /* initialize max_recv_size to a meaningful value */ if (card->caps & SC_CARD_CAP_APDU_EXT) { if (!max_recv_size) max_recv_size = 65536; @@ -169,7 +165,7 @@ max_send_size = card->max_send_size; - /* initialize max_send_size to a meaningfull value */ + /* initialize max_send_size to a meaningful value */ if (card->caps & SC_CARD_CAP_APDU_EXT && card->reader->active_protocol != SC_PROTO_T0) { if (!max_send_size) @@ -265,8 +261,22 @@ } } else { + sc_card_t uninitialized = *card; sc_log(ctx, "matching built-in ATRs"); for (i = 0; ctx->card_drivers[i] != NULL; i++) { + /* FIXME If we had a clean API description, we'd propably get a + * cleaner implementation of the driver's match_card and init, + * which should normally *not* modify the card object if + * unsuccessful. However, after years of relentless hacking, reality + * is different: The card object is changed in virtually every card + * driver so in order to prevent unwanted interaction, we reset the + * card object here and hope that the card driver at least doesn't + * allocate any internal ressources that need to be freed. If we + * had more time, we should refactor the existing code to not + * modify sc_card_t until complete success (possibly by combining + * `match_card()` and `init()`) */ + *card = uninitialized; + struct sc_card_driver *drv = ctx->card_drivers[i]; const struct sc_card_operations *ops = drv->ops; @@ -307,7 +317,7 @@ if (card->name == NULL) card->name = card->driver->name; - /* initialize max_send_size/max_recv_size to a meaningfull value */ + /* initialize max_send_size/max_recv_size to a meaningful value */ card->max_recv_size = sc_get_max_recv_size(card); card->max_send_size = sc_get_max_send_size(card); @@ -382,9 +392,7 @@ return r; r = card->reader->ops->reset(card->reader, do_cold_reset); - /* invalidate cache */ - memset(&card->cache, 0, sizeof(card->cache)); - card->cache.valid = 0; + sc_invalidate_cache(card); r2 = sc_mutex_unlock(card->ctx, card->mutex); if (r2 != SC_SUCCESS) { @@ -413,9 +421,7 @@ if (card->reader->ops->lock != NULL) { r = card->reader->ops->lock(card->reader); while (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) { - /* invalidate cache */ - memset(&card->cache, 0, sizeof(card->cache)); - card->cache.valid = 0; + sc_invalidate_cache(card); if (was_reset++ > 4) /* TODO retry a few times */ break; r = card->reader->ops->lock(card->reader); @@ -466,12 +472,12 @@ return SC_ERROR_INVALID_ARGUMENTS; } if (--card->lock_count == 0) { -#ifdef INVALIDATE_CARD_CACHE_IN_UNLOCK - /* invalidate cache */ - memset(&card->cache, 0, sizeof(card->cache)); - card->cache.valid = 0; - sc_log(card->ctx, "cache invalidated"); -#endif + if (card->flags & SC_CARD_FLAG_KEEP_ALIVE) { + /* Multiple processes accessing the card will most likely render + * the card cache useless. To not have a bad cache, we explicitly + * invalidate it. */ + sc_invalidate_cache(card); + } /* release reader lock */ if (card->reader->ops->unlock != NULL) r = card->reader->ops->unlock(card->reader); @@ -812,17 +818,42 @@ int sc_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { int r; + size_t retry = 10; - if (card == NULL) { + if (len == 0) + return SC_SUCCESS; + + if (card == NULL || rnd == NULL) { return SC_ERROR_INVALID_ARGUMENTS; } + LOG_FUNC_CALLED(card->ctx); - if (card->ops->get_challenge == NULL) + if (card->ops == NULL || card->ops->get_challenge == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); - r = card->ops->get_challenge(card, rnd, len); - LOG_FUNC_RETURN(card->ctx, r); + r = sc_lock(card); + if (r != SC_SUCCESS) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + + while (len > 0 && retry > 0) { + r = card->ops->get_challenge(card, rnd, len); + if (r < 0) { + sc_unlock(card); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + } + + if (r > 0) { + rnd += (size_t) r; + len -= (size_t) r; + } else { + retry--; + } + } + + sc_unlock(card); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } int sc_read_record(sc_card_t *card, unsigned int rec_nr, u8 *buf, @@ -1039,7 +1070,7 @@ return sc_card_find_alg(card, SC_ALGORITHM_GOSTR3410, key_length, NULL); } -static int match_atr_table(sc_context_t *ctx, struct sc_atr_table *table, struct sc_atr *atr) +static int match_atr_table(sc_context_t *ctx, const struct sc_atr_table *table, struct sc_atr *atr) { u8 *card_atr_bin; size_t card_atr_bin_len; @@ -1102,7 +1133,7 @@ return -1; } -int _sc_match_atr(sc_card_t *card, struct sc_atr_table *table, int *type_out) +int _sc_match_atr(sc_card_t *card, const struct sc_atr_table *table, int *type_out) { int res; @@ -1233,7 +1264,16 @@ return conf_block; } -void sc_print_cache(struct sc_card *card) { +void sc_invalidate_cache(struct sc_card *card) +{ + if (card) { + memset(&card->cache, 0, sizeof(card->cache)); + card->cache.valid = 0; + } +} + +void sc_print_cache(struct sc_card *card) +{ struct sc_context *ctx = NULL; if (card == NULL) @@ -1312,6 +1352,8 @@ char temp_path[PATH_MAX]; size_t temp_len; const char path_delim = '\\'; + char expanded_val[PATH_MAX]; + DWORD expanded_len; #else const char path_delim = '/'; #endif @@ -1325,16 +1367,22 @@ return sc_card_sm_unload(card); #ifdef _WIN32 - if (!module_path) { - temp_len = PATH_MAX; + if (!module_path || strlen(module_path) == 0) { + temp_len = PATH_MAX-1; rv = sc_ctx_win32_get_config_value(NULL, "SmDir", "Software\\OpenSC Project\\OpenSC", temp_path, &temp_len); - if (rv == SC_SUCCESS) + if (rv == SC_SUCCESS) { + temp_path[temp_len] = '\0'; module_path = temp_path; + } } + expanded_len = PATH_MAX; + expanded_len = ExpandEnvironmentStringsA(module_path, expanded_val, expanded_len); + if (0 < expanded_len && expanded_len < sizeof expanded_val) + module_path = expanded_val; #endif sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "SM module '%s' located in '%s'", in_module, module_path); - if (module_path) { + if (module_path && strlen(module_path) > 0) { int sz = strlen(in_module) + strlen(module_path) + 3; module = malloc(sz); if (module) @@ -1440,8 +1488,8 @@ LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_CONFIGURATION, "SM configuration block not preset"); /* check if an external SM module has to be used */ - module_path = scconf_get_str(sm_conf_block, "module_path", NULL); - module_name = scconf_get_str(sm_conf_block, "module_name", NULL); + module_path = scconf_get_str(sm_conf_block, "module_path", DEFAULT_SM_MODULE_PATH); + module_name = scconf_get_str(sm_conf_block, "module_name", DEFAULT_SM_MODULE); sc_log(ctx, "SM module '%s' in '%s'", module_name, module_path); if (!module_name) LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_CONFIGURATION, "Invalid SM configuration: module not defined"); diff -Nru opensc-0.17.0/src/libopensc/card-cac.c opensc-0.19.0/src/libopensc/card-cac.c --- opensc-0.17.0/src/libopensc/card-cac.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-cac.c 2018-09-13 11:47:21.000000000 +0000 @@ -6,9 +6,10 @@ * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert * Copyright (C) 2006, Identity Alliance, Thomas Harning * Copyright (C) 2007, EMC, Russell Larner - * Copyright (C) 2016, Red Hat, Inc. + * Copyright (C) 2016 - 2018, Red Hat, Inc. * * CAC driver author: Robert Relyea + * Further work: Jakub Jelen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -63,16 +64,18 @@ * CAC hardware and APDU constants */ #define CAC_MAX_CHUNK_SIZE 240 -#define CAC_INS_GET_CERTIFICATE 0x36 /* CAC1 command to read a certificate */ -#define CAC_INS_SIGN_DECRYPT 0x42 /* A crypto operation */ +#define CAC_INS_SIGN_DECRYPT 0x42 /* A crypto operation */ +#define CAC_INS_READ_FILE 0x52 /* read a TL or V file */ +#define CAC_INS_GET_ACR 0x4c +#define CAC_INS_GET_PROPERTIES 0x56 #define CAC_P1_STEP 0x80 #define CAC_P1_FINAL 0x00 -#define CAC_INS_READ_FILE 0x52 /* read a TL or V file */ #define CAC_FILE_TAG 1 #define CAC_FILE_VALUE 2 /* TAGS in a TL file */ #define CAC_TAG_CERTIFICATE 0x70 #define CAC_TAG_CERTINFO 0x71 +#define CAC_TAG_MSCUID 0x72 #define CAC_TAG_CUID 0xF0 #define CAC_TAG_CC_VERSION_NUMBER 0xF1 #define CAC_TAG_GRAMMAR_VERION_NUMBER 0xF2 @@ -86,9 +89,26 @@ #define CAC_TAG_STATUS_TUPLES 0xFC #define CAC_TAG_NEXT_CCC 0xFD #define CAC_TAG_ERROR_CODES 0xFE -#define CAC_APP_TYPE_GENERAL 0x01 -#define CAC_APP_TYPE_SKI 0x02 -#define CAC_APP_TYPE_PKI 0x04 +#define CAC_TAG_APPLET_FAMILY 0x01 +#define CAC_TAG_NUMBER_APPLETS 0x94 +#define CAC_TAG_APPLET_ENTRY 0x93 +#define CAC_TAG_APPLET_AID 0x92 +#define CAC_TAG_APPLET_INFORMATION 0x01 +#define CAC_TAG_NUMBER_OF_OBJECTS 0x40 +#define CAC_TAG_TV_BUFFER 0x50 +#define CAC_TAG_PKI_OBJECT 0x51 +#define CAC_TAG_OBJECT_ID 0x41 +#define CAC_TAG_BUFFER_PROPERTIES 0x42 +#define CAC_TAG_PKI_PROPERTIES 0x43 + +#define CAC_APP_TYPE_GENERAL 0x01 +#define CAC_APP_TYPE_SKI 0x02 +#define CAC_APP_TYPE_PKI 0x04 + +#define CAC_ACR_ACR 0x00 +#define CAC_ACR_APPLET_OBJECT 0x10 +#define CAC_ACR_AMP 0x20 +#define CAC_ACR_SERVICE 0x21 /* hardware data structures (returned in the CCC) */ /* part of the card_url */ @@ -141,6 +161,22 @@ sc_path_t path; } cac_object_t; +#define CAC_MAX_OBJECTS 16 + +typedef struct { + /* OID has two bytes */ + unsigned char oid[2]; + /* Format is NOT SimpleTLV? */ + unsigned char simpletlv; + /* Is certificate object and private key is initialized */ + unsigned char privatekey; +} cac_properties_object_t; + +typedef struct { + unsigned int num_objects; + cac_properties_object_t objects[CAC_MAX_OBJECTS]; +} cac_properties_t; + /* * Flags for Current Selected Object Type * CAC files are TLV files, with TL and V separated. For generic @@ -152,6 +188,7 @@ */ #define CAC_OBJECT_TYPE_CERT 1 #define CAC_OBJECT_TYPE_TLV_FILE 4 +#define CAC_OBJECT_TYPE_GENERIC 5 /* * CAC private data per card state @@ -169,6 +206,7 @@ cac_object_t *pki_current; /* current pki object _ctl function */ list_t general_list; /* list of general containers */ cac_object_t *general_current; /* current object for _ctl function */ + sc_path_t *aca_path; /* ACA path to be selected before pin verification */ } cac_private_data_t; #define CAC_DATA(card) ((cac_private_data_t*)card->drv_data) @@ -207,6 +245,7 @@ { free(priv->cac_id); free(priv->cache_buf); + free(priv->aca_path); list_destroy(&priv->pki_list); list_destroy(&priv->general_list); free(priv); @@ -227,7 +266,12 @@ #define CAC_2_RID "\xA0\x00\x00\x01\x16" #define CAC_1_RID "\xA0\x00\x00\x00\x79" -#define CAC_1_CM_AID "\xA0\x00\x00\x00\x30\x00\00" + +static const sc_path_t cac_ACA_Path = { + "", 0, + 0,0,SC_PATH_TYPE_DF_NAME, + { CAC_TO_AID(CAC_1_RID "\x10\x00") } +}; static const sc_path_t cac_CCC_Path = { "", 0, @@ -235,54 +279,59 @@ { CAC_TO_AID(CAC_2_RID "\xDB\x00") } }; -#define MAX_CAC_SLOTS 10 /* arbitrary, just needs to be 'large enough' */ +#define MAX_CAC_SLOTS 16 /* Maximum number of slots is 16 now */ /* default certificate labels for the CAC card */ static const char *cac_labels[MAX_CAC_SLOTS] = { "CAC ID Certificate", "CAC Email Signature Certificate", "CAC Email Encryption Certificate", - "CAC Cert 3", "CAC Cert 4", "CAC Cert 5", "CAC Cert 6", "CAC Cert 7", "CAC Cert 8", - "CAC Cert 9" + "CAC Cert 9", + "CAC Cert 10", + "CAC Cert 11", + "CAC Cert 12", + "CAC Cert 13", + "CAC Cert 14", + "CAC Cert 15", + "CAC Cert 16" }; -/* template for a cac1 pki object */ -static const cac_object_t cac_cac1_pki_obj = { +/* template for a CAC pki object */ +static const cac_object_t cac_cac_pki_obj = { "CAC Certificate", 0x0, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x01\x00") } } }; -/* template for cac1 cuid */ -static const cac_cuid_t cac_cac1_cuid = { +/* template for emulated cuid */ +static const cac_cuid_t cac_cac_cuid = { { 0xa0, 0x00, 0x00, 0x00, 0x79 }, 2, 2, 0 }; /* - * CAC-1 general objectes defined in 4.3.1.2 of CAC Applet Developer Guide Version 1.0. + * CAC general objects defined in 4.3.1.2 of CAC Applet Developer Guide Version 1.0. * doubles as a source for CAC-2 labels. */ -static const cac_object_t cac_1_objects[] = { +static const cac_object_t cac_objects[] = { { "Person Instance", 0x200, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x02\x00") }}}, { "Personnel", 0x201, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x02\x01") }}}, { "Benefits", 0x202, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x02\x02") }}}, - { "Other Benefits", 0x202, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, - { CAC_TO_AID(CAC_1_RID "\x02\x02") }}}, + { "Other Benefits", 0x203, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, + { CAC_TO_AID(CAC_1_RID "\x02\x03") }}}, { "PKI Credential", 0x2FD, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x02\xFD") }}}, { "PKI Certificate", 0x2FE, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, { CAC_TO_AID(CAC_1_RID "\x02\xFE") }}}, }; -static const int cac_1_object_count = sizeof(cac_1_objects)/sizeof(cac_1_objects[0]); - +static const int cac_object_count = sizeof(cac_objects)/sizeof(cac_objects[0]); /* * use the object id to find our object info on the object in our CAC-1 list @@ -291,9 +340,9 @@ { int i; - for (i=0; i < cac_1_object_count; i++) { - if (cac_1_objects[i].fd == object_id) { - return &cac_1_objects[i]; + for (i = 0; i < cac_object_count; i++) { + if (cac_objects[i].fd == object_id) { + return &cac_objects[i]; } } return NULL; @@ -319,7 +368,7 @@ * an internal 4096 byte buffer is used, and a copy is returned to the * caller. that need to be freed by the caller. * - * modelled after a similiar function in card-piv.c + * modelled after a similar function in card-piv.c */ static int cac_apdu_io(sc_card_t *card, int ins, int p1, int p2, @@ -390,9 +439,7 @@ goto err; } - if (apdu.sw1 == 0x61) { - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - } + r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card returned error "); @@ -417,6 +464,48 @@ } /* + * Get ACR of currently ACA applet identified by the acr_type + * 5.3.3.5 Get ACR APDU + */ +static int +cac_get_acr(sc_card_t *card, int acr_type, u8 **out_buf, size_t *out_len) +{ + u8 *out = NULL; + /* XXX assuming it will not be longer than 255 B */ + size_t len = 256; + int r; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* for simplicity we support only ACR without arguments now */ + if (acr_type != 0x00 && acr_type != 0x10 + && acr_type != 0x20 && acr_type != 0x21) { + return SC_ERROR_INVALID_ARGUMENTS; + } + + r = cac_apdu_io(card, CAC_INS_GET_ACR, acr_type, 0, NULL, 0, &out, &len); + if (len == 0) { + r = SC_ERROR_FILE_NOT_FOUND; + } + if (r < 0) + goto fail; + + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "got %"SC_FORMAT_LEN_SIZE_T"u bytes out=%p", len, out); + + *out_len = len; + *out_buf = out; + return SC_SUCCESS; + +fail: + if (out) + free(out); + *out_buf = NULL; + *out_len = 0; + return r; +} + +/* * Read a CAC TLV file. Parameters specify if the TLV file is TL (Tag/Length) file or a V (value) file */ #define HIGH_BYTE_OF_SHORT(x) (((x)>> 8) & 0xff) @@ -440,6 +529,9 @@ len = sizeof(count); out_ptr = count; r = cac_apdu_io(card, CAC_INS_READ_FILE, 0, 0, ¶ms[0], sizeof(params), &out_ptr, &len); + if (len == 0) { + r = SC_ERROR_FILE_NOT_FOUND; + } if (r < 0) goto fail; @@ -457,6 +549,10 @@ params[1] = len; r = cac_apdu_io(card, CAC_INS_READ_FILE, HIGH_BYTE_OF_SHORT(offset), LOW_BYTE_OF_SHORT(offset), ¶ms[0], sizeof(params), &out_ptr, &len); + /* if there is no data, assume there is no file */ + if (len == 0) { + r = SC_ERROR_FILE_NOT_FOUND; + } if (r < 0) { goto fail; } @@ -471,91 +567,6 @@ return r; } -/* - * OLD cac read certificate, only use with CAC-1 card. - */ -static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_len) -{ - u8 buf[CAC_MAX_SIZE]; - u8 *out_ptr; - size_t size = 0; - size_t left = 0; - size_t len, next_len; - sc_apdu_t apdu; - int r = SC_SUCCESS; - - - /* get the size */ - size = left = *out_buf ? *out_len : sizeof(buf); - out_ptr = *out_buf ? *out_buf : buf; - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 ); - next_len = MIN(left, 100); - for (; left > 0; left -= len, out_ptr += len) { - len = next_len; - apdu.resp = out_ptr; - apdu.le = len; - apdu.resplen = left; - - r = sc_transmit_apdu(card, &apdu); - if (r < 0) { - break; - } - /* in the old CAC-1, 0x63 means 'more data' in addition to 'pin failed' */ - if (apdu.sw1 != 0x63) { - /* we've either finished reading, or hit an error, break */ - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - left -= len; - break; - } - next_len = MIN(left,apdu.sw2); - } - if (r < 0) { - return r; - } - r = size - left; - if (*out_buf == NULL) { - *out_buf = malloc(r); - if (*out_buf == NULL) { - return SC_ERROR_OUT_OF_MEMORY; - } - memcpy(*out_buf, buf, r); - } - *out_len = r; - return r; -} - -/* Create a fake tag/length file in Simple TLV for cac1 cards based on the val_len. - */ -int cac_cac1_get_cert_tag(sc_card_t *card, size_t val_len, u8 **tlp, size_t *tl_len_p) -{ - static const u8 cac_cac1_cert_tag[] = { CAC_TAG_CERTINFO, 1, CAC_TAG_CERTIFICATE, 0xff, 0, 0 }; - u8 *tl, *tl1, *tl2; - size_t tl_len; - int rv = SC_SUCCESS; - - tl_len = sizeof(cac_cac1_cert_tag); - tl = malloc(tl_len); - if (tl == NULL) - return SC_ERROR_OUT_OF_MEMORY; - memcpy(tl, cac_cac1_cert_tag, tl_len); - - rv = sc_simpletlv_put_tag(CAC_TAG_CERTINFO, 1, tl, tl_len, &tl1); - if (rv != SC_SUCCESS) - goto failure; - - val_len -= 1; /* one byte is CERTINFO Value */ - tl_len -= (tl1 - tl); - rv = sc_simpletlv_put_tag(CAC_TAG_CERTIFICATE, val_len, tl1, tl_len, &tl2); - if (rv != SC_SUCCESS) - goto failure; - - *tlp = tl; - *tl_len_p = (tl2 - tl); - return SC_SUCCESS; -failure: - free(tl); - return rv; -} /* * Callers of this may be expecting a certificate, @@ -602,27 +613,15 @@ if (priv->object_type <= 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); - if ((card->type == SC_CARD_TYPE_CAC_I) && (priv->object_type == CAC_OBJECT_TYPE_CERT)) { - /* SPICE smart card emulator only presents CAC-1 cards with the old CAC-1 interface as - * certs. If we are a cac 1 card, use the old interface */ - r = cac_cac1_get_certificate(card, &val, &val_len); - if (r < 0) - goto done; - - r = cac_cac1_get_cert_tag(card, val_len, &tl, &tl_len); - if (r < 0) - goto done; - } else { - r = cac_read_file(card, CAC_FILE_TAG, &tl, &tl_len); - if (r < 0) { - goto done; - } - - r = cac_read_file(card, CAC_FILE_VALUE, &val, &val_len); - if (r < 0) - goto done; + r = cac_read_file(card, CAC_FILE_TAG, &tl, &tl_len); + if (r < 0) { + goto done; } + r = cac_read_file(card, CAC_FILE_VALUE, &val, &val_len); + if (r < 0) + goto done; + switch (priv->object_type) { case CAC_OBJECT_TYPE_TLV_FILE: tlv_len = tl_len + val_len; @@ -634,11 +633,12 @@ priv->cache_buf_len = tlv_len; for (tl_ptr = tl, val_ptr=val, tlv_ptr = priv->cache_buf; - tl_len > 2 && val_len > 0 && tlv_len > 0; + tl_len >= 2 && tlv_len > 0; val_len -= len, tlv_len -= len, val_ptr += len, tlv_ptr += len) { /* get the tag and the length */ tl_start = tl_ptr; - if (sc_simpletlv_read_tag(&tl_ptr, tl_len, &tag, &len) != SC_SUCCESS) + r = sc_simpletlv_read_tag(&tl_ptr, tl_len, &tag, &len); + if (r != SC_SUCCESS && r != SC_ERROR_TLV_END_OF_CONTENTS) break; tl_head_len = (tl_ptr - tl_start); sc_simpletlv_put_tag(tag, len, tlv_ptr, tlv_len, &tlv_ptr); @@ -647,6 +647,8 @@ /* don't crash on bad data */ if (val_len < len) { + sc_log(card->ctx, "Received too long value %"SC_FORMAT_LEN_SIZE_T"u, " + "while only %"SC_FORMAT_LEN_SIZE_T"u left. Truncating", len, val_len); len = val_len; } /* if we run out of return space, truncate */ @@ -665,13 +667,21 @@ cert_len = 0; cert_ptr = NULL; cert_type = 0; - tl_head_len = 2; - for (tl_ptr = tl, val_ptr=val; tl_len >= 2; - val_len -= len, val_ptr += len, tl_len -= tl_head_len) { + for (tl_ptr = tl, val_ptr = val; tl_len >= 2; + val_len -= len, val_ptr += len, tl_len -= tl_head_len) { tl_start = tl_ptr; - if (sc_simpletlv_read_tag(&tl_ptr, tl_len, &tag, &len) != SC_SUCCESS) + r = sc_simpletlv_read_tag(&tl_ptr, tl_len, &tag, &len); + if (r != SC_SUCCESS && r != SC_ERROR_TLV_END_OF_CONTENTS) break; tl_head_len = tl_ptr - tl_start; + + /* incomplete value */ + if (val_len < len) { + sc_log(card->ctx, "Read incomplete value %"SC_FORMAT_LEN_SIZE_T"u, " + "while only %"SC_FORMAT_LEN_SIZE_T"u left", len, val_len); + break; + } + if (tag == CAC_TAG_CERTIFICATE) { cert_len = len; cert_ptr = val_ptr; @@ -681,8 +691,8 @@ cert_type = *val_ptr; } } - if ((val_len < len) || (tl_len < tl_head_len)) { - break; + if (tag == CAC_TAG_MSCUID) { + sc_log_hex(card->ctx, "MSCUID", val_ptr, len); } } /* if the info byte is 1, then the cert is compressed, decompress it */ @@ -709,8 +719,14 @@ goto done; } break; + case CAC_OBJECT_TYPE_GENERIC: + /* TODO + * We have some two buffers in unknown encoding that we + * need to present in PKCS#15 layer. + */ default: /* Unknown object type */ + sc_log(card->ctx, "Unknown object type: %x", priv->object_type); r = SC_ERROR_INTERNAL; goto done; } @@ -782,12 +798,22 @@ } if (priv->cac_id_len) { serial->len = MIN(priv->cac_id_len, SC_MAX_SERIALNR); - memcpy(serial->value, priv->cac_id, priv->cac_id_len); - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); + memcpy(serial->value, priv->cac_id, serial->len); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND); } +static int cac_get_ACA_path(sc_card_t *card, sc_path_t *path) +{ + cac_private_data_t * priv = CAC_DATA(card); + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); + if (priv->aca_path) { + *path = *priv->aca_path; + } + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); +} static int cac_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) { @@ -800,6 +826,8 @@ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); } switch(cmd) { + case SC_CARDCTL_CAC_GET_ACA_PATH: + return cac_get_ACA_path(card, (sc_path_t *) ptr); case SC_CARDCTL_GET_SERIALNR: return cac_get_serial_nr_from_CUID(card, (sc_serial_number_t *) ptr); case SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS: @@ -821,42 +849,23 @@ static int cac_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { + /* CAC requires 8 byte response */ u8 rbuf[8]; - u8 *rbufp = NULL; - size_t rbuflen = 0; + u8 *rbufp = &rbuf[0]; + size_t out_len = sizeof rbuf; int r; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len); - - r = sc_lock(card); - if (r != SC_SUCCESS) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); - + LOG_FUNC_CALLED(card->ctx); - /* CAC requires 8 byte response */ - while (len > 0) { - size_t n; + r = cac_apdu_io(card, 0x84, 0x00, 0x00, NULL, 0, &rbufp, &out_len); + LOG_TEST_RET(card->ctx, r, "Could not get challenge"); - rbufp = &rbuf[0]; - rbuflen = sizeof(rbuf); - r = cac_apdu_io(card, 0x84, 0x00, 0x00, NULL, 0, &rbufp, &rbuflen); - if (r < 0) { - sc_unlock(card); - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); - } - n = len > rbuflen ? rbuflen : len; - memcpy(rnd, rbufp, n); - len -= n; - rnd += n; + if (len < out_len) { + out_len = len; } + memcpy(rnd, rbuf, out_len); - r = sc_unlock(card); - - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); - + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, (int) out_len); } static int cac_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) @@ -943,7 +952,7 @@ if (rbuflen != 0) { int n = MIN(rbuflen, outplen); memcpy(outp,rbuf, n); - outp += n; + /*outp += n; unused */ outplen -= n; } free(rbuf); @@ -980,6 +989,187 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, cac_rsa_op(card, data, datalen, out, outlen)); } +static int cac_parse_properties_object(sc_card_t *card, u8 type, + u8 *data, size_t data_len, cac_properties_object_t *object) +{ + size_t len; + u8 *val, *val_end, tag; + int parsed = 0; + + if (data_len < 11) + return -1; + + /* Initilize: non-PKI applet */ + object->privatekey = 0; + + val = data; + val_end = data + data_len; + for (; val < val_end; val += len) { + /* get the tag and the length */ + if (sc_simpletlv_read_tag(&val, val_end - val, &tag, &len) != SC_SUCCESS) + break; + + switch (tag) { + case CAC_TAG_OBJECT_ID: + if (len != 2) { + sc_log(card->ctx, "TAG: Object ID: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Object ID = 0x%02x 0x%02x", val[0], val[1]); + memcpy(&object->oid, val, 2); + parsed++; + break; + + case CAC_TAG_BUFFER_PROPERTIES: + if (len != 5) { + sc_log(card->ctx, "TAG: Buffer Properties: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + /* First byte is "Type of Tag Supported" */ + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Buffer Properties: Type of Tag Supported = 0x%02x", + val[0]); + object->simpletlv = val[0]; + parsed++; + break; + + case CAC_TAG_PKI_PROPERTIES: + /* 4th byte is "Private Key Initialized" */ + if (len != 4) { + sc_log(card->ctx, "TAG: PKI Properties: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + if (type != CAC_TAG_PKI_OBJECT) { + sc_log(card->ctx, "TAG: PKI Properties outside of PKI Object"); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: PKI Properties: Private Key Initialized = 0x%02x", + val[2]); + object->privatekey = val[2]; + parsed++; + break; + + default: + /* ignore tags we don't understand */ + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Unknown (0x%02x)",tag ); + break; + } + } + if (parsed < 2) + return SC_ERROR_INVALID_DATA; + + return SC_SUCCESS; +} + +static int cac_get_properties(sc_card_t *card, cac_properties_t *prop) +{ + u8 *rbuf = NULL; + size_t rbuflen = 0, len; + u8 *val, *val_end, tag; + size_t i = 0; + int r; + prop->num_objects = 0; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + r = cac_apdu_io(card, CAC_INS_GET_PROPERTIES, 0x01, 0x00, NULL, 0, + &rbuf, &rbuflen); + if (r < 0) + return r; + + val = rbuf; + val_end = val + rbuflen; + for (; val < val_end; val += len) { + /* get the tag and the length */ + if (sc_simpletlv_read_tag(&val, val_end - val, &tag, &len) != SC_SUCCESS) + break; + + switch (tag) { + case CAC_TAG_APPLET_INFORMATION: + if (len != 5) { + sc_log(card->ctx, "TAG: Applet Information: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Applet Information: Family: 0x%0x", val[0]); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + " Applet Version: 0x%02x 0x%02x 0x%02x 0x%02x", + val[1], val[2], val[3], val[4]); + break; + + case CAC_TAG_NUMBER_OF_OBJECTS: + if (len != 1) { + sc_log(card->ctx, "TAG: Num objects: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Num objects = %hhd", *val); + /* make sure we do not overrun buffer */ + prop->num_objects = MIN(val[0], CAC_MAX_OBJECTS); + break; + + case CAC_TAG_TV_BUFFER: + if (len != 17) { + sc_log(card->ctx, "TAG: TV Object: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: TV Object nr. %"SC_FORMAT_LEN_SIZE_T"u", i); + if (i >= CAC_MAX_OBJECTS) { + free(rbuf); + return SC_SUCCESS; + } + + if (cac_parse_properties_object(card, tag, val, len, + &prop->objects[i]) == SC_SUCCESS) + i++; + break; + + case CAC_TAG_PKI_OBJECT: + if (len != 17) { + sc_log(card->ctx, "TAG: PKI Object: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: PKI Object nr. %"SC_FORMAT_LEN_SIZE_T"u", i); + if (i >= CAC_MAX_OBJECTS) { + free(rbuf); + return SC_SUCCESS; + } + + if (cac_parse_properties_object(card, tag, val, len, + &prop->objects[i]) == SC_SUCCESS) + i++; + break; + + default: + /* ignore tags we don't understand */ + sc_log(card->ctx, "TAG: Unknown (0x%02x), len=%" + SC_FORMAT_LEN_SIZE_T"u", tag, len); + break; + } + } + free(rbuf); + /* sanity */ + if (i != prop->num_objects) + sc_log(card->ctx, "The announced number of objects (%u) " + "did not match reality (%"SC_FORMAT_LEN_SIZE_T"u)", + prop->num_objects, i); + prop->num_objects = i; + + return SC_SUCCESS; +} + /* * CAC cards use SC_PATH_SELECT_OBJECT_ID rather than SC_PATH_SELECT_FILE_ID. In order to use more * of the PKCS #15 structure, we call the selection SC_PATH_SELECT_FILE_ID, but we set p1 to 2 instead @@ -1034,11 +1224,12 @@ * and object type here: */ if (priv) { /* don't record anything if we haven't been initialized yet */ - priv->object_type = CAC_OBJECT_TYPE_TLV_FILE; + priv->object_type = CAC_OBJECT_TYPE_GENERIC; if (cac_is_cert(priv, in_path)) { priv->object_type = CAC_OBJECT_TYPE_CERT; } - /* forget any old cacheed values */ + + /* forget any old cached values */ if (priv->cache_buf) { free(priv->cache_buf); priv->cache_buf = NULL; @@ -1097,16 +1288,18 @@ apdu.p2 = 0; /* first record, return FCI */ } else { - apdu.p2 = (type == SC_CARD_TYPE_CAC_I)? 0x00 : 0x0C; + apdu.p2 = 0x0C; } r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, r, "APDU transmit failed"); + if (file_out == NULL) { /* For some cards 'SELECT' can be only with request to return FCI/FCP. */ r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (apdu.sw1 == 0x6A && apdu.sw2 == 0x86) { apdu.p2 = 0x00; + apdu.resplen = sizeof(buf); if (sc_transmit_apdu(card, &apdu) == SC_SUCCESS) r = sc_check_sw(card, apdu.sw1, apdu.sw2); } @@ -1119,7 +1312,37 @@ if (r) LOG_FUNC_RETURN(ctx, r); - /* CAC cards enver return FCI, fake one */ + /* This needs to come after the applet selection */ + if (priv && in_path->len >= 2) { + /* get applet properties to know if we can treat the + * buffer as SimpleLTV and if we have PKI applet. + * + * Do this only if we select applets for reading + * (not during driver initialization) + */ + cac_properties_t prop; + size_t i = -1; + + r = cac_get_properties(card, &prop); + if (r == SC_SUCCESS) { + for (i = 0; i < prop.num_objects; i++) { + sc_log(card->ctx, "Searching for our OID: 0x%02x 0x%02x = 0x%02x 0x%02x", + prop.objects[i].oid[0], prop.objects[i].oid[1], + in_path->value[0], in_path->value[1]); + if (memcmp(prop.objects[i].oid, + in_path->value, 2) == 0) + break; + } + } + if (i < prop.num_objects) { + if (prop.objects[i].privatekey) + priv->object_type = CAC_OBJECT_TYPE_CERT; + else if (prop.objects[i].simpletlv == 0) + priv->object_type = CAC_OBJECT_TYPE_TLV_FILE; + } + } + + /* CAC cards never return FCI, fake one */ file = sc_file_new(); if (file == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); @@ -1154,6 +1377,12 @@ return cac_select_file_by_type(card, &cac_CCC_Path, NULL, SC_CARD_TYPE_CAC_II); } +/* Select ACA in non-standard location */ +static int cac_select_ACA(sc_card_t *card) +{ + return cac_select_file_by_type(card, &cac_ACA_Path, NULL, SC_CARD_TYPE_CAC_II); +} + static int cac_path_from_cardurl(sc_card_t *card, sc_path_t *path, cac_card_url_t *val, int len) { if (len < 10) { @@ -1161,9 +1390,9 @@ } sc_mem_clear(path, sizeof(sc_path_t)); memcpy(path->aid.value, &val->rid, sizeof(val->rid)); - memcpy(&path->aid.value[5], &val->applicationID, sizeof(val->applicationID)); + memcpy(&path->aid.value[5], val->applicationID, sizeof(val->applicationID)); path->aid.len = sizeof(val->rid) + sizeof(val->applicationID); - memcpy(path->value, &val->objectID, sizeof(val->objectID)); + memcpy(path->value, val->objectID, sizeof(val->objectID)); path->len = sizeof(val->objectID); path->type = SC_PATH_TYPE_FILE_ID; sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, @@ -1182,6 +1411,64 @@ return SC_SUCCESS; } +static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int aid_len) +{ + cac_object_t new_object; + cac_properties_t prop; + size_t i; + int r; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* Search for PKI applets (7 B). Ignore generic objects for now */ + if (aid_len != 7 || (memcmp(aid, CAC_1_RID "\x01", 6) != 0 + && memcmp(aid, CAC_1_RID "\x00", 6) != 0)) + return SC_SUCCESS; + + sc_mem_clear(&new_object.path, sizeof(sc_path_t)); + memcpy(new_object.path.aid.value, aid, aid_len); + new_object.path.aid.len = aid_len; + + /* Call without OID set will just select the AID without subseqent + * OID selection, which we need to figure out just now + */ + cac_select_file_by_type(card, &new_object.path, NULL, SC_CARD_TYPE_CAC_II); + r = cac_get_properties(card, &prop); + if (r < 0) + return SC_ERROR_INTERNAL; + + for (i = 0; i < prop.num_objects; i++) { + /* don't fail just because we have more certs than we can support */ + if (priv->cert_next >= MAX_CAC_SLOTS) + return SC_SUCCESS; + + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "ACA: pki_object found, cert_next=%d (%s), privkey=%d", + priv->cert_next, cac_labels[priv->cert_next], + prop.objects[i].privatekey); + + /* If the private key is not initialized, we can safely + * ignore this object here, but increase the pointer to follow + * the certificate labels + */ + if (!prop.objects[i].privatekey) { + priv->cert_next++; + continue; + } + + /* OID here has always 2B */ + memcpy(new_object.path.value, &prop.objects[i].oid, 2); + new_object.path.len = 2; + new_object.path.type = SC_PATH_TYPE_FILE_ID; + new_object.name = cac_labels[priv->cert_next]; + new_object.fd = priv->cert_next+1; + cac_add_object_to_list(&priv->pki_list, &new_object); + priv->cert_next++; + } + + return SC_SUCCESS; +} + static int cac_parse_cardurl(sc_card_t *card, cac_private_data_t *priv, cac_card_url_t *val, int len) { cac_object_t new_object; @@ -1221,7 +1508,7 @@ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CARDURL: ski_object found"); break; default: - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CARDURL: unkown object_object found (type=0x%x)", val->cardApplicationType); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CARDURL: unknown object_object found (type=0x%02x)", val->cardApplicationType); /* don't fail just because there is an unknown object in the CCC */ break; } @@ -1268,8 +1555,15 @@ for (; (tl < tl_end) && (val< val_end); val += len) { /* get the tag and the length */ u8 tag; - if (sc_simpletlv_read_tag(&tl, tl_end - tl, &tag, &len) != SC_SUCCESS) + r = sc_simpletlv_read_tag(&tl, tl_end - tl, &tag, &len); + if (r != SC_SUCCESS && r != SC_ERROR_TLV_END_OF_CONTENTS) { + sc_log(card->ctx, "Failed to parse tag from buffer"); break; + } + if (val + len > val_end) { + sc_log(card->ctx, "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } switch (tag) { case CAC_TAG_CUID: sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:CUID"); @@ -1278,9 +1572,24 @@ return r; break; case CAC_TAG_CC_VERSION_NUMBER: + if (len != 1) { + sc_log(card->ctx, "TAG: CC Version: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + /* ignore the version numbers for now */ + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: CC Version = 0x%02x", *val); + break; case CAC_TAG_GRAMMAR_VERION_NUMBER: + if (len != 1) { + sc_log(card->ctx, "TAG: Grammar Version: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } /* ignore the version numbers for now */ - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:Version"); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Grammar Version = 0x%02x", *val); break; case CAC_TAG_CARDURL: sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:CARDURL"); @@ -1292,9 +1601,15 @@ * The following are really for file systems cards. This code only cares about CAC VM cards */ case CAC_TAG_PKCS15: - /* should verify that this is '0'. If it's not zero, we should drop out of here and - * let the PKCS 15 code handle this card */ - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:PKCS5"); + if (len != 1) { + sc_log(card->ctx, "TAG: PKCS15: " + "Invalid length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + /* TODO should verify that this is '0'. If it's not + * zero, we should drop out of here and let the PKCS 15 + * code handle this card */ + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG: PKCS15 = 0x%02x", *val); break; case CAC_TAG_DATA_MODEL: case CAC_TAG_CARD_APDU: @@ -1302,11 +1617,11 @@ case CAC_TAG_STATUS_TUPLES: case CAC_TAG_REDIRECTION: case CAC_TAG_ERROR_CODES: - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:FSSpecific(0x%x)", tag); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:FSSpecific(0x%02x)", tag); break; case CAC_TAG_ACCESS_CONTROL: - /* handle access control later */ - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:ACCESS Control"); + /* TODO handle access control later */ + sc_log_hex(card->ctx, "TAG:ACCESS Control", val, len); break; case CAC_TAG_NEXT_CCC: sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:NEXT CCC"); @@ -1324,7 +1639,7 @@ break; default: /* ignore tags we don't understand */ - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:Unknown (0x%x)",tag ); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"TAG:Unknown (0x%02x)",tag ); break; } } @@ -1355,48 +1670,124 @@ return r; } -/* select a CAC-1 pki applet by index */ +/* Service Applet Table (Table 5-21) should list all the applets on the + * card, which is a good start if we don't have CCC + */ +static int cac_parse_ACA_service(sc_card_t *card, cac_private_data_t *priv, + u8 *val, size_t val_len) +{ + size_t len = 0; + u8 *val_end = val + val_len; + int r; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + for (; val < val_end; val += len) { + /* get the tag and the length */ + u8 tag; + if (sc_simpletlv_read_tag(&val, val_end - val, &tag, &len) != SC_SUCCESS) + break; + + switch (tag) { + case CAC_TAG_APPLET_FAMILY: + if (len != 5) { + sc_log(card->ctx, "TAG: Applet Information: " + "bad length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Applet Information: Family: 0x%02x", val[0]); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + " Applet Version: 0x%02x 0x%02x 0x%02x 0x%02x", + val[1], val[2], val[3], val[4]); + break; + case CAC_TAG_NUMBER_APPLETS: + if (len != 1) { + sc_log(card->ctx, "TAG: Num applets: " + "bad length %"SC_FORMAT_LEN_SIZE_T"u", len); + break; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Num applets = %hhd", *val); + break; + case CAC_TAG_APPLET_ENTRY: + /* Make sure we match the outer length */ + if (len < 3 || val[2] != len - 3) { + sc_log(card->ctx, "TAG: Applet Entry: " + "bad length (%"SC_FORMAT_LEN_SIZE_T + "u) or length of internal buffer", len); + break; + } + sc_debug_hex(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Applet Entry: AID", &val[3], val[2]); + /* This is SimpleTLV prefixed with applet ID (1B) */ + r = cac_parse_aid(card, priv, &val[3], val[2]); + if (r < 0) + return r; + break; + default: + /* ignore tags we don't understand */ + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "TAG: Unknown (0x%02x)", tag); + break; + } + } + return SC_SUCCESS; +} + +/* select a CAC pki applet by index */ static int cac_select_pki_applet(sc_card_t *card, int index) { - sc_path_t applet_path = cac_cac1_pki_obj.path; + sc_path_t applet_path = cac_cac_pki_obj.path; applet_path.aid.value[applet_path.aid.len-1] = index; - return cac_select_file_by_type(card, &applet_path, NULL, SC_CARD_TYPE_CAC_I); + return cac_select_file_by_type(card, &applet_path, NULL, SC_CARD_TYPE_CAC_II); } /* - * Find the first existing CAC-1 applet. If none found, then this isn't a CAC-1 + * Find the first existing CAC applet. If none found, then this isn't a CAC */ static int cac_find_first_pki_applet(sc_card_t *card, int *index_out) { int r, i; - for (i=0; i < MAX_CAC_SLOTS; i++) { + for (i = 0; i < MAX_CAC_SLOTS; i++) { r = cac_select_pki_applet(card, i); if (r == SC_SUCCESS) { + /* Try to read first two bytes of the buffer to + * make sure it is not just malfunctioning card + */ + u8 params[2] = {CAC_FILE_TAG, 2}; + u8 data[2], *out_ptr = data; + size_t len = 2; + r = cac_apdu_io(card, CAC_INS_READ_FILE, 0, 0, + ¶ms[0], sizeof(params), &out_ptr, &len); + if (r != 2) + continue; + *index_out = i; - return r; + return SC_SUCCESS; } } return SC_ERROR_OBJECT_NOT_FOUND; } /* - * CAC-1 has been found, identify all the certs and general containers. - * This emulates CAC-2's CCC. + * This emulates CCC for Alt tokens, that do not come with CCC nor ACA applets */ -static int cac_populate_cac_1(sc_card_t *card, int index, cac_private_data_t *priv) +static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t *priv) { int r, i; - cac_object_t pki_obj = cac_cac1_pki_obj; + cac_object_t pki_obj = cac_cac_pki_obj; u8 buf[100]; u8 *val; size_t val_len; /* populate PKI objects */ - for (i=index; i < MAX_CAC_SLOTS; i++) { + for (i = index; i < MAX_CAC_SLOTS; i++) { r = cac_select_pki_applet(card, i); if (r == SC_SUCCESS) { pki_obj.name = cac_labels[i]; - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CAC1: pki_object found, cert_next=%d (%s),", i, pki_obj.name); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "CAC: pki_object found, cert_next=%d (%s),", i, pki_obj.name); pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i; pki_obj.fd = i+1; /* don't use id of zero */ cac_add_object_to_list(&priv->pki_list, &pki_obj); @@ -1404,18 +1795,21 @@ } /* populate non-PKI objects */ - for (i=0; i < cac_1_object_count; i++) { - r = cac_select_file_by_type(card, &cac_1_objects[i].path, NULL, SC_CARD_TYPE_CAC_I); + for (i=0; i < cac_object_count; i++) { + r = cac_select_file_by_type(card, &cac_objects[i].path, NULL, + SC_CARD_TYPE_CAC_II); if (r == SC_SUCCESS) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CAC1: obj_object found, cert_next=%d (%s),", i, cac_1_objects[i].name); - cac_add_object_to_list(&priv->general_list, &cac_1_objects[i]); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "CAC: obj_object found, cert_next=%d (%s),", + i, cac_objects[i].name); + cac_add_object_to_list(&priv->general_list, &cac_objects[i]); } } /* * create a cuid to simulate the cac 2 cuid. */ - priv->cuid = cac_cac1_cuid; + priv->cuid = cac_cac_cuid; /* create a serial number by hashing the first 100 bytes of the * first certificate on the card */ r = cac_select_pki_applet(card, index); @@ -1423,9 +1817,8 @@ return r; /* shouldn't happen unless the card has been removed or is malfunctioning */ } val = buf; - val_len = sizeof(buf); - r = cac_cac1_get_certificate(card, &val, &val_len); - if (r >= 0) { + val_len = cac_read_binary(card, 0, val, sizeof(buf), 0); + if (val_len > 0) { priv->cac_id = malloc(20); if (priv->cac_id == NULL) { return SC_ERROR_OUT_OF_MEMORY; @@ -1433,6 +1826,8 @@ #ifdef ENABLE_OPENSSL SHA1(val, val_len, priv->cac_id); priv->cac_id_len = 20; + sc_debug_hex(card->ctx, SC_LOG_DEBUG_VERBOSE, + "cuid", priv->cac_id, priv->cac_id_len); #else sc_log(card->ctx, "OpenSSL Required"); return SC_ERROR_NOT_SUPPORTED; @@ -1441,6 +1836,34 @@ return SC_SUCCESS; } +static int cac_process_ACA(sc_card_t *card, cac_private_data_t *priv) +{ + int r; + u8 *val = NULL; + size_t val_len; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* Assuming ACA is already selected */ + r = cac_get_acr(card, CAC_ACR_SERVICE, &val, &val_len); + if (r < 0) + goto done; + + r = cac_parse_ACA_service(card, priv, val, val_len); + if (r == SC_SUCCESS) { + priv->aca_path = malloc(sizeof(sc_path_t)); + if (!priv->aca_path) { + r = SC_ERROR_OUT_OF_MEMORY; + goto done; + } + memcpy(priv->aca_path, &cac_ACA_Path, sizeof(sc_path_t)); + } +done: + if (val) + free(val); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); +} + /* * Look for a CAC card. If it exists, initialize our data structures */ @@ -1473,10 +1896,10 @@ } } - /* is this a CAC-1 specified in DoD "CAC Applet Developer Guide" version 1.0 September 2002 */ - r = cac_find_first_pki_applet(card, &index); + /* Even some ALT tokens can be missing CCC so we should try with ACA */ + r = cac_select_ACA(card); if (r == SC_SUCCESS) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "applet found, is CAC-1"); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "ACA found, is CAC-2 without CCC"); if (!initialize) /* match card only */ return r; @@ -1485,13 +1908,34 @@ if (!priv) return SC_ERROR_OUT_OF_MEMORY; } - r = cac_populate_cac_1(card, index, priv); + r = cac_process_ACA(card, priv); if (r == SC_SUCCESS) { - card->type = SC_CARD_TYPE_CAC_I; + card->type = SC_CARD_TYPE_CAC_II; card->drv_data = priv; return r; } } + + /* is this a CAC Alt token without any accompanying structures */ + r = cac_find_first_pki_applet(card, &index); + if (r == SC_SUCCESS) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "PKI applet found, is bare CAC Alt"); + if (!initialize) /* match card only */ + return r; + + if (!priv) { + priv = cac_new_private_data(); + if (!priv) + return SC_ERROR_OUT_OF_MEMORY; + } + card->drv_data = priv; /* needed for the read_binary() */ + r = cac_populate_cac_alt(card, index, priv); + if (r == SC_SUCCESS) { + card->type = SC_CARD_TYPE_CAC_II; + return r; + } + card->drv_data = NULL; /* reset on failure */ + } if (priv) { cac_free_private_data(priv); } @@ -1522,11 +1966,11 @@ r = cac_find_and_initialize(card, 1); if (r < 0) { - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_CARD); } flags = SC_ALGORITHM_RSA_RAW; - _sc_card_add_rsa_alg(card, 1024, flags, 0); /* manditory */ + _sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */ _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ diff -Nru opensc-0.17.0/src/libopensc/card-cardos.c opensc-0.19.0/src/libopensc/card-cardos.c --- opensc-0.17.0/src/libopensc/card-cardos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-cardos.c 2018-09-13 11:47:21.000000000 +0000 @@ -42,7 +42,7 @@ NULL, 0, NULL }; -static struct sc_atr_table cardos_atrs[] = { +static const struct sc_atr_table cardos_atrs[] = { /* 4.0 */ { "3b:e2:00:ff:c1:10:31:fe:55:c8:02:9c", NULL, NULL, SC_CARD_TYPE_CARDOS_GENERIC, 0, NULL }, /* Italian eID card, postecert */ @@ -59,6 +59,7 @@ /* CardOS v5.0 */ { "3b:d2:18:00:81:31:fe:58:c9:01:14", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, /* CardOS v5.3 */ + { "3b:d2:18:00:81:31:fe:58:c9:02:17", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, { "3b:d2:18:00:81:31:fe:58:c9:03:16", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -170,8 +171,9 @@ size_t data_field_length; sc_apdu_t apdu; u8 rbuf[2]; + int r; - card->name = "CardOS M4"; + card->name = "Atos CardOS"; card->cla = 0x00; /* Set up algorithm info. */ @@ -187,9 +189,9 @@ _sc_card_add_rsa_alg(card, 1024, flags, 0); if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { - int r = cardos_have_2048bit_package(card); + r = cardos_have_2048bit_package(card); if (r < 0) - return r; + return SC_ERROR_INVALID_CARD; if (r == 1) rsa_2048 = 1; card->caps |= SC_CARD_CAP_APDU_EXT; @@ -207,14 +209,18 @@ apdu.le = sizeof rbuf; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, - sc_transmit_apdu(card, &apdu), - "APDU transmit failed"); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, - sc_check_sw(card, apdu.sw1, apdu.sw2), - "GET DATA command returned error"); + r = sc_transmit_apdu(card, &apdu); + if (r < 0) + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, + SC_ERROR_INVALID_CARD, + "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r < 0) + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, + SC_ERROR_INVALID_CARD, + "GET DATA command returned error"); if (apdu.resplen != 2) - return SC_ERROR_WRONG_LENGTH; + return SC_ERROR_INVALID_CARD; data_field_length = ((rbuf[0] << 8) | rbuf[1]); /* strip the length of possible Lc and Le bytes */ @@ -298,7 +304,7 @@ /* no error, maybe a note */ { 0x9000, SC_SUCCESS, NULL}, { 0x9001, SC_SUCCESS, "success, but eeprom weakness detected"}, -{ 0x9850, SC_SUCCESS, "over/underflow useing in/decrease"} +{ 0x9850, SC_SUCCESS, "over/underflow using in/decrease"} }; static int cardos_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) @@ -351,7 +357,7 @@ len = apdu.resplen; while (len != 0) { size_t tlen = 0, ilen = 0; - /* is there a file informatin block (0x6f) ? */ + /* is there a file information block (0x6f) ? */ p = sc_asn1_find_tag(card->ctx, p, len, 0x6f, &tlen); if (p == NULL) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "directory tag missing"); @@ -371,7 +377,7 @@ buf[fids++] = q[1]; buflen -= 2; } else - /* not enought space left in buffer => break */ + /* not enough space left in buffer => break */ break; /* extract next offset */ q = sc_asn1_find_tag(card->ctx, p, tlen, 0x8a, &ilen); @@ -558,8 +564,8 @@ status[0] = 0x01; if (file->type == SC_FILE_TYPE_DF) { - status[1] = file->size >> 8; - status[2] = file->size; + status[1] = (file->size >> 8) & 0xFF; + status[2] = file->size & 0xFF; } else { status[1] = status[2] = 0x00; /* not used */ } @@ -598,6 +604,8 @@ /* we will add the length later */ p++; + memset(buf, 0, sizeof(buf)); + /* set the length */ buf[0] = (file->size >> 8) & 0xff; buf[1] = file->size & 0xff; @@ -890,7 +898,7 @@ /* There are two ways to create a signature, depending on the way, * the key was created: RSA_SIG and RSA_PURE_SIG. * We can use the following reasoning, to determine the correct operation: - * 1. We check for several caps flags (as set in card->caps), to pervent generating + * 1. We check for several caps flags (as set in card->caps), to prevent generating * invalid signatures with duplicated hash prefixes with some cards * 2. Use the information from AlgorithmInfo of the TokenInfo file. * This information is parsed in set_security_env and stored in a static variable. @@ -975,6 +983,32 @@ } static int +cardos_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) +{ + int r; + size_t card_max_send_size = card->max_send_size; + size_t reader_max_send_size = card->reader->max_send_size; + + if (sc_get_max_send_size(card) < crgram_len + 1) { + /* CardOS doesn't support chaining for PSO:DEC, so we just _hope_ + * that both, the reader and the card are able to send enough data. + * (data is prefixed with 1 byte padding content indicator) */ + card->max_send_size = crgram_len + 1; + card->reader->max_send_size = crgram_len + 1; + } + + r = iso_ops->decipher(card, crgram, crgram_len, out, outlen); + + /* reset whatever we've modified above */ + card->max_send_size = card_max_send_size; + card->reader->max_send_size = reader_max_send_size; + + return r; +} + +static int cardos_lifecycle_get(sc_card_t *card, int *mode) { sc_apdu_t apdu; @@ -1277,6 +1311,7 @@ cardos_ops.set_security_env = cardos_set_security_env; cardos_ops.restore_security_env = cardos_restore_security_env; cardos_ops.compute_signature = cardos_compute_signature; + cardos_ops.decipher = cardos_decipher; cardos_ops.list_files = cardos_list_files; cardos_ops.check_sw = cardos_check_sw; diff -Nru opensc-0.17.0/src/libopensc/card-coolkey.c opensc-0.19.0/src/libopensc/card-coolkey.c --- opensc-0.17.0/src/libopensc/card-coolkey.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-coolkey.c 2018-09-13 11:47:21.000000000 +0000 @@ -58,6 +58,7 @@ #include "compression.h" #endif #include "iso7816.h" +#include "gp.h" #include "../pkcs11/pkcs11.h" @@ -88,7 +89,7 @@ #define COOLKEY_INS_COMPUTE_CRYPT 0x36 #define COOLKEY_INS_COMPUTE_ECC_KEY_AGREEMENT 0x37 #define COOLKEY_INS_COMPUTE_ECC_SIGNATURE 0x38 -#define COOLKEY_INS_GET_RANDOM 0x73 +#define COOLKEY_INS_GET_RANDOM 0x72 #define COOLKEY_INS_READ_OBJECT 0x56 #define COOLKEY_INS_WRITE_OBJECT 0x54 #define COOLKEY_INS_LOGOUT 0x61 @@ -160,7 +161,7 @@ u8 ic_personalization_id[4]; } global_platform_cplc_data_t; -/* format of the coolkey_cuid, either contructed from cplc data or read from the combined object */ +/* format of the coolkey_cuid, either constructed from cplc data or read from the combined object */ typedef struct coolkey_cuid { u8 ic_fabricator[2]; u8 ic_type[2]; @@ -214,7 +215,7 @@ u8 object_offset[2]; u8 object_count[2]; u8 token_name_length; - u8 token_name[255]; /* arbitary size up to token_name_length */ + u8 token_name[255]; /* arbitrary size up to token_name_length */ } coolkey_decompressed_header_t; /* @@ -293,11 +294,11 @@ uint32_t cka_always_sensitive:1; uint32_t cka_extractable:1; uint32_t cka_never_extractable:1; - uint32_t reseved:8; + uint32_t reserved:8; }; * cka_class is used to determine which booleans are valid. Any attributes in the full attribute list - * takes precidence over the fixed attributes. That is if there is a CKA_ID in the full attribute list, + * takes precedence over the fixed attributes. That is if there is a CKA_ID in the full attribute list, * The cka_id in the fixed_attributes is ignored. When determining which boolean attribute is valid, the * cka_class in the fixed attributes are used, even if it is overridden by the full attribute list. * valid cka_class values and their corresponding valid bools are as follows: @@ -658,7 +659,7 @@ return 0; /* return no bits */ } /* This table lets us return a pointer to the CKA_ID value without allocating data or - * creating a changable static that could cause thread issues */ + * creating a changeable static that could cause thread issues */ static const u8 coolkey_static_cka_id[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; @@ -860,21 +861,21 @@ }; static const struct coolkey_error_codes_st coolkey_error_codes[]= { - {SC_ERROR_UNKNOWN, "Reservered 0x9c00" }, + {SC_ERROR_UNKNOWN, "Reserved 0x9c00" }, {SC_ERROR_NOT_ENOUGH_MEMORY, "No memory left on card" }, {SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed" }, {SC_ERROR_NOT_ALLOWED, "Operation not allowed" }, - {SC_ERROR_UNKNOWN, "Reservered 0x9c04" }, + {SC_ERROR_UNKNOWN, "Reserved 0x9c04" }, {SC_ERROR_NO_CARD_SUPPORT, "Unsupported feature" }, {SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Not authorized" }, {SC_ERROR_DATA_OBJECT_NOT_FOUND, "Object not found" }, {SC_ERROR_FILE_ALREADY_EXISTS, "Object exists" }, {SC_ERROR_NO_CARD_SUPPORT, "Incorrect Algorithm" }, - {SC_ERROR_UNKNOWN, "Reservered 0x9c0a" }, + {SC_ERROR_UNKNOWN, "Reserved 0x9c0a" }, {SC_ERROR_SM_INVALID_CHECKSUM, "Signature invalid" }, {SC_ERROR_AUTH_METHOD_BLOCKED, "Identity blocked" }, - {SC_ERROR_UNKNOWN, "Reservered 0x9c0d" }, - {SC_ERROR_UNKNOWN, "Reservered 0x9c0e" }, + {SC_ERROR_UNKNOWN, "Reserved 0x9c0d" }, + {SC_ERROR_UNKNOWN, "Reserved 0x9c0e" }, {SC_ERROR_INCORRECT_PARAMETERS, "Invalid parameter" }, {SC_ERROR_INCORRECT_PARAMETERS, "Incorrect P1" }, {SC_ERROR_INCORRECT_PARAMETERS, "Incorrect P2" }, @@ -914,7 +915,7 @@ * an internal 4096 byte buffer is used, and a copy is returned to the * caller. that need to be freed by the caller. * - * modelled after a similiar function in card-piv.c. The coolkey version + * modelled after a similar function in card-piv.c. The coolkey version * adds the coolkey nonce to user authenticated operations. */ @@ -1128,13 +1129,13 @@ do { ulong2bebytes(¶ms.offset[0], offset); params.length = MIN(left, COOLKEY_MAX_CHUNK_SIZE); - len = left+2; + len = left; r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_READ_OBJECT, 0, 0, (u8 *)¶ms, sizeof(params), &out_ptr, &len, nonce, nonce_size); if (r < 0) { goto fail; } - /* santity check to make sure we don't overflow left */ + /* sanity check to make sure we don't overflow left */ if ((left < len) || (len == 0)) { r = SC_ERROR_INTERNAL; goto fail; @@ -1195,7 +1196,7 @@ { coolkey_private_data_t * priv = COOLKEY_DATA(card); int r = 0, len; - u8 *data = NULL;; + u8 *data = NULL; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (idx > priv->obj->length) { @@ -1466,7 +1467,7 @@ for (i=0; i < attribute_count; i++) { size_t record_len = coolkey_get_attribute_record_len(attr, object_record_type, buf_len); /* make sure we have the complete record */ - if (buf_len < record_len) { + if (buf_len < record_len || record_len < 4) { return SC_ERROR_CORRUPTED_DATA; } /* does the attribute match the one we are looking for */ @@ -1609,40 +1610,17 @@ static int coolkey_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { - size_t rbuflen = 0; - int r; - - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len); - - r = sc_lock(card); - if (r != SC_SUCCESS) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); - - for(; len >= COOLKEY_MAX_CHUNK_SIZE; len -= COOLKEY_MAX_CHUNK_SIZE, - rnd += COOLKEY_MAX_CHUNK_SIZE) { - rbuflen = COOLKEY_MAX_CHUNK_SIZE; - r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM, - 0, 0, NULL, 0, &rnd, &rbuflen, NULL, 0); - if (r != COOLKEY_MAX_CHUNK_SIZE) { - len = 0; - break; - } - } - if (len) { - r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM, - 0, 0, NULL, 0, &rnd, &len, NULL, 0); - } - sc_unlock(card); + LOG_FUNC_CALLED(card->ctx); - if (r > 0) { - r= SC_SUCCESS; - } + if (len > COOLKEY_MAX_CHUNK_SIZE) + len = COOLKEY_MAX_CHUNK_SIZE; - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + LOG_TEST_RET(card->ctx, + coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM, 0, 0, + NULL, 0, &rnd, &len, NULL, 0), + "Could not get challenge"); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, (int) len); } static int coolkey_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) @@ -1903,7 +1881,7 @@ } /* - * COOLKEY cards don't select objects in the applet, objects are selected by a paramter + * COOLKEY cards don't select objects in the applet, objects are selected by a parameter * to the APDU. We create paths for the object in which the path value is the object_id * and the path type is SC_PATH_SELECT_FILE_ID (so we could cache at the PKCS #15 level if * we wanted to. @@ -1951,7 +1929,7 @@ *file_out = file; } - return SC_SUCCESS; + return SC_SUCCESS; } static int coolkey_finish(sc_card_t *card) @@ -2144,12 +2122,6 @@ if (card->drv_data) { return SC_SUCCESS; } - - /* Select a coolkey read the coolkey objects out */ - r = coolkey_select_applet(card); - if (r < 0) { - return r; - } sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"Coolkey Applet found"); priv = coolkey_new_private_data(); @@ -2161,6 +2133,13 @@ if (r < 0) { goto cleanup; } + + /* Select a coolkey read the coolkey objects out */ + r = coolkey_select_applet(card); + if (r < 0) { + goto cleanup; + } + priv->protocol_version_major = life_cycle.protocol_version_major; priv->protocol_version_minor = life_cycle.protocol_version_minor; priv->pin_count = life_cycle.pin_count; @@ -2211,6 +2190,14 @@ /* if we didn't pull the cuid from the combined object, then grab it now */ if (!combined_processed) { global_platform_cplc_data_t cplc_data; + /* select the card manager, because a card with applet only will have + already selected the coolkey applet */ + + r = gp_select_card_manager(card); + if (r < 0) { + goto cleanup; + } + r = coolkey_get_cplc_data(card, &cplc_data); if (r < 0) { goto cleanup; @@ -2259,7 +2246,7 @@ r = coolkey_initialize(card); if (r < 0) { - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_CARD); } card->type = SC_CARD_TYPE_COOLKEY_GENERIC; @@ -2267,7 +2254,7 @@ /* set Token Major/minor version */ flags = SC_ALGORITHM_RSA_RAW; - _sc_card_add_rsa_alg(card, 1024, flags, 0); /* manditory */ + _sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */ _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ @@ -2287,6 +2274,7 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); } + static int coolkey_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) { @@ -2342,6 +2330,7 @@ return r; } + static int coolkey_logout(sc_card_t *card) { @@ -2358,6 +2347,20 @@ return SC_SUCCESS; } + +static int coolkey_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0) { + r = coolkey_select_applet(card); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + static struct sc_card_operations coolkey_ops; static struct sc_card_driver coolkey_drv = { @@ -2388,6 +2391,7 @@ coolkey_ops.check_sw = coolkey_check_sw; coolkey_ops.pin_cmd = coolkey_pin_cmd; coolkey_ops.logout = coolkey_logout; + coolkey_ops.card_reader_lock_obtained = coolkey_card_reader_lock_obtained; return &coolkey_drv; } diff -Nru opensc-0.17.0/src/libopensc/cardctl.h opensc-0.19.0/src/libopensc/cardctl.h --- opensc-0.17.0/src/libopensc/cardctl.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/cardctl.h 2018-09-13 11:47:21.000000000 +0000 @@ -155,7 +155,7 @@ SC_CARDCTL_RUTOKEN_GENERATE_KEY_DO, SC_CARDCTL_RUTOKEN_DELETE_DO, SC_CARDCTL_RUTOKEN_GET_INFO, - /* NON STANDART */ + /* NON STANDARD */ SC_CARDCTL_RUTOKEN_GET_DO_INFO, SC_CARDCTL_RUTOKEN_GOST_ENCIPHER, SC_CARDCTL_RUTOKEN_GOST_DECIPHER, @@ -220,6 +220,7 @@ SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, SC_CARDCTL_CAC_GET_NEXT_CERT_OBJECT, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, + SC_CARDCTL_CAC_GET_ACA_PATH, /* * AuthentIC v3 @@ -490,7 +491,9 @@ SC_CARDCTL_OBERTHUR_KEY_RSA_SFM, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, SC_CARDCTL_OBERTHUR_KEY_DSA_PUBLIC, - SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE + SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE, + SC_CARDCTL_OBERTHUR_KEY_EC_CRT, + SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC }; struct sc_cardctl_oberthur_genkey_info { @@ -1020,7 +1023,7 @@ typedef struct sc_cardctl_isoApplet_genkey { u8 algorithm_ref; /* Algorithm reference sent to card */ - unsigned int priv_key_ref; /* Private key refernce sent to card */ + unsigned int priv_key_ref; /* Private key reference sent to card */ union { struct { @@ -1037,7 +1040,7 @@ typedef struct sc_cardctl_isoApplet_import_key { u8 algorithm_ref; /* Algorithm reference sent to card */ - unsigned int priv_key_ref; /* Private key refernce sent to card */ + unsigned int priv_key_ref; /* Private key reference sent to card */ union { struct { @@ -1081,7 +1084,7 @@ typedef struct sc_cardctl_coolkey_find_object { int type; /* in parameter */ unsigned long find_id; /* in parameter */ - sc_cardctl_coolkey_attribute_t *coolkey_template; /* in paramter */ + sc_cardctl_coolkey_attribute_t *coolkey_template; /* in parameter */ int template_count; /* in parameter */ sc_cardctl_coolkey_object_t *obj; /* out parameter */ } sc_cardctl_coolkey_find_object_t; diff -Nru opensc-0.17.0/src/libopensc/card-dnie.c opensc-0.19.0/src/libopensc/card-dnie.c --- opensc-0.17.0/src/libopensc/card-dnie.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-dnie.c 2018-09-13 11:47:21.000000000 +0000 @@ -78,7 +78,7 @@ * Override APDU response error codes from iso7816.c to allow * handling of SM specific error */ -static struct sc_card_error dnie_errors[] = { +static const struct sc_card_error dnie_errors[] = { {0x6688, SC_ERROR_SM, "Cryptographic checksum invalid"}, {0x6987, SC_ERROR_SM, "Expected SM Data Object missing"}, {0x6988, SC_ERROR_SM, "SM Data Object incorrect"}, @@ -128,7 +128,7 @@ * OpenDNIe defines two ATR's for user and finalized card state */ static struct sc_atr_table dnie_atrs[] = { - /* TODO: get ATR for uninitalized DNIe */ + /* TODO: get ATR for uninitialized DNIe */ { /** card activated; normal operation state */ "3B:7F:00:00:00:00:6A:44:4E:49:65:00:00:00:00:00:00:03:90:00", "FF:FF:00:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:FF:FF:FF", @@ -163,6 +163,7 @@ */ char *user_consent_msgs[] = { "SETTITLE", "SETDESC", "CONFIRM", "BYE" }; +#if !defined(__APPLE__) && !defined(_WIN32) /** * Do fgets() without interruptions. * @@ -181,6 +182,7 @@ } return s; } +#endif /** * Ask for user consent. @@ -201,7 +203,7 @@ CFStringRef header_ref; /* to store title */ CFStringRef message_ref; /* to store message */ #endif -#ifdef linux +#if !defined(__APPLE__) && !defined(_WIN32) pid_t pid; FILE *fin=NULL; FILE *fout=NULL; /* to handle pipes as streams */ @@ -213,7 +215,7 @@ int n = 0; /* to iterate on to-be-sent messages */ #endif int res = SC_ERROR_INTERNAL; /* by default error :-( */ - char *msg = NULL; /* to makr errors */ + char *msg = NULL; /* to mark errors */ if ((card == NULL) || (card->ctx == NULL)) return SC_ERROR_INVALID_ARGUMENTS; @@ -246,7 +248,7 @@ header_ref = CFStringCreateWithCString( NULL, title, strlen(title) ); message_ref = CFStringCreateWithCString( NULL,message, strlen(message) ); - /* Displlay user notification alert */ + /* Display user notification alert */ CFUserNotificationDisplayAlert( 0, /* no timeout */ kCFUserNotificationNoteAlertLevel, /* Alert level */ @@ -269,7 +271,7 @@ if( result == kCFUserNotificationAlternateResponse ) LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED); -#elif linux +#else /* check that user_consent_app exists. TODO: check if executable */ res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file); if (res != 0) { @@ -359,8 +361,6 @@ /* close out channel to force client receive EOF and also die */ if (fout != NULL) fclose(fout); if (fin != NULL) fclose(fin); -#else -#error "Don't know how to handle user consent in this (rare) Operating System" #endif if (msg != NULL) sc_log(card->ctx, "%s", msg); @@ -396,8 +396,8 @@ /** * Parse configuration file for dnie parameters. * - * DNIe card driver has two main paramaters: - * - The name of the user consent Application to be used in Linux. This application shoud be any of pinentry-xxx family + * DNIe card driver has two main parameters: + * - The name of the user consent Application to be used in Linux. This application should be any of pinentry-xxx family * - A flag to indicate if user consent is to be used in this driver. If false, the user won't be prompted for confirmation on signature operations * * @See ../../etc/opensc.conf for details @@ -469,7 +469,7 @@ /** * Analyze a buffer looking for provided data pattern. * - * Comodity function for dnie_get_info() that searches a byte array + * Commodity function for dnie_get_info() that searches a byte array * in provided buffer * * @param card pointer to card info data @@ -645,15 +645,14 @@ /* if serial number is cached, use it */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); - sc_log(card->ctx, "Serial Number (cached): '%s'", - sc_dump_hex(serial->value, serial->len)); + sc_log_hex(card->ctx, "Serial Number (cached)", serial->value, serial->len); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } /* not cached, retrieve it by mean of an APDU */ /* official driver read 0x11 bytes, but only uses 7. Manual says just 7 (for le) */ dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xb8, 0x00, 0x00, 0x07, 0, rbuf, sizeof(rbuf), NULL, 0); - apdu.cla = 0x90; /* propietary cmd */ + apdu.cla = 0x90; /* proprietary cmd */ /* send apdu */ result = sc_transmit_apdu(card, &apdu); if (result != SC_SUCCESS) { @@ -672,8 +671,7 @@ */ /* copy and return serial number */ memcpy(serial, &card->serialnr, sizeof(*serial)); - sc_log(card->ctx, "Serial Number (apdu): '%s'", - sc_dump_hex(serial->value, serial->len)); + sc_log_hex(card->ctx, "Serial Number (apdu)", serial->value, serial->len); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -714,6 +712,7 @@ /* RSA Support with PKCS1.5 padding */ algoflags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; _sc_card_add_rsa_alg(card, 1024, algoflags, 0); + _sc_card_add_rsa_alg(card, 1920, algoflags, 0); _sc_card_add_rsa_alg(card, 2048, algoflags, 0); } @@ -759,15 +758,25 @@ if ((*sm_apdu) != plain) { rv = cwa_decode_response(card, provider, *sm_apdu); - if (plain) { - plain->resplen = (*sm_apdu)->resplen; + if (plain && rv == SC_SUCCESS) { + if (plain->resp) { + /* copy the response into the original resp buffer */ + if ((*sm_apdu)->resplen <= plain->resplen) { + memcpy(plain->resp, (*sm_apdu)->resp, (*sm_apdu)->resplen); + plain->resplen = (*sm_apdu)->resplen; + } else { + sc_log(card->ctx, "Invalid initial length," + " needed %"SC_FORMAT_LEN_SIZE_T"u bytes" + " but has %"SC_FORMAT_LEN_SIZE_T"u", + (*sm_apdu)->resplen, plain->resplen); + rv = SC_ERROR_BUFFER_TOO_SMALL; + } + } plain->sw1 = (*sm_apdu)->sw1; plain->sw2 = (*sm_apdu)->sw2; - if (((*sm_apdu)->data) != plain->data) - free((unsigned char *) (*sm_apdu)->data); - if ((*sm_apdu)->resp != plain->resp) - free((*sm_apdu)->resp); } + free((unsigned char *) (*sm_apdu)->data); + free((*sm_apdu)->resp); free(*sm_apdu); } *sm_apdu = NULL; @@ -914,10 +923,10 @@ /** * Uncompress data if in compressed format. * - * @param card poiner to sc_card_t structure + * @param card pointer to sc_card_t structure * @param from buffer to get data from * @param len pointer to buffer length - * @return uncompresed or original buffer; len points to new buffer length + * @return uncompressed or original buffer; len points to new buffer length * on error return null */ static u8 *dnie_uncompress(sc_card_t * card, u8 * from, size_t *len) @@ -932,7 +941,7 @@ return NULL; LOG_FUNC_CALLED(card->ctx); - /* if data size not enought for compression header assume uncompressed */ + /* if data size not enough for compression header assume uncompressed */ if (*len < 8) goto compress_exit; /* evaluate compressed an uncompressed sizes (little endian format) */ @@ -962,13 +971,8 @@ } /* Done; update buffer len and return pt to uncompressed data */ *len = uncompressed; - sc_log(card->ctx, "Compressed data:\n%s\n", - sc_dump_hex(from + 8, compressed)); - sc_log(card->ctx, - "Uncompress() done. Before:'%"SC_FORMAT_LEN_SIZE_T"u' After: '%"SC_FORMAT_LEN_SIZE_T"u'", - compressed, uncompressed); - sc_log(card->ctx, "Uncompressed data:\n%s\n", - sc_dump_hex(upt, uncompressed)); + sc_log_hex(card->ctx, "Compressed data", from + 8, compressed); + sc_log_hex(card->ctx, "Uncompressed data", upt, uncompressed); compress_exit: #endif @@ -1056,7 +1060,7 @@ free(apdu.resp); LOG_FUNC_RETURN(ctx, r); /* arriving here means response error */ } - /* copy received data into buffer. realloc() if not enought space */ + /* copy received data into buffer. realloc() if not enough space */ count = apdu.resplen; buffer = realloc(buffer, len + count); if (!buffer) { @@ -1082,7 +1086,7 @@ if (apdu.resp != tmp) free(apdu.resp); if (pt == NULL) { - sc_log(ctx, "Uncompress proccess failed"); + sc_log(ctx, "Uncompress process failed"); free(buffer); LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); } @@ -1106,10 +1110,10 @@ * * @param card pointer to sc_card_t structure * @param idx offset from card file to ask data for - * @param buf where to store readed data. must be non null + * @param buf where to store read data. must be non null * @param count number of bytes to read * @param flags. not used - * @return number of bytes readed, 0 on EOF, error code on error + * @return number of bytes read, 0 on EOF, error code on error */ static int dnie_read_binary(struct sc_card *card, unsigned int idx, @@ -1215,8 +1219,8 @@ * - only handles some types: * -- SC_PATH_TYPE_FILE_ID 2-byte long file ID * -- SC_PATH_TYPE_DF_NAME named DF's - * -- SC_PATH_TYPE_PARENT jump to parent DF of current EF/DF - undocummented in DNIe manual - * -- other file types are marked as unssupported + * -- SC_PATH_TYPE_PARENT jump to parent DF of current EF/DF - undocumented in DNIe manual + * -- other file types are marked as unsupported * * - Also MF must be addressed by their Name, not their ID * So some magic is needed: @@ -1259,18 +1263,18 @@ */ if (in_path->len != 2) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - sc_log(ctx, "select_file(ID): %s", sc_dump_hex(in_path->value, in_path->len)); + sc_log_hex(ctx, "select_file(ID)", in_path->value, in_path->len); res = dnie_compose_and_send_apdu(card, in_path->value, in_path->len, 0, file_out); break; case SC_PATH_TYPE_DF_NAME: - sc_log(ctx, "select_file(NAME): %s", sc_dump_hex(in_path->value, in_path->len)); + sc_log_hex(ctx, "select_file(NAME)", in_path->value, in_path->len); res = dnie_compose_and_send_apdu(card, in_path->value, in_path->len, 4, file_out); break; case SC_PATH_TYPE_PATH: if ((in_path->len == 0) || ((in_path->len & 1) != 0)) /* not divisible by 2 */ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - sc_log(ctx, "select_file(PATH): requested:%s ", sc_dump_hex(in_path->value, in_path->len)); + sc_log_hex(ctx, "select_file(PATH): requested", in_path->value, in_path->len); /* convert to SC_PATH_TYPE_FILE_ID */ res = sc_lock(card); /* lock to ensure path traversal */ @@ -1278,7 +1282,7 @@ if (memcmp(in_path->value, "\x3F\x00", 2) == 0) { /* if MF, use the name as path */ strcpy((char *)tmp_path, DNIE_MF_NAME); - sc_log(ctx, "select_file(NAME): requested:%s ", sc_dump_hex(tmp_path, sizeof(DNIE_MF_NAME) - 1)); + sc_log_hex(ctx, "select_file(NAME): requested", tmp_path, sizeof(DNIE_MF_NAME) - 1); res = dnie_compose_and_send_apdu(card, tmp_path, sizeof(DNIE_MF_NAME) - 1, 4, file_out); if (res != SC_SUCCESS) { sc_unlock(card); @@ -1337,58 +1341,34 @@ * No reason to do it, as is needed to do SM handshake... * Also: official driver reads in blocks of 20 bytes. * Why? Manual and iso-7816-4 states that only 8 bytes - * are required... so we will obbey Manual + * are required... so we will obey Manual * * @param card Pointer to card Structure * @param rnd Where to store challenge * @param len requested challenge length * @return SC_SUCCESS if OK; else error code */ -#define BUFFER_SIZE 8 static int dnie_get_challenge(struct sc_card *card, u8 * rnd, size_t len) { - sc_apdu_t apdu; - u8 buf[MAX_RESP_BUFFER_SIZE]; - int result = SC_SUCCESS; - if ((card == NULL) || (card->ctx == NULL)) - return SC_ERROR_INVALID_ARGUMENTS; + /* As DNIe cannot handle other data length than 0x08 and 0x14 */ + u8 rbuf[8]; + size_t out_len; + int r; + LOG_FUNC_CALLED(card->ctx); - /* just a copy of iso7816::get_challenge() but call dnie_check_sw to - * look for extra error codes */ - if ( (rnd==NULL) || (len==0) ) { - /* no valid buffer provided */ - result = SC_ERROR_INVALID_ARGUMENTS; - goto dnie_get_challenge_error; - } - dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00, BUFFER_SIZE, 0, - buf, MAX_RESP_BUFFER_SIZE, NULL, 0); - /* - * As DNIe cannot handle other data length than 0x08 and 0x14, - * perform consecutive reads of 8 bytes until retrieve requested length - */ - while (len > 0) { - size_t n = len > BUFFER_SIZE ? BUFFER_SIZE : len; - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); - apdu.le = BUFFER_SIZE; - apdu.resp = buf; - apdu.resplen = MAX_RESP_BUFFER_SIZE; /* include SW's */ - result = sc_transmit_apdu(card, &apdu); - if (result != SC_SUCCESS) { - LOG_TEST_RET(card->ctx, result, "APDU transmit failed"); - } - if (apdu.resplen != BUFFER_SIZE) { - result = sc_check_sw(card, apdu.sw1, apdu.sw2); - goto dnie_get_challenge_error; - } - memcpy(rnd, apdu.resp, n); - len -= n; - rnd += n; + r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); + + if (len < (size_t) r) { + out_len = len; + } else { + out_len = (size_t) r; } - result = SC_SUCCESS; - dnie_get_challenge_error: - LOG_FUNC_RETURN(card->ctx, result); + memcpy(rnd, rbuf, out_len); + + LOG_FUNC_RETURN(card->ctx, (int) out_len); } /* @@ -1644,7 +1624,7 @@ * and applies * * @param card pointer to sc_card_t structure - * @param data data to be hased/signed + * @param data data to be hashed/signed * @param datalen length of provided data * @param out buffer to store results into * @param outlen available space in result buffer @@ -1661,7 +1641,7 @@ struct sc_apdu apdu; u8 rbuf[MAX_RESP_BUFFER_SIZE]; /* to receive sign response */ - /* some preliminar checks */ + /* some preliminary checks */ if ((card == NULL) || (card->ctx == NULL)) return SC_ERROR_INVALID_ARGUMENTS; /* OK: start working */ @@ -1671,8 +1651,6 @@ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); if (datalen > SC_MAX_APDU_BUFFER_SIZE) /* should be 256 */ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - if (outlen<256) /* enought space to store 2048 bit response */ - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); #ifdef ENABLE_DNIE_UI /* (Requested by DGP): on signature operation, ask user consent */ @@ -1689,9 +1667,9 @@ So just extract 15+20 DigestInfo+Hash info from ASN.1 provided data and feed them into sign() command */ - sc_log(card->ctx, - "Compute signature len: '%"SC_FORMAT_LEN_SIZE_T"u' bytes:\n%s\n============================================================", - datalen, sc_dump_hex(data, datalen)); + sc_log_hex(card->ctx, + "Compute signature\n============================================================", + data, datalen); /*INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x9E Resp: Digital Signature @@ -1711,6 +1689,8 @@ /* ok: copy result from buffer */ result_resplen = apdu.resplen; + if ((int)outlenctx, SC_ERROR_INVALID_ARGUMENTS); memcpy(out, apdu.resp, result_resplen); /* and return response length */ LOG_FUNC_RETURN(card->ctx, result_resplen); @@ -1896,7 +1876,7 @@ * the read_binary() file cache work * * Extract real file length from compressed file is done by mean of - * reading 8 first bytes for uncompressed/compressed lenght. + * reading 8 first bytes for uncompressed/compressed length. * Lengths are provided as two 4-byte little endian numbers * * Implemented just like a direct read binary apdu bypassing dnie file cache @@ -1946,7 +1926,7 @@ } /** - * Access control list bytes for propietary DNIe FCI response for DF's. + * Access control list bytes for proprietary DNIe FCI response for DF's. * based in information from official DNIe Driver * Parsing code based on itacns card driver */ @@ -1957,7 +1937,7 @@ }; /** - * Access control list bytes for propietary DNIe FCI response for EF's. + * Access control list bytes for proprietary DNIe FCI response for EF's. * based in information from official DNIe Driver * Parsing code based on itacns card driver */ @@ -1972,7 +1952,7 @@ * * Parse SelectFile's File Control information. * - First, std iso_parse_fci is called to parse std fci tags - * - Then analyze propietary tag according DNIe Manual + * - Then analyze proprietary tag according DNIe Manual * * @param card OpenSC card structure pointer * @param file currently selected EF or DF @@ -2137,7 +2117,7 @@ * Not implemented yet, as current availability for DNIe user driver * is unknown * - * @param card Pointer to Card Driver data structrure + * @param card Pointer to Card Driver data structure * @param data Pointer to Pin data structure * @return SC_SUCCESS if ok; else error code */ @@ -2195,7 +2175,7 @@ dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, 0x00, 0, pinlen, NULL, 0, pinbuffer, pinlen); - /* and send to card throught virtual channel */ + /* and send to card through virtual channel */ res = sc_transmit_apdu(card, &apdu); if (res != SC_SUCCESS) { LOG_TEST_RET(card->ctx, res, "VERIFY APDU Transmit fail"); @@ -2244,7 +2224,7 @@ /* * some flags and settings from documentation - * No (easy) way to handle pinpad throught SM, so disable it + * No (easy) way to handle pinpad through SM, so disable it */ data->flags &= ~SC_PIN_CMD_NEED_PADDING; /* no pin padding */ data->flags &= ~SC_PIN_CMD_USE_PINPAD; /* cannot handle pinpad */ diff -Nru opensc-0.17.0/src/libopensc/card-entersafe.c opensc-0.19.0/src/libopensc/card-entersafe.c --- opensc-0.17.0/src/libopensc/card-entersafe.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-entersafe.c 2018-09-13 11:47:21.000000000 +0000 @@ -30,7 +30,7 @@ #include "asn1.h" #include "cardctl.h" -static struct sc_atr_table entersafe_atrs[] = { +static const struct sc_atr_table entersafe_atrs[] = { { "3b:0f:00:65:46:53:05:19:05:71:df:00:00:00:00:00:00", "ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff:00:00:00:00:00:00", @@ -619,7 +619,7 @@ { if ( pathlen - bMatch == 2 ) { - /* we are in the rigth directory */ + /* we are in the right directory */ return entersafe_select_fid(card, path[bMatch], path[bMatch+1], file_out); } else if ( pathlen - bMatch > 2 ) @@ -894,9 +894,9 @@ } /** - * We don't really set the security envirment,but cache it.It will be set when + * We don't really set the security environment,but cache it.It will be set when * security operation is performed later.Because we may transport partial of - * the sign/decipher data within the security envirment apdu. + * the sign/decipher data within the security environment apdu. */ static int entersafe_set_security_env(sc_card_t *card, const sc_security_env_t *env, @@ -1061,8 +1061,7 @@ r = entersafe_transmit_apdu(card, &apdu,0,0,0,0); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - /* invalidate cache */ - card->cache.valid = 0; + sc_invalidate_cache(card); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xEE, 0x00, 0x00); apdu.cla=0x84; @@ -1409,13 +1408,15 @@ data->modulus = malloc(len); if (!data->modulus) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_OUT_OF_MEMORY); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OUT_OF_MEMORY); p=rbuf; - assert(*p=='E'); + if (*p!='E') + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); p+=2+p[1]; /* N */ - assert(*p=='N'); + if (*p!='N') + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); ++p; if(*p++>0x80) { diff -Nru opensc-0.17.0/src/libopensc/card-epass2003.c opensc-0.19.0/src/libopensc/card-epass2003.c --- opensc-0.17.0/src/libopensc/card-epass2003.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-epass2003.c 2018-09-13 11:47:21.000000000 +0000 @@ -46,7 +46,7 @@ #include "asn1.h" #include "cardctl.h" -static struct sc_atr_table epass2003_atrs[] = { +static const struct sc_atr_table epass2003_atrs[] = { /* This is a FIPS certified card using SCP01 security messaging. */ {"3B:9F:95:81:31:FE:9F:00:66:46:53:05:10:00:11:71:df:00:00:00:6a:82:5e", "FF:FF:FF:FF:FF:00:FF:FF:FF:FF:FF:FF:00:00:00:ff:00:ff:ff:00:00:00:00", @@ -98,6 +98,8 @@ unsigned char sk_enc[16]; /* encrypt session key */ unsigned char sk_mac[16]; /* mac session key */ unsigned char icv_mac[16]; /* instruction counter vector(for sm) */ + unsigned char currAlg; /* current Alg */ + unsigned int ecAlgFlags; /* Ec Alg mechanism type*/ } epass2003_exdata; #define REVERSE_ORDER4(x) ( \ @@ -170,6 +172,7 @@ static int epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu); static int epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out); int epass2003_refresh(struct sc_card *card); +static int hash_data(const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType); static int epass2003_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2) @@ -403,6 +406,12 @@ return openssl_dig(EVP_sha1(), input, length, output); } +static int +sha256_digest(const unsigned char *input, size_t length, unsigned char *output) +{ + return openssl_dig(EVP_sha256(), input, length, output); +} + static int gen_init_key(struct sc_card *card, unsigned char *key_enc, unsigned char *key_mac, @@ -731,11 +740,11 @@ memcpy(mac_tlv + 2, &mac[mac_len - 16], 8); } else { - unsigned char iv[8] = { 0 }; + unsigned char iv[EVP_MAX_IV_LENGTH] = { 0 }; unsigned char tmp[8] = { 0 }; des_encrypt_cbc(exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac); des_decrypt_cbc(&exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp); - memset(iv, 0x00, 8); + memset(iv, 0x00, sizeof iv); des_encrypt_cbc(exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2); } @@ -894,9 +903,9 @@ * SW12(TLV)=0x99|0x02|SW1+SW2 * MAC(TLV)=0x8e|0x08|MAC */ static int -decrypt_response(struct sc_card *card, unsigned char *in, unsigned char *out, size_t * out_len) +decrypt_response(struct sc_card *card, unsigned char *in, size_t inlen, unsigned char *out, size_t * out_len) { - size_t in_len; + size_t cipher_len; size_t i; unsigned char iv[16] = { 0 }; unsigned char plaintext[4096] = { 0 }; @@ -913,37 +922,40 @@ /* parse cipher length */ if (0x01 == in[2] && 0x82 != in[1]) { - in_len = in[1]; + cipher_len = in[1]; i = 3; } else if (0x01 == in[3] && 0x81 == in[1]) { - in_len = in[2]; + cipher_len = in[2]; i = 4; } else if (0x01 == in[4] && 0x82 == in[1]) { - in_len = in[2] * 0x100; - in_len += in[3]; + cipher_len = in[2] * 0x100; + cipher_len += in[3]; i = 5; } else { return -1; } + if (cipher_len < 2 || i+cipher_len > inlen || cipher_len > sizeof plaintext) + return -1; + /* decrypt */ if (KEY_TYPE_AES == exdata->smtype) - aes128_decrypt_cbc(exdata->sk_enc, 16, iv, &in[i], in_len - 1, plaintext); + aes128_decrypt_cbc(exdata->sk_enc, 16, iv, &in[i], cipher_len - 1, plaintext); else - des3_decrypt_cbc(exdata->sk_enc, 16, iv, &in[i], in_len - 1, plaintext); + des3_decrypt_cbc(exdata->sk_enc, 16, iv, &in[i], cipher_len - 1, plaintext); /* unpadding */ - while (0x80 != plaintext[in_len - 2] && (in_len - 2 > 0)) - in_len--; + while (0x80 != plaintext[cipher_len - 2] && (cipher_len - 2 > 0)) + cipher_len--; - if (2 == in_len) + if (2 == cipher_len || *out_len < cipher_len - 2) return -1; - memcpy(out, plaintext, in_len - 2); - *out_len = in_len - 2; + memcpy(out, plaintext, cipher_len - 2); + *out_len = cipher_len - 2; return 0; } @@ -965,7 +977,8 @@ r = sc_check_sw(card, sm->sw1, sm->sw2); if (r == SC_SUCCESS) { if (exdata->sm) { - if (0 != decrypt_response(card, sm->resp, plain->resp, &len)) + len = plain->resplen; + if (0 != decrypt_response(card, sm->resp, sm->resplen, plain->resp, &len)) return SC_ERROR_CARD_CMD_FAILED; } else { @@ -1140,6 +1153,7 @@ epass2003_init(struct sc_card *card) { unsigned int flags; + unsigned int ext_flags; unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; size_t datalen = SC_MAX_APDU_BUFFER_SIZE; epass2003_exdata *exdata = NULL; @@ -1158,7 +1172,7 @@ /* decide FIPS/Non-FIPS mode */ if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) - return SC_ERROR_CARD_CMD_FAILED; + return SC_ERROR_INVALID_CARD; if (0x01 == data[2]) exdata->smtype = KEY_TYPE_AES; @@ -1192,6 +1206,11 @@ _sc_card_add_rsa_alg(card, 1024, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); + //set EC Alg Flags + flags = SC_ALGORITHM_ONBOARD_KEY_GEN|SC_ALGORITHM_ECDSA_HASH_SHA1|SC_ALGORITHM_ECDSA_HASH_SHA256|SC_ALGORITHM_ECDSA_HASH_NONE|SC_ALGORITHM_ECDSA_RAW; + ext_flags = 0; + _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); + card->caps = SC_CARD_CAP_RNG | SC_CARD_CAP_APDU_EXT; LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); @@ -1288,7 +1307,7 @@ } if (path[0] == 0x29) { /* TODO:0x29 accords with FID prefix in profile */ - /* Not allowed to select prvate key file, so fake fci. */ + /* Not allowed to select private key file, so fake fci. */ /* 62 16 82 02 11 00 83 02 29 00 85 02 08 00 86 08 FF 90 90 90 FF FF FF FF */ apdu.resplen = 0x18; memcpy(apdu.resp, @@ -1465,7 +1484,7 @@ if (card->cache.valid && bMatch > 2) { if (pathlen - bMatch == 2) { - /* we are in the rigth directory */ + /* we are in the right directory */ return epass2003_select_fid(card, path[bMatch], path[bMatch + 1], file_out); } else if (pathlen - bMatch > 2) { @@ -1561,19 +1580,15 @@ u8 *p; unsigned short fid = 0; int r, locked = 0; + epass2003_exdata *exdata = NULL; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); - switch (env->operation) { - case SC_SEC_OPERATION_DECIPHER: - apdu.p2 = 0xB8; - break; - case SC_SEC_OPERATION_SIGN: - apdu.p2 = 0xB8; - break; - default: + if (!card->drv_data) return SC_ERROR_INVALID_ARGUMENTS; - } + exdata = (epass2003_exdata *)card->drv_data; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); + p = sbuf; *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; @@ -1590,6 +1605,38 @@ apdu.lc = r; apdu.datalen = r; apdu.data = sbuf; + + if (env->algorithm == SC_ALGORITHM_EC) + { + apdu.p2 = 0xB6; + exdata->currAlg = SC_ALGORITHM_EC; + if(env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1) + { + sbuf[2] = 0x91; + exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA1; + } + else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256) + { + sbuf[2] = 0x92; + exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA256; + } + else + { + sc_log(card->ctx, "%0x Alg Not Support! ", env->algorithm_flags); + goto err; + } + } + else if(env->algorithm == SC_ALGORITHM_RSA) + { + exdata->currAlg = SC_ALGORITHM_RSA; + apdu.p2 = 0xB8; + sc_log(card->ctx, "setenv RSA Algorithm alg_flags = %0x\n",env->algorithm_flags); + } + else + { + sc_log(card->ctx, "%0x Alg Not Support! ", env->algorithm); + } + if (se_num > 0) { r = sc_lock(card); LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); @@ -1640,16 +1687,76 @@ struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; + epass2003_exdata *exdata = NULL; + + LOG_FUNC_CALLED(card->ctx); + + if (!card->drv_data) + return SC_ERROR_INVALID_ARGUMENTS; + + exdata = (epass2003_exdata *)card->drv_data; - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = 256; + if(exdata->currAlg == SC_ALGORITHM_EC) + { + if(exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA1) + { + r = hash_data(data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA1); + LOG_TEST_RET(card->ctx, r, "hash_data failed"); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); + apdu.data = sbuf; + apdu.lc = 0x14; + apdu.datalen = 0x14; + } + else if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA256) + { + r = hash_data(data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA256); + LOG_TEST_RET(card->ctx, r, "hash_data failed"); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); + apdu.data = sbuf; + apdu.lc = 0x20; + apdu.datalen = 0x20; + } + else + { + return SC_ERROR_NOT_SUPPORTED; + } + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 0; - memcpy(sbuf, data, datalen); - apdu.data = sbuf; - apdu.lc = datalen; - apdu.datalen = datalen; + r = sc_transmit_apdu_t(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { + size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; + memcpy(out, apdu.resp, len); + LOG_FUNC_RETURN(card->ctx, len); + } + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); + } + else if(exdata->currAlg == SC_ALGORITHM_RSA) + { + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 0; + + memcpy(sbuf, data, datalen); + apdu.data = sbuf; + apdu.lc = datalen; + apdu.datalen = datalen; + } + else + { + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 256; + + memcpy(sbuf, data, datalen); + apdu.data = sbuf; + apdu.lc = datalen; + apdu.datalen = datalen; + } r = sc_transmit_apdu_t(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); @@ -1776,12 +1883,10 @@ tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); if (tag != NULL && taglen > 0 && taglen <= 16) { - char tbuf[128]; memcpy(file->name, tag, taglen); file->namelen = taglen; - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, file->name, file->namelen, tbuf, sizeof(tbuf)); - sc_log(ctx, "File name: %s", tbuf); + sc_log_hex(ctx, "File name", file->name, file->namelen); if (!file->type) file->type = SC_FILE_TYPE_DF; } @@ -1862,11 +1967,13 @@ } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { - if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) { + if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { buf[0] = 0x11; buf[1] = 0x00; } - else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { + else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { buf[0] = 0x12; buf[1] = 0x00; } @@ -1903,7 +2010,9 @@ } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || - file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT|| + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { buf[0] = (file->size >> 8) & 0xFF; buf[1] = file->size & 0xFF; sc_asn1_put_tag(0x85, buf, 2, p, *outlen - (p - out), &p); @@ -1942,13 +2051,14 @@ ops[3] = SC_AC_OP_DELETE; } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { - if (file->ef_structure == - SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) { + if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { ops[1] = SC_AC_OP_UPDATE; ops[2] = SC_AC_OP_CRYPTO; ops[3] = SC_AC_OP_DELETE; } - else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { + else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { ops[0] = SC_AC_OP_READ; ops[1] = SC_AC_OP_UPDATE; ops[2] = SC_AC_OP_CRYPTO; @@ -1973,13 +2083,22 @@ buf[ii] = rv; } sc_asn1_put_tag(0x86, buf, sizeof(ops), p, *outlen - (p - out), &p); + if(file->size == 256) + { + out[4]= 0x13; + } } /* VT ??? */ - if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { + if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| + file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { unsigned char data[2] = {0x00, 0x66}; sc_asn1_put_tag(0x87, data, sizeof(data), p, *outlen - (p - out), &p); + if(file->size == 256) + { + out[4]= 0x14; + } } out[1] = p - out - 2; @@ -2129,19 +2248,36 @@ static int -hash_data(unsigned char *data, size_t datalen, unsigned char *hash) +hash_data(const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType) { - unsigned char data_hash[24] = { 0 }; - size_t len = 0; if ((NULL == data) || (NULL == hash)) return SC_ERROR_INVALID_ARGUMENTS; - sha1_digest(data, datalen, data_hash); + if(mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA1) + { + unsigned char data_hash[24] = { 0 }; + size_t len = 0; - len = REVERSE_ORDER4(datalen); - memcpy(&data_hash[20], &len, 4); - memcpy(hash, data_hash, 24); + sha1_digest(data, datalen, data_hash); + len = REVERSE_ORDER4(datalen); + memcpy(&data_hash[20], &len, 4); + memcpy(hash, data_hash, 24); + } + else if(mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA256) + { + unsigned char data_hash[36] = { 0 }; + size_t len = 0; + + sha256_digest(data, datalen, data_hash); + len = REVERSE_ORDER4(datalen); + memcpy(&data_hash[32], &len, 4); + memcpy(hash, data_hash, 36); + } + else + { + return SC_ERROR_NOT_SUPPORTED; + } return SC_SUCCESS; } @@ -2214,7 +2350,7 @@ int r; unsigned char hash[HASH_LEN] = { 0 }; - r = hash_data(pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash); + r = hash_data(pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); LOG_TEST_RET(card->ctx, r, "hash data failed"); r = install_secret_key(card, 0x04, pin->key_data.es_secret.kid, @@ -2265,7 +2401,14 @@ LOG_FUNC_CALLED(card->ctx); - sbuf[0] = 0x01; + if(len == 256) + { + sbuf[0] = 0x02; + } + else + { + sbuf[0] = 0x01; + } sbuf[1] = (u8) ((len >> 8) & 0xff); sbuf[2] = (u8) (len & 0xff); sbuf[3] = (u8) ((data->prkey_id >> 8) & 0xFF); @@ -2285,6 +2428,10 @@ /* read public key */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xb4, 0x02, 0x00); + if(len == 256) + { + apdu.p1 = 0x00; + } apdu.cla = 0x80; apdu.lc = apdu.datalen = 2; apdu.data = &sbuf[5]; @@ -2316,7 +2463,7 @@ int r; LOG_FUNC_CALLED(card->ctx); - card->cache.valid = 0; + sc_invalidate_cache(card); r = sc_delete_file(card, sc_get_mf_path()); LOG_TEST_RET(card->ctx, r, "delete MF failed"); @@ -2349,6 +2496,7 @@ { LOG_FUNC_CALLED(card->ctx); + sc_log(card->ctx, "cmd is %0lx", cmd); switch (cmd) { case SC_CARDCTL_ENTERSAFE_WRITE_KEY: return epass2003_write_key(card, (sc_epass2003_wkey_data *) ptr); @@ -2429,34 +2577,26 @@ return r; } - static int -epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t count) +static int +epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { - sc_apdu_t apdu; u8 rbuf[16]; - size_t n; - int ret = SC_SUCCESS; /* if count == 0 */ + size_t out_len; + int r; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); - apdu.le = sizeof(rbuf); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); + LOG_FUNC_CALLED(card->ctx); - while (count > 0) - { - ret = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed"); - ret = sc_check_sw(card, apdu.sw1, apdu.sw2); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Get challenge failed"); - if (apdu.resplen != sizeof(rbuf)) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN); - n = count < sizeof(rbuf) ? count : sizeof(rbuf); - memcpy(rnd, rbuf, n); - count -= n; - rnd += n; + r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); + + if (len < (size_t) r) { + out_len = len; + } else { + out_len = (size_t) r; } - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); + memcpy(rnd, rbuf, out_len); + + LOG_FUNC_RETURN(card->ctx, (int) out_len); } @@ -2474,7 +2614,7 @@ r = sc_get_challenge(card, random, 8); LOG_TEST_RET(card->ctx, r, "get challenge external_key_auth failed"); - r = hash_data(data, datalen, hash); + r = hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); LOG_TEST_RET(card->ctx, r, "hash data failed"); des3_encrypt_cbc(hash, HASH_LEN, iv, random, 8, tmp_data); @@ -2493,7 +2633,7 @@ static int update_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, - unsigned char *data, unsigned long datalen) + const unsigned char *data, unsigned long datalen) { int r; struct sc_apdu apdu; @@ -2501,7 +2641,7 @@ unsigned char tmp_data[256] = { 0 }; unsigned char maxtries = 0; - r = hash_data(data, datalen, hash); + r = hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); LOG_TEST_RET(card->ctx, r, "hash data failed"); r = get_external_key_maxtries(card, &maxtries); @@ -2552,15 +2692,19 @@ data->pin1.max_tries = maxtries; } - - return r; +//remove below code, because the old implement only return PIN retries, now modify the code and return PIN status +// return r; } - /* verify */ - if (data->cmd == SC_PIN_CMD_UNBLOCK) { + else if (data->cmd == SC_PIN_CMD_UNBLOCK) { /* verify */ r = external_key_auth(card, (kid + 1), (unsigned char *)data->pin1.data, data->pin1.len); LOG_TEST_RET(card->ctx, r, "verify pin failed"); } + else if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) { /* change */ + r = update_secret_key(card, 0x04, kid, data->pin2.data, + (unsigned long)data->pin2.len); + LOG_TEST_RET(card->ctx, r, "verify pin failed"); + } else { r = external_key_auth(card, kid, (unsigned char *)data->pin1.data, data->pin1.len); @@ -2571,13 +2715,11 @@ } LOG_TEST_RET(card->ctx, r, "verify pin failed"); - - if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) { - /* change */ - r = update_secret_key(card, 0x04, kid, (unsigned char *)data->pin2.data, - (unsigned long)data->pin2.len); - LOG_TEST_RET(card->ctx, r, "verify pin failed"); + if (r == SC_SUCCESS) + { + data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; } + return r; } diff -Nru opensc-0.17.0/src/libopensc/card-flex.c opensc-0.19.0/src/libopensc/card-flex.c --- opensc-0.17.0/src/libopensc/card-flex.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-flex.c 2018-09-13 11:47:21.000000000 +0000 @@ -31,7 +31,7 @@ #define FLAG_KEYGEN 0x80000000 #define IS_CYBERFLEX(card) (card->type == SC_CARD_TYPE_FLEX_CYBER) -static struct sc_atr_table flex_atrs[] = { +static const struct sc_atr_table flex_atrs[] = { /* Cryptoflex */ /* 8k win2000 */ { "3b:95:15:40:20:68:01:02:00:00", NULL, "Cryptoflex 8K", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL }, @@ -64,7 +64,7 @@ /* 32K e-gate v4 */ { "3B:95:18:40:FF:62:04:01:01:05", NULL, "Cryptoflex 32K e-gate v4", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL }, - /* new cryptoflex 32k card - atr looks very similiar to old 8k card */ + /* new cryptoflex 32k card - atr looks very similar to old 8k card */ { "3b:95:15:40:ff:68:01:02:45:47", NULL, "Cryptoflex 32K", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL }, { "3B:E2:00:00:40:20:49:06", NULL, "Cryptoflex", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL }, diff -Nru opensc-0.17.0/src/libopensc/card-gemsafeV1.c opensc-0.19.0/src/libopensc/card-gemsafeV1.c --- opensc-0.17.0/src/libopensc/card-gemsafeV1.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-gemsafeV1.c 2018-09-13 11:47:21.000000000 +0000 @@ -44,7 +44,7 @@ }; /* Known ATRs */ -static struct sc_atr_table gemsafe_atrs[] = { +static const struct sc_atr_table gemsafe_atrs[] = { /* standard version */ {"3B:7B:94:00:00:80:65:B0:83:01:01:74:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, {"3B:6B:00:00:80:65:B0:83:01:01:74:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, @@ -180,9 +180,9 @@ memcpy(exdata->aid, gemsafe_pteid_aid, sizeof(gemsafe_pteid_aid)); exdata->aid_len = sizeof(gemsafe_pteid_aid); } else if (card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { - memcpy(exdata->aid, gemsafe_seeid_aid, sizeof(gemsafe_seeid_aid)); - exdata->aid_len = sizeof(gemsafe_seeid_aid); - } + memcpy(exdata->aid, gemsafe_seeid_aid, sizeof(gemsafe_seeid_aid)); + exdata->aid_len = sizeof(gemsafe_seeid_aid); + } /* increase lock_count here to prevent sc_unlock to select * applet twice in gp_select_applet */ @@ -192,7 +192,7 @@ if (r < 0) { free(exdata); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "applet selection failed\n"); - return SC_ERROR_INTERNAL; + return SC_ERROR_INVALID_CARD; } card->lock_count--; @@ -232,7 +232,7 @@ card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; card->drv_data = exdata; - return 0; + return SC_SUCCESS; } static int gemsafe_finish(sc_card_t *card) @@ -566,6 +566,20 @@ return r; } +static int gemsafe_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0 && exdata) { + r = gp_select_applet(card, exdata->aid, exdata->aid_len); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + static struct sc_card_driver *sc_get_driver(void) { struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); @@ -585,6 +599,7 @@ gemsafe_ops.get_challenge = gemsafe_get_challenge; gemsafe_ops.process_fci = gemsafe_process_fci; gemsafe_ops.pin_cmd = iso_ops->pin_cmd; + gemsafe_ops.card_reader_lock_obtained = gemsafe_card_reader_lock_obtained; return &gemsafe_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-gids.c opensc-0.19.0/src/libopensc/card-gids.c --- opensc-0.17.0/src/libopensc/card-gids.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-gids.c 2018-09-13 11:47:21.000000000 +0000 @@ -33,6 +33,7 @@ #include #include +#include "../common/compat_strlcpy.h" #ifdef ENABLE_OPENSSL /* openssl only needed for card administration */ @@ -117,7 +118,7 @@ struct gids_aid { int enumtag; - size_t len_short; /* min lenght without version */ + size_t len_short; /* min length without version */ size_t len_long; /* With version and other stuff */ u8 *value; }; @@ -393,7 +394,7 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); } -// check for the existance of a file +// check for the existence of a file static int gids_does_file_exists(sc_card_t *card, char* directory, char* filename) { struct gids_private_data* privatedata = (struct gids_private_data*) card->drv_data; int fileIdentifier, dataObjectIdentifier; @@ -462,7 +463,7 @@ memset(masterfilebuffer + offset, 0, sizeof(gids_mf_record_t)); record = (gids_mf_record_t*) (masterfilebuffer + offset); strncpy(record->directory, directory, 8); - strncpy(record->filename, filename, 8); + strlcpy(record->filename, filename, sizeof(record->filename)); record->fileIdentifier = fileIdentifier; record->dataObjectIdentifier = dataObjectIdentifier; @@ -533,17 +534,19 @@ r = gids_get_DO(card, GIDS_APPLET_EFID, dataObjectIdentifier, buffer, &buffersize); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "unable to update the masterfile"); - p = sc_asn1_find_tag(card->ctx, buffer, sizeof(buffer), GIDS_TRY_COUNTER_OLD_TAG, &datasize); + buffersize = buffersize > sizeof(buffer) ? sizeof(buffer) : buffersize; + + p = sc_asn1_find_tag(card->ctx, buffer, buffersize, GIDS_TRY_COUNTER_OLD_TAG, &datasize); if (p && datasize == 1) { if (tries_left) *tries_left = p[0]; } - p = sc_asn1_find_tag(card->ctx, buffer, sizeof(buffer), GIDS_TRY_COUNTER_TAG, &datasize); + p = sc_asn1_find_tag(card->ctx, buffer, buffersize, GIDS_TRY_COUNTER_TAG, &datasize); if (p && datasize == 1) { if (tries_left) *tries_left = p[0]; } - p = sc_asn1_find_tag(card->ctx, buffer, sizeof(buffer), GIDS_TRY_LIMIT_TAG, &datasize); + p = sc_asn1_find_tag(card->ctx, buffer, buffersize , GIDS_TRY_LIMIT_TAG, &datasize); if (p && datasize == 1) { if (tries_left) *max_tries = p[0]; @@ -631,7 +634,7 @@ // cache some data in memory data = (struct gids_private_data*) calloc(1, sizeof(struct gids_private_data)); if (!data) { - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); } memset(data, 0, sizeof(struct gids_private_data)); card->drv_data = data; @@ -743,6 +746,7 @@ assert(card != NULL && env != NULL); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); + memset(sbuf, 0, sizeof(sbuf)); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, INS_MANAGE_SECURITY_ENVIRONMENT, P1_DECIPHERMENT_INTERNAL_AUTHENTICATE_KEY_AGREEMENT, 0); switch (env->operation) { @@ -772,7 +776,7 @@ if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED); } - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; @@ -901,7 +905,7 @@ } if (response && responselen) - sc_log(card->ctx, "encoded public key: %s", sc_dump_hex(*response, *responselen)); + sc_log_hex(card->ctx, "encoded public key", *response, *responselen); return SC_SUCCESS; } @@ -1052,7 +1056,7 @@ memset(container, 0, sizeof(sc_cardctl_gids_get_container_t)); container->containernum = num; - if (!records[num].bFlags & CONTAINER_MAP_VALID_CONTAINER) { + if (!(records[num].bFlags & CONTAINER_MAP_VALID_CONTAINER)) { return SC_SUCCESS; } // ignore problematic containers @@ -1129,7 +1133,7 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS); } } - snprintf(ch_tmp, sizeof(ch_tmp), "3FFFB0%02X", key_info->key_reference); + snprintf(ch_tmp, sizeof(ch_tmp), "3FFFB0%02X", (u8) (0xFF & key_info->key_reference)); sc_format_path(ch_tmp, &(key_info->path)); return SC_SUCCESS; } @@ -1258,7 +1262,6 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); } // else can be empty if not record - keymaprecordnum = 0; keymapbuffersize = 0; } else { keymaprecordnum = (keymapbuffersize - 1) / sizeof(struct gids_keymap_record); @@ -1474,9 +1477,9 @@ int r; char ch_tmp[10]; sc_path_t cpath; - snprintf(ch_tmp, sizeof(ch_tmp), "B0%02X",containernum + GIDS_FIRST_KEY_IDENTIFIER); + snprintf(ch_tmp, sizeof(ch_tmp), "3FFFB0%02X", (u8) (0xFF & (containernum + GIDS_FIRST_KEY_IDENTIFIER))); sc_format_path(ch_tmp, &cpath); - r = iso_ops->select_file(card, &cpath, NULL); + r = gids_select_file(card, &cpath, NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "unable to select the key file"); // delete current selected file memset(&cpath, 0, sizeof(cpath)); @@ -1623,7 +1626,7 @@ unsigned short fileIdentifier, DO; u8 masterfilebuffer[MAX_GIDS_FILE_SIZE]; size_t masterfilebuffersize = 0; - gids_mf_record_t *records = (gids_mf_record_t *) masterfilebuffer; + gids_mf_record_t *records = (gids_mf_record_t *) (masterfilebuffer+1); size_t recordcount, recordnum = (size_t) -1; size_t i; @@ -1645,7 +1648,7 @@ memcpy(masterfilebuffer, privatedata->masterfile, privatedata->masterfilesize); masterfilebuffersize = privatedata->masterfilesize; - recordcount = (masterfilebuffersize / sizeof(gids_mf_record_t)); + recordcount = ((masterfilebuffersize-1) / sizeof(gids_mf_record_t)); for (i = 0; i < recordcount; i++) { if (records[i].fileIdentifier == fileIdentifier && records[i].dataObjectIdentifier == DO) { recordnum = i; @@ -1656,7 +1659,7 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND); } - for (i = (recordnum+1) * sizeof(gids_mf_record_t); i < masterfilebuffersize; i++) { + for (i = 1 + (recordnum+1) * sizeof(gids_mf_record_t); i < masterfilebuffersize; i++) { masterfilebuffer[i - sizeof(gids_mf_record_t)] = masterfilebuffer[i]; } masterfilebuffersize -= sizeof(gids_mf_record_t); @@ -1766,7 +1769,7 @@ u8 EveryoneReadAdminWriteAc[] = {0x62,0x0C,0x82,0x01,0x39,0x83,0x02,0xA0,0x12,0x8C,0x03,0x03,0x20,0x00}; u8 UserReadWriteAc[] = {0x62,0x0C,0x82,0x01,0x39,0x83,0x02,0xA0,0x13,0x8C,0x03,0x03,0x30,0x30}; u8 AdminReadWriteAc[] = {0x62,0x0C,0x82,0x01,0x39,0x83,0x02,0xA0,0x14,0x8C,0x03,0x03,0x20,0x20}; - // File type=18=key file ; type = symetric key + // File type=18=key file ; type = symmetric key u8 AdminKey[] = {0x62,0x1A,0x82,0x01,0x18,0x83,0x02,0xB0,0x80,0x8C,0x04,0x87,0x00,0x20,0xFF,0xA5, 0x0B,0xA4,0x09,0x80,0x01,0x02,0x83,0x01,0x80,0x95,0x01,0xC0}; // file used to store other file references. Format undocumented. @@ -1879,13 +1882,13 @@ u8 apduSetRandomResponse[256]; u8* randomR2 = apduSetRandomResponse+4; u8 apduSendReponse[40 + 4] = {0x7C,0x2A,0x82,0x28}; - // according to the specification, the z size (z1||z2) should be 14 bytes - // but because the buffer must be a multiple of the 3DES block size (8 bytes), 7 isn't working u8 z1[8]; u8 buffer[16+16+8]; u8* buffer2 = apduSendReponse + 4; int buffer2size = 40; u8 apduSendResponseResponse[256]; + u8 buffer3[16+16+8]; + int buffer3size = 40; sc_apdu_t apdu; const EVP_CIPHER *cipher; @@ -1923,8 +1926,10 @@ SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_check_sw(card, apdu.sw1, apdu.sw2), "invalid return"); // compute the half size of the mutual authentication secret - r = RAND_bytes(z1, sizeof(z1)); + r = RAND_bytes(z1, 7); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "unable to set computer random"); + // set the padding + z1[7] = 0x80; // Encrypt R2||R1||Z1 memcpy(buffer, randomR2, 16); @@ -1963,6 +1968,47 @@ r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_check_sw(card, apdu.sw1, apdu.sw2), "invalid return"); + + if (apdu.resplen != 44) + { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Expecting a response len of 44 - found %d",(int) apdu.resplen); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); + } + // init crypto + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); + } + if (!EVP_DecryptInit(ctx, cipher, key, NULL)) { + EVP_CIPHER_CTX_free(ctx); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); + } + EVP_CIPHER_CTX_set_padding(ctx,0); + if (!EVP_DecryptUpdate(ctx, buffer3, &buffer3size, apdu.resp + 4, apdu.resplen - 4)) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unable to decrypt data"); + EVP_CIPHER_CTX_free(ctx); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PIN_CODE_INCORRECT); + } + if(!EVP_DecryptFinal(ctx, buffer3+buffer3size, &buffer3size)) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unable to decrypt final data"); + EVP_CIPHER_CTX_free(ctx); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PIN_CODE_INCORRECT); + } + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "data has been decrypted using the key"); + if (memcmp(buffer3, randomR1, 16) != 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "R1 doesn't match"); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PIN_CODE_INCORRECT); + } + if (memcmp(buffer3 + 16, randomR2, 16) != 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "R2 doesn't match"); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PIN_CODE_INCORRECT); + } + if (buffer[39] != 0x80) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding not found"); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PIN_CODE_INCORRECT); + } + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); #endif @@ -2004,13 +2050,27 @@ } } +static int gids_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0) { + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + size_t resplen = sizeof(rbuf); + r = gids_select_aid(card, gids_aid.value, gids_aid.len, rbuf, &resplen); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + static struct sc_card_driver *sc_get_driver(void) { if (iso_ops == NULL) iso_ops = sc_get_iso7816_driver()->ops; - gids_ops.match_card = gids_match_card; gids_ops.init = gids_init; gids_ops.finish = gids_finish; @@ -2045,6 +2105,8 @@ gids_ops.put_data = NULL; gids_ops.delete_record = NULL; gids_ops.read_public_key = gids_read_public_key; + gids_ops.card_reader_lock_obtained = gids_card_reader_lock_obtained; + return &gids_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-gpk.c opensc-0.19.0/src/libopensc/card-gpk.c --- opensc-0.17.0/src/libopensc/card-gpk.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-gpk.c 2018-09-13 11:47:21.000000000 +0000 @@ -86,7 +86,7 @@ /* * ATRs of GPK4000 cards courtesy of libscez */ -static struct sc_atr_table gpk_atrs[] = { +static const struct sc_atr_table gpk_atrs[] = { { "3B:27:00:80:65:A2:04:01:01:37", NULL, "GPK 4K", SC_CARD_TYPE_GPK_GPK4000_s, 0, NULL }, { "3B:27:00:80:65:A2:05:01:01:37", NULL, "GPK 4K", SC_CARD_TYPE_GPK_GPK4000_sp, 0, NULL }, { "3B:27:00:80:65:A2:0C:01:01:37", NULL, "GPK 4K", SC_CARD_TYPE_GPK_GPK4000_su256, 0, NULL }, @@ -206,7 +206,7 @@ /* Make sure max send/receive size is 4 byte aligned and <256. */ card->max_recv_size = 252; - return 0; + return SC_SUCCESS; } /* @@ -409,6 +409,9 @@ if (sp[0] == 0x85) { unsigned int ac[3], n; + if (sp + 11 + 2*3 >= end) + break; + file->id = (sp[4] << 8) | sp[5]; file->size = (sp[8] << 8) | sp[9]; file->record_length = sp[7]; @@ -1507,7 +1510,7 @@ } /* - * Store a privat key component + * Store a private key component */ static int gpk_pkfile_load(sc_card_t *card, struct sc_cardctl_gpk_pkload *args) @@ -1527,13 +1530,8 @@ return SC_ERROR_INTERNAL; if (0) { - char buf[2048]; - - sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL, - args->data, args->datalen, - buf, sizeof(buf)); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Sending %d bytes (cleartext):\n%s", - args->datalen, buf); + sc_log_hex(card->ctx, "Sending (cleartext)", + args->data, args->datalen); } memset(&apdu, 0, sizeof(apdu)); diff -Nru opensc-0.17.0/src/libopensc/card-iasecc.c opensc-0.19.0/src/libopensc/card-iasecc.c --- opensc-0.17.0/src/libopensc/card-iasecc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-iasecc.c 2018-09-13 11:47:21.000000000 +0000 @@ -45,6 +45,7 @@ /* #include "sm.h" */ #include "pkcs15.h" /* #include "hash-strings.h" */ +#include "gp.h" #include "iasecc.h" @@ -69,7 +70,7 @@ NULL, 0, NULL }; -static struct sc_atr_table iasecc_known_atrs[] = { +static const struct sc_atr_table iasecc_known_atrs[] = { { "3B:7F:96:00:00:00:31:B8:64:40:70:14:10:73:94:01:80:82:90:00", "FF:FF:FF:FF:FF:FF:FF:FE:FF:FF:00:00:FF:FF:FF:FF:FF:FF:FF:FF", "IAS/ECC Gemalto", SC_CARD_TYPE_IASECC_GEMALTO, 0, NULL }, @@ -90,12 +91,6 @@ { NULL, NULL, NULL, 0, 0, NULL } }; -static struct sc_aid GlobalPlatform_CardManager_AID = { - { 0xA0,0x00,0x00,0x00,0x03,0x00,0x00}, 7 -}; -static struct sc_aid GlobalPlatform_ISD_Default_RID = { - { 0xA0,0x00,0x00,0x01,0x51,0x00,0x00}, 7 -}; static struct sc_aid OberthurIASECC_AID = { {0xA0,0x00,0x00,0x00,0x77,0x01,0x08,0x00,0x07,0x00,0x00,0xFE,0x00,0x00,0x01,0x00}, 16 }; @@ -157,7 +152,7 @@ else memset(pin_status->sha1, 0, SHA_DIGEST_LENGTH); - sc_log(ctx, "iasecc_chv_cache_verified() sha1(PIN): %s", sc_dump_hex(pin_status->sha1, SHA_DIGEST_LENGTH)); + sc_log_hex(ctx, "iasecc_chv_cache_verified() sha1(PIN)", pin_status->sha1, SHA_DIGEST_LENGTH); if (!current) { if (!checked_pins) { @@ -219,7 +214,7 @@ SHA1(pin_cmd->pin1.data, pin_cmd->pin1.len, data_sha1); else memset(data_sha1, 0, SHA_DIGEST_LENGTH); - sc_log(ctx, "data_sha1: %s", sc_dump_hex(data_sha1, SHA_DIGEST_LENGTH)); + sc_log_hex(ctx, "data_sha1: %s", data_sha1, SHA_DIGEST_LENGTH); for(current = checked_pins; current; current = current->next) if (current->reference == pin_cmd->pin_reference) @@ -253,7 +248,7 @@ struct sc_apdu apdu; unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE]; - /* ISO 'select' command failes when not FCP data returned */ + /* ISO 'select' command fails when not FCP data returned */ sc_format_path("3F00", &path); path.type = SC_PATH_TYPE_FILE_ID; @@ -264,6 +259,9 @@ apdu.resplen = sizeof(apdu_resp); apdu.resp = apdu_resp; + if (card->type == SC_CARD_TYPE_IASECC_MI2) + apdu.p2 = 0x04; + rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); @@ -280,7 +278,7 @@ /* Ignore the FCP of the MF, because: * - some cards do not return it; - * - there is not need of it -- create/delete of the files in MF is not invisaged. + * - there is not need of it -- create/delete of the files in MF is not envisaged. */ mf_file = sc_file_new(); if (mf_file == NULL) @@ -316,7 +314,7 @@ int rv; /* Select application (deselect previously selected application) */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x00); + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x04, 0x00); apdu.lc = aid->len; apdu.data = aid->value; apdu.datalen = aid->len; @@ -342,7 +340,6 @@ struct sc_context *ctx = card->ctx; int i; - sc_log(ctx, "iasecc_match_card(%s) called", sc_dump_hex(card->atr.value, card->atr.len)); i = _sc_match_atr(card, iasecc_known_atrs, &card->type); if (i < 0) { sc_log(ctx, "card not matched"); @@ -454,7 +451,7 @@ if (*hist != 0x80 || ((*(hist+1)&0xF0) != 0xF0)) LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_FOUND); - sc_log(ctx, "AID in historical_bytes '%s'", sc_dump_hex(hist + 2, *(hist+1) & 0x0F)); + sc_log_hex(ctx, "AID in historical_bytes", hist + 2, *(hist+1) & 0x0F); if (memcmp(hist + 2, OberthurIASECC_AID.value, *(hist+1) & 0x0F)) LOG_FUNC_RETURN(ctx, SC_ERROR_RECORD_NOT_FOUND); @@ -475,8 +472,6 @@ iasecc_init_oberthur(struct sc_card *card) { struct sc_context *ctx = card->ctx; - unsigned char resp[0x100]; - size_t resp_len; unsigned int flags; int rv = 0; @@ -493,10 +488,9 @@ iasecc_parse_ef_atr(card); - resp_len = sizeof(resp); - if (iasecc_select_aid(card, &GlobalPlatform_CardManager_AID, resp, &resp_len)) { - resp_len = sizeof(resp); - iasecc_select_aid(card, &GlobalPlatform_ISD_Default_RID, resp, &resp_len); + /* if we fail to select CM, */ + if (gp_select_card_manager(card)) { + gp_select_isd_rid(card); } rv = iasecc_oberthur_match(card); @@ -514,38 +508,33 @@ static int -iasecc_init_sagem(struct sc_card *card) +iasecc_mi_match(struct sc_card *card) { struct sc_context *ctx = card->ctx; - unsigned int flags; + unsigned char resp[0x100]; + size_t resp_len; int rv = 0; LOG_FUNC_CALLED(ctx); - flags = IASECC_CARD_DEFAULT_FLAGS; - - _sc_card_add_rsa_alg(card, 1024, flags, 0x10001); - _sc_card_add_rsa_alg(card, 2048, flags, 0x10001); - - card->caps = SC_CARD_CAP_RNG; - card->caps |= SC_CARD_CAP_APDU_EXT; - card->caps |= SC_CARD_CAP_USE_FCI_AC; + resp_len = sizeof(resp); + rv = iasecc_select_aid(card, &MIIASECC_AID, resp, &resp_len); + LOG_TEST_RET(ctx, rv, "IASECC: failed to select MI IAS/ECC applet"); - rv = iasecc_parse_ef_atr(card); - if (rv == SC_ERROR_FILE_NOT_FOUND) { - rv = iasecc_select_mf(card, NULL); - LOG_TEST_RET(ctx, rv, "MF selection error"); + if (!card->ef_atr) + card->ef_atr = calloc(1, sizeof(struct sc_ef_atr)); + if (!card->ef_atr) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - rv = iasecc_parse_ef_atr(card); - } - LOG_TEST_RET(ctx, rv, "IASECC: ATR parse failed"); + memcpy(card->ef_atr->aid.value, MIIASECC_AID.value, MIIASECC_AID.len); + card->ef_atr->aid.len = MIIASECC_AID.len; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } static int -iasecc_init_amos(struct sc_card *card) +iasecc_init_amos_or_sagem(struct sc_card *card) { struct sc_context *ctx = card->ctx; unsigned int flags; @@ -562,6 +551,14 @@ card->caps |= SC_CARD_CAP_APDU_EXT; card->caps |= SC_CARD_CAP_USE_FCI_AC; + if (card->type == SC_CARD_TYPE_IASECC_MI) { + rv = iasecc_mi_match(card); + if (rv) + card->type = SC_CARD_TYPE_IASECC_MI2; + else + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + } + rv = iasecc_parse_ef_atr(card); if (rv == SC_ERROR_FILE_NOT_FOUND) { rv = iasecc_select_mf(card, NULL); @@ -569,58 +566,11 @@ rv = iasecc_parse_ef_atr(card); } - LOG_TEST_RET(ctx, rv, "IASECC: ATR parse failed"); - LOG_FUNC_RETURN(ctx, SC_SUCCESS); -} - -static int -iasecc_mi_match(struct sc_card *card) -{ - struct sc_context *ctx = card->ctx; - - LOG_FUNC_CALLED(ctx); - - if (!card->ef_atr) - card->ef_atr = calloc(1, sizeof(struct sc_ef_atr)); - if (!card->ef_atr) - LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - - memcpy(card->ef_atr->aid.value, MIIASECC_AID.value, MIIASECC_AID.len); - card->ef_atr->aid.len = MIIASECC_AID.len; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } -static int -iasecc_init_mi(struct sc_card *card) -{ - struct sc_context *ctx = card->ctx; - unsigned int flags; - unsigned char resp[0x100]; - size_t resp_len; - int rv = 0; - - LOG_FUNC_CALLED(ctx); - - flags = IASECC_CARD_DEFAULT_FLAGS; - - _sc_card_add_rsa_alg(card, 1024, flags, 0x10001); - _sc_card_add_rsa_alg(card, 2048, flags, 0x10001); - - card->caps = SC_CARD_CAP_RNG; - card->caps |= SC_CARD_CAP_APDU_EXT; - card->caps |= SC_CARD_CAP_USE_FCI_AC; - - resp_len = sizeof(resp); - rv = iasecc_select_aid(card, &MIIASECC_AID, resp, &resp_len); - LOG_TEST_RET(ctx, rv, "Could not select MI's AID"); - - rv = iasecc_mi_match(card); - LOG_TEST_RET(ctx, rv, "Could not match MI's AID"); - - LOG_FUNC_RETURN(ctx, SC_SUCCESS); -} static int iasecc_init(struct sc_card *card) @@ -642,13 +592,13 @@ else if (card->type == SC_CARD_TYPE_IASECC_OBERTHUR) rv = iasecc_init_oberthur(card); else if (card->type == SC_CARD_TYPE_IASECC_SAGEM) - rv = iasecc_init_sagem(card); + rv = iasecc_init_amos_or_sagem(card); else if (card->type == SC_CARD_TYPE_IASECC_AMOS) - rv = iasecc_init_amos(card); + rv = iasecc_init_amos_or_sagem(card); else if (card->type == SC_CARD_TYPE_IASECC_MI) - rv = iasecc_init_mi(card); + rv = iasecc_init_amos_or_sagem(card); else - LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_CARD); if (!rv) { @@ -665,7 +615,7 @@ LOG_TEST_RET(ctx, rv, "Select EF.ATR AID failed"); } - rv = iasecc_get_serialnr(card, NULL); + iasecc_get_serialnr(card, NULL); } #ifdef ENABLE_SM @@ -854,7 +804,7 @@ /* TODO: redesign using of cache - * TODO: do not keep inermediate results in 'file_out' argument */ + * TODO: do not keep intermediate results in 'file_out' argument */ static int iasecc_select_file(struct sc_card *card, const struct sc_path *path, struct sc_file **file_out) @@ -875,16 +825,16 @@ sc_log(ctx, "iasecc_select_file() path:%s", sc_print_path(path)); sc_print_cache(card); - if (lpath.len >= 2 && lpath.value[0] == 0x3F && lpath.value[1] == 0x00) { + if (path->type != SC_PATH_TYPE_DF_NAME + && lpath.len >= 2 + && lpath.value[0] == 0x3F && lpath.value[1] == 0x00) { sc_log(ctx, "EF.ATR(aid:'%s')", card->ef_atr ? sc_dump_hex(card->ef_atr->aid.value, card->ef_atr->aid.len) : ""); rv = iasecc_select_mf(card, file_out); LOG_TEST_RET(ctx, rv, "MF selection error"); - if (lpath.len >= 2 && lpath.value[0] == 0x3F && lpath.value[1] == 0x00) { - memmove(&lpath.value[0], &lpath.value[2], lpath.len - 2); - lpath.len -= 2; - } + memmove(&lpath.value[0], &lpath.value[2], lpath.len - 2); + lpath.len -= 2; } if (lpath.aid.len) { @@ -950,7 +900,8 @@ && card->type != SC_CARD_TYPE_IASECC_OBERTHUR && card->type != SC_CARD_TYPE_IASECC_SAGEM && card->type != SC_CARD_TYPE_IASECC_AMOS - && card->type != SC_CARD_TYPE_IASECC_MI) + && card->type != SC_CARD_TYPE_IASECC_MI + && card->type != SC_CARD_TYPE_IASECC_MI2) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported card"); if (lpath.type == SC_PATH_TYPE_FILE_ID) { @@ -963,6 +914,8 @@ apdu.p2 = 0x04; if (card->type == SC_CARD_TYPE_IASECC_MI) apdu.p2 = 0x04; + if (card->type == SC_CARD_TYPE_IASECC_MI2) + apdu.p2 = 0x04; } else if (lpath.type == SC_PATH_TYPE_FROM_CURRENT) { apdu.p1 = 0x09; @@ -972,6 +925,8 @@ apdu.p2 = 0x04; if (card->type == SC_CARD_TYPE_IASECC_MI) apdu.p2 = 0x04; + if (card->type == SC_CARD_TYPE_IASECC_MI2) + apdu.p2 = 0x04; } else if (lpath.type == SC_PATH_TYPE_PARENT) { apdu.p1 = 0x03; @@ -982,6 +937,8 @@ apdu.p1 = 0x04; if (card->type == SC_CARD_TYPE_IASECC_AMOS) apdu.p2 = 0x04; + if (card->type == SC_CARD_TYPE_IASECC_MI2) + apdu.p2 = 0x04; } else { sc_log(ctx, "Invalid PATH type: 0x%X", lpath.type); @@ -1022,7 +979,7 @@ * (or invent something else) */ if (rv == SC_ERROR_FILE_NOT_FOUND && cache_valid && df_from_cache) { - card->cache.valid = 0; + sc_invalidate_cache(card); sc_log(ctx, "iasecc_select_file() file not found, retry without cached DF"); if (file_out) { sc_file_free(*file_out); @@ -1372,6 +1329,29 @@ LOG_FUNC_RETURN(ctx, rv); } +static int +iasecc_get_challenge(struct sc_card *card, u8 * rnd, size_t len) +{ + /* As IAS/ECC cannot handle other data length than 0x08 */ + u8 rbuf[8]; + size_t out_len; + int r; + + LOG_FUNC_CALLED(card->ctx); + + r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); + + if (len < (size_t) r) { + out_len = len; + } else { + out_len = (size_t) r; + } + memcpy(rnd, rbuf, out_len); + + LOG_FUNC_RETURN(card->ctx, (int) out_len); +} + static int iasecc_logout(struct sc_card *card) @@ -1782,7 +1762,7 @@ LOG_TEST_RET(ctx, rv, "Cannot convert SC_AC_OP_PSO_DECRYPT acl"); algo_ref = iasecc_get_algorithm(ctx, env, SC_PKCS15_ALGO_OP_DECIPHER, CKM_RSA_PKCS); if (!algo_ref) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Application do not supports DECHIPHER:RSA_PKCS"); + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Application do not supports DECIPHER:RSA_PKCS"); cse_crt_ct[2] = env->key_ref[0] | IASECC_OBJECT_REF_LOCAL; cse_crt_ct[5] = algo_ref; /* IASECC_ALGORITHM_RSA_PKCS_DECRYPT | IASECC_ALGORITHM_SHA1 */ @@ -2162,21 +2142,27 @@ if (card->cache.valid && card->cache.current_df) { sc_file_dup(&save_current_df, card->cache.current_df); - if (save_current_df == NULL) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate current DF file"); + if (save_current_df == NULL) { + rv = SC_ERROR_OUT_OF_MEMORY; + sc_log(ctx, "Cannot duplicate current DF file"); + goto err; + } } if (card->cache.valid && card->cache.current_ef) { sc_file_dup(&save_current_ef, card->cache.current_ef); - if (save_current_ef == NULL) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate current EF file"); + if (save_current_ef == NULL) { + rv = SC_ERROR_OUT_OF_MEMORY; + sc_log(ctx, "Cannot duplicate current EF file"); + goto err; + } } if (!(data->pin_reference & IASECC_OBJECT_REF_LOCAL) && card->cache.valid && card->cache.current_df) { sc_format_path("3F00", &path); path.type = SC_PATH_TYPE_FILE_ID; rv = iasecc_select_file(card, &path, NULL); - LOG_TEST_RET(ctx, rv, "Unable to select MF"); + LOG_TEST_GOTO_ERR(ctx, rv, "Unable to select MF"); } memset(&sdo, 0, sizeof(sdo)); @@ -2187,10 +2173,13 @@ sc_log(ctx, "iasecc_pin_get_policy() reference %i", sdo.sdo_ref); rv = iasecc_sdo_get_data(card, &sdo); - LOG_TEST_RET(ctx, rv, "Cannot get SDO PIN data"); + LOG_TEST_GOTO_ERR(ctx, rv, "Cannot get SDO PIN data"); - if (sdo.docp.acls_contact.size == 0) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Extremely strange ... there is no ACLs"); + if (sdo.docp.acls_contact.size == 0) { + rv = SC_ERROR_INVALID_DATA; + sc_log(ctx, "Extremely strange ... there is no ACLs"); + goto err; + } sc_log(ctx, "iasecc_pin_get_policy() sdo.docp.size.size %"SC_FORMAT_LEN_SIZE_T"u", @@ -2218,13 +2207,13 @@ se.reference = acl->key_ref; rv = iasecc_se_get_info(card, &se); - LOG_TEST_RET(ctx, rv, "SDO get data error"); + LOG_TEST_GOTO_ERR(ctx, rv, "SDO get data error"); } if (scb & IASECC_SCB_METHOD_USER_AUTH) { rv = iasecc_se_get_crt_by_usage(card, &se, IASECC_CRT_TAG_AT, IASECC_UQB_AT_USER_PASSWORD, &acl->crts[crt_num]); - LOG_TEST_RET(ctx, rv, "no authentication template for 'USER PASSWORD'"); + LOG_TEST_GOTO_ERR(ctx, rv, "no authentication template for 'USER PASSWORD'"); sc_log(ctx, "iasecc_pin_get_policy() scb:0x%X; sdo_ref:[%i,%i,...]", scb, acl->crts[crt_num].refs[0], acl->crts[crt_num].refs[1]); crt_num++; @@ -2268,17 +2257,19 @@ if (save_current_df) { sc_log(ctx, "iasecc_pin_get_policy() restore current DF"); rv = iasecc_select_file(card, &save_current_df->path, NULL); - LOG_TEST_RET(ctx, rv, "Cannot return to saved DF"); - sc_file_free(save_current_df); + LOG_TEST_GOTO_ERR(ctx, rv, "Cannot return to saved DF"); } if (save_current_ef) { sc_log(ctx, "iasecc_pin_get_policy() restore current EF"); rv = iasecc_select_file(card, &save_current_ef->path, NULL); - LOG_TEST_RET(ctx, rv, "Cannot return to saved EF"); - sc_file_free(save_current_ef); + LOG_TEST_GOTO_ERR(ctx, rv, "Cannot return to saved EF"); } +err: + sc_file_free(save_current_df); + sc_file_free(save_current_ef); + LOG_FUNC_RETURN(ctx, rv); } @@ -2534,6 +2525,12 @@ static int iasecc_get_serialnr(struct sc_card *card, struct sc_serial_number *serial) { +#if 1 + /* the current implementation doesn't perform any bounds check when parsing + * the serial number. Hence, we disable this code until someone has time to + * fix this. */ + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); +#else struct sc_context *ctx = card->ctx; struct sc_iin *iin = &card->serialnr.iin; struct sc_apdu apdu; @@ -2578,7 +2575,7 @@ if (card->type == SC_CARD_TYPE_IASECC_SAGEM) { /* 5A 0A 92 50 00 20 10 10 25 00 01 3F */ /* 00 02 01 01 02 50 00 13 */ - for (ii=0; ii < rbuf[1] - offs; ii++) + for (ii=0; (ii < rbuf[1] - offs) && (ii + offs + 2 < sizeof(rbuf)); ii++) *(card->serialnr.value + ii) = ((rbuf[ii + offs + 1] & 0x0F) << 4) + ((rbuf[ii + offs + 2] & 0xF0) >> 4) ; card->serialnr.len = ii; @@ -2603,6 +2600,7 @@ memcpy(serial, &card->serialnr, sizeof(*serial)); LOG_FUNC_RETURN(ctx, SC_SUCCESS); +#endif } @@ -3584,7 +3582,7 @@ /* update_record: Untested */ iasecc_ops.select_file = iasecc_select_file; /* get_response: Untested */ - /* get_challenge: ISO7816 implementation works */ + iasecc_ops.get_challenge = iasecc_get_challenge; iasecc_ops.logout = iasecc_logout; /* restore_security_env */ iasecc_ops.set_security_env = iasecc_set_security_env; diff -Nru opensc-0.17.0/src/libopensc/card-incrypto34.c opensc-0.19.0/src/libopensc/card-incrypto34.c --- opensc-0.17.0/src/libopensc/card-incrypto34.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-incrypto34.c 2018-09-13 11:47:21.000000000 +0000 @@ -47,7 +47,7 @@ NULL, 0, NULL }; -static struct sc_atr_table incrypto34_atrs[] = { +static const struct sc_atr_table incrypto34_atrs[] = { { "3b:ff:18:00:ff:81:31:fe:55:00:6b:02:09:02:00:01:01:01:44:53:44:10:31:80:92", NULL, NULL, SC_CARD_TYPE_INCRYPTO34_GENERIC, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -141,7 +141,7 @@ /* no error, maybe a note */ { 0x9000, SC_SUCCESS, NULL}, { 0x9001, SC_SUCCESS, "success, but eeprom weakness detected"}, -{ 0x9850, SC_SUCCESS, "over/underflow useing in/decrease"} +{ 0x9850, SC_SUCCESS, "over/underflow using in/decrease"} }; static int incrypto34_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) @@ -357,6 +357,7 @@ * generation. */ case SC_FILE_EF_LINEAR_VARIABLE_TLV: type[1] = 0xff; + /* fall through */ default: type[0] |= file->ef_structure & 7; break; diff -Nru opensc-0.17.0/src/libopensc/card-isoApplet.c opensc-0.19.0/src/libopensc/card-isoApplet.c --- opensc-0.17.0/src/libopensc/card-isoApplet.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-isoApplet.c 2018-09-13 11:47:21.000000000 +0000 @@ -46,7 +46,7 @@ { /* Save the current algorithm reference * (ISOAPPLET_ALG_REF_ECDSA, ISOAPPLET_ALG_REF_RSA_PAD_PKCS1) - * to be able to distiguish between RSA and ECC operations. + * to be able to distinguish between RSA and ECC operations. * If ECC is being used, the signatures generated by the card * have to be modified. */ unsigned int sec_env_alg_ref; @@ -95,7 +95,7 @@ * * @param[in] card * @param[in] aid The applet ID. - * @param[in] aid_len The legth of aid. + * @param[in] aid_len The length of aid. * @param[out] resp The response of the applet upon selection. * @param[in,out] resp_len In: The buffer size of resp. Out: The length of the response. * @@ -125,7 +125,7 @@ apdu.le = 0; rv = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(ctx, rv, "APDU transmit faiure."); + LOG_TEST_RET(ctx, rv, "APDU transmit failure."); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rv, "Card returned error"); @@ -193,7 +193,6 @@ static int isoApplet_init(sc_card_t *card) { - int r; int i; unsigned long flags = 0; unsigned long ext_flags = 0; @@ -211,8 +210,9 @@ card->cla = 0x00; /* Obtain applet version and specific features */ - r = isoApplet_select_applet(card, isoApplet_aid, ISOAPPLET_AID_LEN, rbuf, &rlen); - LOG_TEST_RET(card->ctx, r, "Error obtaining applet version."); + if (0 > isoApplet_select_applet(card, isoApplet_aid, ISOAPPLET_AID_LEN, rbuf, &rlen)) { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Error obtaining applet version."); + } if(rlen < 3) { assert(sizeof(rbuf) >= 3); @@ -479,7 +479,7 @@ } /* - * @brief Encode the EC parameters as a concatenation of TLV enrties. + * @brief Encode the EC parameters as a concatenation of TLV entries. * * The format is: * 81 - prime @@ -589,7 +589,7 @@ * There are two cases: * 1) The card can do ext. apdus: The data fits in one apdu. * 2) The card can't do ext. apdus: sc_transmit_apdu will handle that - the - * card will send SW_BYTES_REMAINING, OpenSC will automaticall do a + * card will send SW_BYTES_REMAINING, OpenSC will automatically do a * GET RESPONSE to get the remaining data, and will append it to the data * buffer. */ if(args->algorithm_ref == SC_ISOAPPLET_ALG_REF_EC_GEN) @@ -1032,7 +1032,7 @@ break; default: - LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Uknown algorithm refernce."); + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unknown algorithm reference."); } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); @@ -1141,7 +1141,7 @@ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; @@ -1211,17 +1211,32 @@ static int isoApplet_get_challenge(struct sc_card *card, u8 *rnd, size_t len) { - struct sc_context *ctx = card->ctx; int r; - LOG_FUNC_CALLED(ctx); + LOG_FUNC_CALLED(card->ctx); - if(card->caps & SC_CARD_CAP_RNG) { + if(card->caps & SC_CARD_CAP_RNG) { r = iso_ops->get_challenge(card, rnd, len); } else { r = SC_ERROR_NOT_SUPPORTED; } - LOG_FUNC_RETURN(ctx, r); + + LOG_FUNC_RETURN(card->ctx, r); +} + +static int isoApplet_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0) { + size_t rlen = SC_MAX_APDU_BUFFER_SIZE; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + r = isoApplet_select_applet(card, isoApplet_aid, ISOAPPLET_AID_LEN, rbuf, &rlen); + } + + LOG_FUNC_RETURN(card->ctx, r); } static struct sc_card_driver *sc_get_driver(void) @@ -1246,6 +1261,7 @@ isoApplet_ops.set_security_env = isoApplet_set_security_env; isoApplet_ops.compute_signature = isoApplet_compute_signature; isoApplet_ops.get_challenge = isoApplet_get_challenge; + isoApplet_ops.card_reader_lock_obtained = isoApplet_card_reader_lock_obtained; /* unsupported functions */ isoApplet_ops.write_binary = NULL; diff -Nru opensc-0.17.0/src/libopensc/card-itacns.c opensc-0.19.0/src/libopensc/card-itacns.c --- opensc-0.17.0/src/libopensc/card-itacns.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-itacns.c 2018-09-13 11:47:21.000000000 +0000 @@ -51,7 +51,7 @@ /* List of ATR's for "hard" matching. */ -static struct sc_atr_table itacns_atrs[] = { +static const struct sc_atr_table itacns_atrs[] = { { "3b:f4:18:00:ff:81:31:80:55:00:31:80:00:c7", NULL, NULL, SC_CARD_TYPE_ITACNS_CIE_V1, 0, NULL}, { NULL, NULL, NULL, 0, 0, NULL} @@ -510,7 +510,7 @@ //Returned file->size should be 16. //We choose to not consider it as critical, because some cards //do not return FCI/FCP templates that include the file size. - //Notify abnormal lenght anyway. + //Notify abnormal length anyway. if (len != 16) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unexpected file length of EF_IDCarta (%lu)\n", diff -Nru opensc-0.17.0/src/libopensc/card-jcop.c opensc-0.19.0/src/libopensc/card-jcop.c --- opensc-0.17.0/src/libopensc/card-jcop.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-jcop.c 2018-09-13 11:47:21.000000000 +0000 @@ -28,7 +28,7 @@ #include "internal.h" #include "cardctl.h" -static struct sc_atr_table jcop_atrs[] = { +static const struct sc_atr_table jcop_atrs[] = { { "3B:E6:00:FF:81:31:FE:45:4A:43:4F:50:33:31:06", NULL, NULL, SC_CARD_TYPE_JCOP_GENERIC, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -434,7 +434,7 @@ /* Files may be locked by anyone who can MODIFY. */ /* opensc seems to think LOCK ACs are only on DFs */ /* sa_to_acl(file, SC_AC_OP_LOCK, sa[0] & 0xf); */ - /* there are seperate SIGN, ENCIPHER, and DECIPHER ACs. + /* there are separate SIGN, ENCIPHER, and DECIPHER ACs. I use SIGN for SC_AC_OP_CRYPTO unless it is NEVER, in which case I use DECIPHER */ if ((sa[1] & 0xf0) == 0x10) @@ -655,7 +655,7 @@ return SC_ERROR_INVALID_ARGUMENTS; } apdu.le = 0; - if (!env->flags & SC_SEC_ENV_ALG_REF_PRESENT) + if (!(env->flags & SC_SEC_ENV_ALG_REF_PRESENT)) return SC_ERROR_INVALID_ARGUMENTS; if (!(env->flags & SC_SEC_ENV_FILE_REF_PRESENT)) return SC_ERROR_INVALID_ARGUMENTS; diff -Nru opensc-0.17.0/src/libopensc/card-jpki.c opensc-0.19.0/src/libopensc/card-jpki.c --- opensc-0.17.0/src/libopensc/card-jpki.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-jpki.c 2018-09-13 11:47:21.000000000 +0000 @@ -28,7 +28,7 @@ #include "internal.h" #include "jpki.h" -static struct sc_atr_table jpki_atrs[] = { +static const struct sc_atr_table jpki_atrs[] = { {"3b:e0:00:ff:81:31:fe:45:14", NULL, NULL, SC_CARD_TYPE_JPKI_BASE, 0, NULL}, {NULL, NULL, NULL, 0, 0, NULL} @@ -82,8 +82,10 @@ struct jpki_private_data *drvdata = JPKI_DRVDATA(card); LOG_FUNC_CALLED(card->ctx); - if (drvdata) { + if (drvdata->mf) { + free(drvdata->mf); + } free(drvdata); card->drv_data = NULL; } @@ -360,6 +362,19 @@ LOG_FUNC_RETURN(card->ctx, apdu.resplen); } +static int jpki_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0) { + r = jpki_select_ap(card); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + static struct sc_card_driver * sc_get_driver(void) { @@ -374,6 +389,7 @@ jpki_ops.pin_cmd = jpki_pin_cmd; jpki_ops.set_security_env = jpki_set_security_env; jpki_ops.compute_signature = jpki_compute_signature; + jpki_ops.card_reader_lock_obtained = jpki_card_reader_lock_obtained; return &jpki_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-masktech.c opensc-0.19.0/src/libopensc/card-masktech.c --- opensc-0.17.0/src/libopensc/card-masktech.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-masktech.c 2018-09-13 11:47:21.000000000 +0000 @@ -273,7 +273,7 @@ change_data.pin2.prompt = data->pin2.prompt; rv = iso_ops->pin_cmd(card, &change_data, tries_left); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed - chnage PIN"); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed - change PIN"); return 0; } diff -Nru opensc-0.17.0/src/libopensc/card-mcrd.c opensc-0.19.0/src/libopensc/card-mcrd.c --- opensc-0.17.0/src/libopensc/card-mcrd.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-mcrd.c 2018-09-13 11:47:21.000000000 +0000 @@ -34,15 +34,16 @@ #include "asn1.h" #include "cardctl.h" #include "esteid.h" +#include "gp.h" -static struct sc_atr_table mcrd_atrs[] = { +static const struct sc_atr_table mcrd_atrs[] = { {"3B:FF:94:00:FF:80:B1:FE:45:1F:03:00:68:D2:76:00:00:28:FF:05:1E:31:80:00:90:00:23", NULL, "Micardo 2.1/German BMI/D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL}, {"3b:6f:00:ff:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00", NULL, - "D-Trust", SC_CARD_TYPE_MCRD_DTRUST, 0, NULL}, + "D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL}, {"3b:ff:11:00:ff:80:b1:fe:45:1f:03:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00:a6", NULL, - "D-Trust", SC_CARD_TYPE_MCRD_DTRUST, 0, NULL}, - /* Certain pcsc-lite versions (1.5.3 for example on Ubuntu 10.04) incorrectly trunkate the wram ATR to the length of the cold ATR */ + "D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL}, + /* Certain pcsc-lite versions (1.5.3 for example on Ubuntu 10.04) incorrectly truncate the warm ATR to the length of the cold ATR */ /* See opensc.conf for further information */ {"3B:FE:94:00:FF:80:B1:FA:45:1F:03:45:73:74:45:49:44:20", NULL, "Broken EstEID 1.1 warm", SC_CARD_TYPE_MCRD_ESTEID_V11, 0, NULL}, {"3b:fe:94:00:ff:80:b1:fa:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:43", NULL, "EstEID 1.0 cold", SC_CARD_TYPE_MCRD_ESTEID_V10, 0, NULL}, @@ -59,13 +60,13 @@ {NULL, NULL, NULL, 0, 0, NULL} }; -static unsigned char EstEID_v3_AID[] = {0xF0, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}; -static unsigned char EstEID_v35_AID[] = {0xD2, 0x33, 0x00, 0x00, 0x00, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x33, 0x35}; -static unsigned char AzeDIT_v35_AID[] = {0xD0, 0x31, 0x00, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x49, 0x44}; +static const struct sc_aid EstEID_v3_AID = { {0xF0, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}, 15 }; +static const struct sc_aid EstEID_v35_AID = { {0xD2, 0x33, 0x00, 0x00, 0x00, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x33, 0x35}, 15 }; +static const struct sc_aid AzeDIT_v35_AID = { {0xD0, 0x31, 0x00, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x49, 0x44}, 11 }; static struct sc_card_operations mcrd_ops; static struct sc_card_driver mcrd_drv = { - "MICARDO 2.1 / EstEID 1.0 - 3.0", + "MICARDO 2.1 / EstEID 1.0 - 3.5", "mcrd", &mcrd_ops, NULL, 0, NULL @@ -119,6 +120,24 @@ #define DRVDATA(card) ((struct mcrd_priv_data *) ((card)->drv_data)) +// Control Reference Template Tag for Key Agreement (ISO 7816-4:2013 Table 54) +static const struct sc_asn1_entry c_asn1_control[] = { + { "control", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 0xA6, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +// Ephemeral public key Template Tag (ISO 7816-8:2016 Table 3) +static const struct sc_asn1_entry c_asn1_ephermal[] = { + { "ephemeral", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 0x7F49, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +// External Public Key +static const struct sc_asn1_entry c_asn1_public[] = { + { "publicKey", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x86, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + static int load_special_files(sc_card_t * card); static int select_part(sc_card_t * card, u8 kind, unsigned short int fid, sc_file_t ** file); @@ -131,10 +150,11 @@ struct mcrd_priv_data *priv = DRVDATA(card); struct df_info_s *dfi; - assert(!priv->is_ef); + if(!(!priv->is_ef)) + return NULL; if (!priv->curpathlen) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "no current path to find the df_info\n"); + sc_log(ctx, "no current path to find the df_info\n"); return NULL; } @@ -147,7 +167,7 @@ /* Not found, create it. */ dfi = calloc(1, sizeof *dfi); if (!dfi) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "out of memory while allocating df_info\n"); + sc_log(ctx, "out of memory while allocating df_info\n"); return NULL; } dfi->pathlen = priv->curpathlen; @@ -184,7 +204,8 @@ int r; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; - assert(card != NULL); + if(!(card != NULL)) + return SC_ERROR_INTERNAL; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xA4); sbuf[0] = 0x83; @@ -202,7 +223,8 @@ sc_apdu_t apdu; int r; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; - assert(card != NULL); + if(!(card != NULL)) + return SC_ERROR_INTERNAL; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6); @@ -224,7 +246,8 @@ int r; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 keyref_data[SC_ESTEID_KEYREF_FILE_RECLEN]; - assert(card != NULL); + if(!(card != NULL)) + return SC_ERROR_INTERNAL; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8); /* track the active keypair */ @@ -235,11 +258,11 @@ SC_ESTEID_KEYREF_FILE_RECLEN, SC_RECORD_BY_REC_NR); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Can't read keyref info file!"); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "authkey reference 0x%02x%02x\n", keyref_data[9], keyref_data[10]); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "signkey reference 0x%02x%02x\n", keyref_data[19], keyref_data[20]); @@ -277,7 +300,6 @@ static int mcrd_match_card(sc_card_t * card) { int i = 0, r = 0; - sc_apdu_t apdu; i = _sc_match_atr(card, mcrd_atrs, &card->type); if (i >= 0) { @@ -285,16 +307,9 @@ return 1; } - sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); - apdu.lc = sizeof(EstEID_v35_AID); - apdu.data = EstEID_v35_AID; - apdu.datalen = sizeof(EstEID_v35_AID); - apdu.resplen = 0; - apdu.le = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); - if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { + LOG_FUNC_CALLED(card->ctx); + r = gp_select_aid(card, &EstEID_v35_AID); + if (r >= 0) { sc_log(card->ctx, "AID found"); card->type = SC_CARD_TYPE_MCRD_ESTEID_V30; return 1; @@ -304,11 +319,10 @@ static int mcrd_init(sc_card_t * card) { - unsigned long flags; + unsigned long flags, ext_flags; struct mcrd_priv_data *priv; int r; sc_path_t tmppath; - sc_apdu_t apdu; priv = calloc(1, sizeof *priv); if (!priv) @@ -329,39 +343,24 @@ flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_SHA1 | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA256; /* EstEID v3.0 has 2048 bit keys */ _sc_card_add_rsa_alg(card, 2048, flags, 0); + + flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE; + ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; + _sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL); sc_reset(card, 0); - sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); - apdu.lc = sizeof(EstEID_v3_AID); - apdu.data = EstEID_v3_AID; - apdu.datalen = sizeof(EstEID_v3_AID); - apdu.resplen = 0; - apdu.le = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); - if(apdu.sw1 != 0x90 && apdu.sw2 != 0x00) + r = gp_select_aid(card, &EstEID_v3_AID); + if (r < 0) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); - apdu.lc = sizeof(EstEID_v35_AID); - apdu.data = EstEID_v35_AID; - apdu.datalen = sizeof(EstEID_v35_AID); - apdu.resplen = 0; - apdu.le = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); - if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); - apdu.lc = sizeof(AzeDIT_v35_AID); - apdu.data = AzeDIT_v35_AID; - apdu.datalen = sizeof(AzeDIT_v35_AID); - apdu.resplen = 0; - apdu.le = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); - if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { + r = gp_select_aid(card, &EstEID_v35_AID); + if (r >= 0) { + // Force EstEID 3.5 card recv size 255 with T=0 to avoid recursive read binary + // sc_read_binary cannot handle recursive 61 00 calls + if (card->reader && card->reader->active_protocol == SC_PROTO_T0) + card->max_recv_size = 255; + } else { + r = gp_select_aid(card, &AzeDIT_v35_AID); + if (r < 0) { free(card->drv_data); card->drv_data = NULL; SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_CARD); @@ -385,6 +384,8 @@ sc_format_path ("3f00", &tmppath); r = sc_select_file (card, &tmppath, NULL); + if (r < 0) + r = SC_ERROR_INVALID_CARD; /* Not needed for the fixed EstEID profile */ if (!is_esteid_card(card)) @@ -452,12 +453,12 @@ } } - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "new EF_Rule file loaded (%d records)\n", recno - 1); + sc_log(ctx, "new EF_Rule file loaded (%d records)\n", recno - 1); /* Read the KeyD file. Note that we bypass our cache here. */ r = select_part(card, MCRD_SEL_EF, EF_KeyD, NULL); if (r == SC_ERROR_FILE_NOT_FOUND) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "no EF_KeyD file available\n"); + sc_log(ctx, "no EF_KeyD file available\n"); return 0; /* That is okay. */ } SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "selecting EF_KeyD failed"); @@ -483,14 +484,14 @@ } } - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "new EF_KeyD file loaded (%d records)\n", recno - 1); + sc_log(ctx, "new EF_KeyD file loaded (%d records)\n", recno - 1); /* FIXME: Do we need to restore the current DF? I guess it is not required, but we could try to do so by selecting 3fff? */ return 0; } /* Return the SE number from the keyD for the FID. If ref_data is not - NULL the reference data is returned; this shoudl be an array of at + NULL the reference data is returned; this should be an array of at least 2 bytes. Returns -1 on error. */ static int get_se_num_from_keyd(sc_card_t * card, unsigned short fid, u8 * ref_data) @@ -500,7 +501,6 @@ struct keyd_record_s *keyd; size_t len, taglen; const u8 *p, *tag; - char dbgbuf[2048]; u8 fidbuf[2]; fidbuf[0] = (fid >> 8) & 0xFF; @@ -508,7 +508,7 @@ dfi = get_df_info(card); if (!dfi || !dfi->keyd_file) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "EF_keyD not loaded\n"); + sc_log(ctx, "EF_keyD not loaded\n"); return -1; } @@ -516,9 +516,8 @@ p = keyd->data; len = keyd->datalen; - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, - p, len, dbgbuf, sizeof dbgbuf); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "keyd no %d:\n%s", keyd->recno, dbgbuf); + sc_log(ctx, "keyd no %d", keyd->recno); + sc_debug_hex(ctx, SC_LOG_DEBUG_NORMAL, "", p, len); tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); if (!tag || taglen != 4 || @@ -541,7 +540,7 @@ continue; return *tag; /* found. */ } - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "EF_keyD for %04hx not found\n", fid); + sc_log(ctx, "EF_keyD for %04hx not found\n", fid); return -1; } @@ -560,7 +559,7 @@ /* Currently we support only the short for. */ if (buflen != 1) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "can't handle long ARRs\n"); + sc_log(ctx, "can't handle long ARRs\n"); return; } @@ -568,13 +567,12 @@ for (rule = dfi ? dfi->rule_file : NULL; rule && rule->recno != *buf; rule = rule->next) ; if (!rule) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "referenced EF_rule record %d not found\n", *buf); + sc_log(ctx, "referenced EF_rule record %d not found\n", *buf); return; } - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, - rule->data, rule->datalen, dbgbuf, sizeof dbgbuf); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_hex_dump(rule->data, rule->datalen, dbgbuf, sizeof dbgbuf); + sc_log(ctx, "rule for record %d:\n%s", *buf, dbgbuf); p = rule->data; @@ -582,8 +580,8 @@ skip = 1; /* Skip over initial unknown SC DOs. */ for (;;) { buf = p; - if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != - SC_SUCCESS) + if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS + || p == NULL) break; left -= (p - buf); tag |= cla; @@ -591,11 +589,11 @@ if (tag == 0x80 && taglen != 1) { skip = 1; } else if (tag == 0x80) { /* AM byte. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " AM_DO: %02x\n", *p); + sc_log(ctx, " AM_DO: %02x\n", *p); skip = 0; } else if (tag >= 0x81 && tag <= 0x8f) { /* Cmd description */ - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, p, taglen, dbgbuf, sizeof dbgbuf); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " AM_DO: cmd[%s%s%s%s] %s", + sc_hex_dump(p, taglen, dbgbuf, sizeof dbgbuf); + sc_log(ctx, " AM_DO: cmd[%s%s%s%s] %s", (tag & 8) ? "C" : "", (tag & 4) ? "I" : "", (tag & 2) ? "1" : "", @@ -604,33 +602,32 @@ } else if (tag == 0x9C) { /* Proprietary state machine descrip. */ skip = 1; } else if (!skip) { - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, p, taglen, dbgbuf, sizeof dbgbuf); switch (tag) { case 0x90: /* Always */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: always\n"); + sc_log(ctx, " SC: always\n"); break; case 0x97: /* Never */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: never\n"); + sc_log(ctx, " SC: never\n"); break; case 0xA4: /* Authentication, value is a CRT. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: auth %s", dbgbuf); + sc_log_hex(ctx, " SC: auth", p, taglen); break; case 0xB4: case 0xB6: case 0xB8: /* Cmd or resp with SM, value is a CRT. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: cmd/resp %s", dbgbuf); + sc_log_hex(ctx, " SC: cmd/resp", p, taglen); break; case 0x9E: /* Security Condition byte. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: condition %s", dbgbuf); + sc_log_hex(ctx, " SC: condition", p, taglen); break; case 0xA0: /* OR template. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: OR\n"); + sc_log(ctx, " SC: OR\n"); break; case 0xAF: /* AND template. */ - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " SC: AND\n"); + sc_log(ctx, " SC: AND\n"); break; } } @@ -648,13 +645,13 @@ const u8 *tag = NULL, *p = buf; int bad_fde = 0; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "processing FCI bytes\n"); + sc_log(ctx, "processing FCI bytes\n"); /* File identifier. */ tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); if (tag != NULL && taglen == 2) { file->id = (tag[0] << 8) | tag[1]; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " file identifier: 0x%02X%02X\n", tag[0], tag[1]); } /* Number of data bytes in the file including structural information. */ @@ -669,7 +666,7 @@ } if (tag != NULL && taglen >= 2) { int bytes = (tag[0] << 8) + tag[1]; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " bytes in file: %d\n", bytes); file->size = bytes; } @@ -677,7 +674,7 @@ tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen); if (tag != NULL && taglen >= 2) { int bytes = (tag[0] << 8) + tag[1]; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " bytes in file: %d\n", bytes); file->size = bytes; } @@ -692,7 +689,7 @@ const char *type; file->shareable = byte & 0x40 ? 1 : 0; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " shareable: %s\n", (byte & 0x40) ? "yes" : "no"); file->ef_structure = byte & 0x07; @@ -713,9 +710,9 @@ type = "unknown"; break; } - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " type: %s\n", type); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + sc_log(ctx, " EF structure: %d\n", byte & 0x07); } } @@ -737,7 +734,7 @@ name[i] = '?'; } name[taglen] = 0; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " file name: %s\n", name); + sc_log(ctx, " file name: %s\n", name); } /* Proprietary information. */ @@ -853,7 +850,7 @@ unsigned int len; int r; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "select_part (0x%04X, kind=%u)\n", fid, kind); if (fid == MFID) { @@ -928,7 +925,8 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - assert(!priv->curpathlen || priv->curpath[0] == MFID); + if (!(!priv->curpathlen || priv->curpath[0] == MFID)) + return SC_ERROR_INTERNAL; if (pathlen && *pathptr == 0x3FFF) { pathlen--; @@ -969,7 +967,8 @@ /* This EF or DF was already selected, but we need to get the FCI, so we have to select again. */ - assert(priv->curpathlen > 1); + if (!(priv->curpathlen > 1)) + return SC_ERROR_INTERNAL; priv->curpathlen--; priv->is_ef = 0; r = select_down(card, pathptr + pathlen - 1, 1, @@ -994,7 +993,8 @@ priv->is_ef = 0; } if (priv->is_ef) { - assert(priv->curpathlen > 1); + if(!(priv->curpathlen > 1)) + return SC_ERROR_INTERNAL; priv->curpathlen--; priv->is_ef = 0; } @@ -1012,7 +1012,8 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - assert(!priv->curpathlen || priv->curpath[0] == MFID); + if (!(!priv->curpathlen || priv->curpath[0] == MFID)) + return SC_ERROR_INTERNAL; if (pathlen > 1) return SC_ERROR_INVALID_ARGUMENTS; @@ -1028,7 +1029,8 @@ /* There is no current file. */ r = SC_ERROR_INTERNAL; } else { - assert(priv->curpathlen > 1); + if (!(priv->curpathlen > 1)) + return SC_ERROR_INTERNAL; priv->curpathlen--; priv->is_ef = 0; r = select_down(card, pathptr, 1, 0, file); @@ -1053,7 +1055,8 @@ priv->is_ef = 0; } if (priv->is_ef) { - assert(priv->curpathlen > 1); + if (!(priv->curpathlen > 1)) + return SC_ERROR_INTERNAL; priv->curpathlen--; priv->is_ef = 0; } @@ -1084,7 +1087,7 @@ linep += 4; } strcpy(linep, "\n"); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s", line); + sc_log(card->ctx, "%s", line); } if (path->type == SC_PATH_TYPE_DF_NAME) { @@ -1147,7 +1150,7 @@ linep += 4; } strcpy(linep, "\n"); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s", line); + sc_log(card->ctx, "%s", line); } return r; } @@ -1166,7 +1169,7 @@ /* It seems that MICARDO does not fully comply with ISO, so I use - values gathered from peeking actual signing opeations using a + values gathered from peeking actual signing operations using a different system. It has been generalized [?] and modified by information coming from openpgp card implementation, EstEID 'manual' and some other sources. -mp @@ -1174,21 +1177,23 @@ static int mcrd_set_security_env(sc_card_t * card, const sc_security_env_t * env, int se_num) { - struct mcrd_priv_data *priv = DRVDATA(card); + struct mcrd_priv_data *priv; sc_apdu_t apdu; sc_path_t tmppath; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; int r, locked = 0; - assert(card != NULL && env != NULL); + if (!(card != NULL && env != NULL)) + return SC_ERROR_INTERNAL; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); + priv = DRVDATA(card); /* special environment handling for esteid, stolen from openpgp */ if (is_esteid_card(card)) { /* some sanity checks */ if (env->flags & SC_SEC_ENV_ALG_PRESENT) { - if (env->algorithm != SC_ALGORITHM_RSA) + if (env->algorithm != SC_ALGORITHM_RSA && env->algorithm != SC_ALGORITHM_EC) return SC_ERROR_INVALID_ARGUMENTS; } if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) @@ -1204,8 +1209,9 @@ select_esteid_df(card); switch (env->operation) { case SC_SEC_OPERATION_DECIPHER: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Using keyref %d to dechiper\n", + case SC_SEC_OPERATION_DERIVE: + sc_log(card->ctx, + "Using keyref %d to decipher\n", env->key_ref[0]); mcrd_restore_se(card, 6); mcrd_delete_ref_to_authkey(card); @@ -1213,7 +1219,7 @@ mcrd_set_decipher_key_ref(card, env->key_ref[0]); break; case SC_SEC_OPERATION_SIGN: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Using keyref %d to sign\n", + sc_log(card->ctx, "Using keyref %d to sign\n", env->key_ref[0]); mcrd_restore_se(card, 1); break; @@ -1224,9 +1230,7 @@ return 0; } - if (card->type == SC_CARD_TYPE_MCRD_DTRUST - || card->type == SC_CARD_TYPE_MCRD_GENERIC) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Using SC_CARD_TYPE_MCRD_DTRUST\n"); + if (card->type == SC_CARD_TYPE_MCRD_GENERIC) { /* some sanity checks */ if (env->flags & SC_SEC_ENV_ALG_PRESENT) { if (env->algorithm != SC_ALGORITHM_RSA) @@ -1238,15 +1242,15 @@ switch (env->operation) { case SC_SEC_OPERATION_DECIPHER: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Using keyref %d to dechiper\n", + sc_log(card->ctx, + "Using keyref %d to decipher\n", env->key_ref[0]); mcrd_delete_ref_to_authkey(card); mcrd_delete_ref_to_signkey(card); mcrd_set_decipher_key_ref(card, env->key_ref[0]); break; case SC_SEC_OPERATION_SIGN: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Using keyref %d to sign\n", + sc_log(card->ctx, "Using keyref %d to sign\n", env->key_ref[0]); break; default: @@ -1274,8 +1278,7 @@ *p++ = 0x03; *p++ = 0x80; - if (card->type == SC_CARD_TYPE_MCRD_DTRUST - || card->type == SC_CARD_TYPE_MCRD_GENERIC) { + if (card->type == SC_CARD_TYPE_MCRD_GENERIC) { unsigned char fid; fid = env->key_ref[0]; @@ -1293,7 +1296,7 @@ fid |= env->file_ref.value[env->file_ref.len - 1]; num = get_se_num_from_keyd(card, fid, p); if (num != -1) { - /* Need to restore the security environmnet. */ + /* Need to restore the security environment. */ if (num) { r = mcrd_restore_se(card, num); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, @@ -1319,13 +1322,13 @@ if (apdu.datalen != 0) { r = sc_transmit_apdu(card, &apdu); if (r) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "%s: APDU transmit failed", sc_strerror(r)); goto err; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "%s: Card returned error", sc_strerror(r)); goto err; } @@ -1347,18 +1350,21 @@ u8 * out, size_t outlen) { struct mcrd_priv_data *priv = DRVDATA(card); - sc_security_env_t *env = &priv->sec_env; + sc_security_env_t *env = NULL; int r; sc_apdu_t apdu; - assert(card != NULL && data != NULL && out != NULL); + if (data == NULL || out == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + env = &priv->sec_env; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); if (env->operation != SC_SEC_OPERATION_SIGN) return SC_ERROR_INVALID_ARGUMENTS; if (datalen > 255) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + sc_log(card->ctx, "Will compute signature (%d) for %"SC_FORMAT_LEN_SIZE_T"u (0x%02"SC_FORMAT_LEN_SIZE_T"x) bytes using key %d algorithm %d flags %d\n", env->operation, datalen, datalen, env->key_ref[0], env->algorithm, env->algorithm_flags); @@ -1375,7 +1381,7 @@ apdu.lc = datalen; apdu.data = data; apdu.datalen = datalen; - apdu.le = 0x80; + apdu.le = MIN(0x80u, outlen); apdu.resp = out; apdu.resplen = outlen; @@ -1387,6 +1393,62 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen); } +static int mcrd_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) +{ + sc_security_env_t *env = NULL; + int r = 0; + size_t sbuf_len = 0; + sc_apdu_t apdu; + u8 *sbuf = NULL; + struct sc_asn1_entry asn1_control[2], asn1_ephermal[2], asn1_public[2]; + + if (card == NULL || crgram == NULL || out == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + env = &DRVDATA(card)->sec_env; + + LOG_FUNC_CALLED(card->ctx); + if (env->operation != SC_SEC_OPERATION_DERIVE) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, iso_ops->decipher(card, crgram, crgram_len, out, outlen)); + if (crgram_len > 255) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Will derive (%d) for %"SC_FORMAT_LEN_SIZE_T"u (0x%02"SC_FORMAT_LEN_SIZE_T"x) bytes using key %d algorithm %d flags %d\n", + env->operation, crgram_len, crgram_len, env->key_ref[0], + env->algorithm, env->algorithm_flags); + + // Encode TLV + sc_copy_asn1_entry(c_asn1_control, asn1_control); + sc_copy_asn1_entry(c_asn1_ephermal, asn1_ephermal); + sc_copy_asn1_entry(c_asn1_public, asn1_public); + sc_format_asn1_entry(asn1_public + 0, (void*)crgram, &crgram_len, 1); + sc_format_asn1_entry(asn1_ephermal + 0, &asn1_public, NULL, 1); + sc_format_asn1_entry(asn1_control + 0, &asn1_ephermal, NULL, 1); + r = sc_asn1_encode(card->ctx, asn1_control, &sbuf, &sbuf_len); + LOG_TEST_RET(card->ctx, r, "Error encoding TLV."); + + // Create APDU + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86); + apdu.lc = sbuf_len; + apdu.data = sbuf; + apdu.datalen = sbuf_len; + apdu.le = MIN(0x80u, outlen); + apdu.resp = out; + apdu.resplen = outlen; + + r = sc_transmit_apdu(card, &apdu); + sc_mem_clear(sbuf, sbuf_len); + free(sbuf); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen); +} + /* added by -mp, to give pin information in the card driver (pkcs15emu->driver needed) */ static int mcrd_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data, int *tries_left) @@ -1427,9 +1489,8 @@ return SC_SUCCESS; } - if (card->type == SC_CARD_TYPE_MCRD_DTRUST - || card->type == SC_CARD_TYPE_MCRD_GENERIC) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "modify pin reference for D-Trust\n"); + if (card->type == SC_CARD_TYPE_MCRD_GENERIC) { + sc_log(card->ctx, "modify pin reference for D-Trust\n"); if (data->pin_reference == 0x02) data->pin_reference = data->pin_reference | 0x80; } @@ -1450,6 +1511,7 @@ mcrd_ops.select_file = mcrd_select_file; mcrd_ops.set_security_env = mcrd_set_security_env; mcrd_ops.compute_signature = mcrd_compute_signature; + mcrd_ops.decipher = mcrd_decipher; mcrd_ops.pin_cmd = mcrd_pin_cmd; return &mcrd_drv; diff -Nru opensc-0.17.0/src/libopensc/card-miocos.c opensc-0.19.0/src/libopensc/card-miocos.c --- opensc-0.17.0/src/libopensc/card-miocos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-miocos.c 2018-09-13 11:47:21.000000000 +0000 @@ -29,7 +29,7 @@ #include "asn1.h" #include "cardctl.h" -static struct sc_atr_table miocos_atrs[] = { +static const struct sc_atr_table miocos_atrs[] = { /* Test card with 32 kB memory */ { "3B:9D:94:40:23:00:68:10:11:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL }, /* Test card with 64 kB memory */ diff -Nru opensc-0.17.0/src/libopensc/card-muscle.c opensc-0.19.0/src/libopensc/card-muscle.c --- opensc-0.17.0/src/libopensc/card-muscle.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-muscle.c 2018-09-13 11:47:21.000000000 +0000 @@ -42,7 +42,7 @@ NULL, 0, NULL }; -static struct sc_atr_table muscle_atrs[] = { +static const struct sc_atr_table muscle_atrs[] = { /* Tyfone JCOP 242R2 cards */ { "3b:6d:00:00:ff:54:79:66:6f:6e:65:20:32:34:32:52:32", NULL, NULL, SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU, 0, NULL }, /* Aladdin eToken PRO USB 72K Java */ @@ -94,9 +94,11 @@ apdu.resp = response; r = sc_transmit_apdu(card, &apdu); if (r == SC_SUCCESS && response[0] == 0x01) { - card->type = SC_CARD_TYPE_MUSCLE_V1; - return 1; + card->type = SC_CARD_TYPE_MUSCLE_V1; + } else { + card->type = SC_CARD_TYPE_MUSCLE_GENERIC; } + return 1; } return 0; } @@ -241,7 +243,7 @@ if(buffer == NULL) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); r = msc_read_object(card, objectId, 0, buffer, file->size); - /* TODO: RETREIVE ACLS */ + /* TODO: RETRIEVE ACLS */ if(r < 0) goto update_bin_free_buffer; r = msc_delete_object(card, objectId, 0); if(r < 0) goto update_bin_free_buffer; @@ -476,18 +478,17 @@ card->caps |= SC_CARD_CAP_RNG; /* Card type detection */ - if (_sc_match_atr(card, muscle_atrs, &card->type) < 0) { - free(priv->fs); - free(card->drv_data); - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED); - } - + _sc_match_atr(card, muscle_atrs, &card->type); if(card->type == SC_CARD_TYPE_MUSCLE_ETOKEN_72K) { card->caps |= SC_CARD_CAP_APDU_EXT; } if(card->type == SC_CARD_TYPE_MUSCLE_JCOP241) { card->caps |= SC_CARD_CAP_APDU_EXT; } + if (!(card->caps & SC_CARD_CAP_APDU_EXT)) { + card->max_recv_size = 255; + card->max_send_size = 255; + } if(card->type == SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU) { /* Tyfone JCOP v242R2 card that doesn't support extended APDUs */ } @@ -517,7 +518,9 @@ mscfs_check_cache(priv->fs); for(x = 0; x < fs->cache.size; x++) { - u8* oid= fs->cache.array[x].objectId.id; + u8* oid = fs->cache.array[x].objectId.id; + if (bufLen < 2) + break; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "FILE: %02X%02X%02X%02X\n", oid[0],oid[1],oid[2],oid[3]); @@ -526,7 +529,8 @@ buf[1] = oid[3]; if(buf[0] == 0x00 && buf[1] == 0x00) continue; /* No directories/null names outside of root */ buf += 2; - count+=2; + count += 2; + bufLen -= 2; } } return count; @@ -602,7 +606,7 @@ static int muscle_card_extract_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info) { - /* CURRENTLY DONT SUPPOT EXTRACTING PRIVATE KEYS... */ + /* CURRENTLY DONT SUPPORT EXTRACTING PRIVATE KEYS... */ switch(info->keyType) { case 1: /* RSA */ return msc_extract_rsa_public_key(card, @@ -618,7 +622,7 @@ static int muscle_card_import_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info) { - /* CURRENTLY DONT SUPPOT EXTRACTING PRIVATE KEYS... */ + /* CURRENTLY DONT SUPPORT EXTRACTING PRIVATE KEYS... */ switch(info->keyType) { case 0x02: /* RSA_PRIVATE */ case 0x03: /* RSA_PRIVATE_CRT */ @@ -721,7 +725,7 @@ u8 key_id; int r; - /* saniti check */ + /* sanity check */ if (priv->env.operation != SC_SEC_OPERATION_DECIPHER) return SC_ERROR_INVALID_ARGUMENTS; @@ -774,8 +778,12 @@ { if (len == 0) return SC_SUCCESS; - else - return msc_get_challenge(card, len, 0, NULL, rnd); + else { + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, + msc_get_challenge(card, len, 0, NULL, rnd), + "GET CHALLENGE cmd failed"); + return (int) len; + } } static int muscle_check_sw(sc_card_t * card, unsigned int sw1, unsigned int sw2) { @@ -810,6 +818,21 @@ return iso_ops->check_sw(card, sw1, sw2); } +static int muscle_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (was_reset > 0) { + if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) != 1) { + r = SC_ERROR_INVALID_CARD; + } + } + + LOG_FUNC_RETURN(card->ctx, r); +} + static struct sc_card_driver * sc_get_driver(void) { @@ -837,6 +860,7 @@ muscle_ops.select_file = muscle_select_file; muscle_ops.delete_file = muscle_delete_file; muscle_ops.list_files = muscle_list_files; + muscle_ops.card_reader_lock_obtained = muscle_card_reader_lock_obtained; return &muscle_drv; } diff -Nru opensc-0.17.0/src/libopensc/card-myeid.c opensc-0.19.0/src/libopensc/card-myeid.c --- opensc-0.17.0/src/libopensc/card-myeid.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-myeid.c 2018-09-13 11:47:21.000000000 +0000 @@ -149,7 +149,6 @@ myeid_private_data_t *priv; u8 appletInfo[20]; size_t appletInfoLen; - int r; myeid_card_caps_t card_caps; LOG_FUNC_CALLED(card->ctx); @@ -168,9 +167,8 @@ appletInfoLen = 20; - r = myeid_get_info(card, appletInfo, appletInfoLen); - - LOG_TEST_RET(card->ctx, r, "Failed to get MyEID applet information."); + if (0 > myeid_get_info(card, appletInfo, appletInfoLen)) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Failed to get MyEID applet information."); priv->change_counter = appletInfo[19] | appletInfo[18] << 8; @@ -190,10 +188,8 @@ if (card->version.fw_major >= 40) { /* Since 4.0, we can query available algorithms and key sizes. * Since 3.5.0 RSA up to 2048 and ECC up to 256 are always supported, so we check only max ECC key length. */ - r = myeid_get_card_caps(card, &card_caps); - - if (r != SC_SUCCESS) { - sc_log(card->ctx, "Failed to get card capabilities. Using default max ECC key length 256."); + if (myeid_get_card_caps(card, &card_caps) != SC_SUCCESS) { + sc_log(card->ctx, "Failed to get card capabilities. Using default max ECC key length 256."); } } @@ -614,9 +610,9 @@ assert(card != NULL && env != NULL); LOG_FUNC_CALLED(card->ctx); - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) { - sc_log(card->ctx, "asymmetric keyref not supported.\n"); + sc_log(card->ctx, "symmetric keyref not supported.\n"); return SC_ERROR_NOT_SUPPORTED; } if (se_num > 0) @@ -697,9 +693,9 @@ assert(card != NULL && env != NULL); LOG_FUNC_CALLED(card->ctx); - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) { - sc_log(card->ctx, "asymmetric keyref not supported."); + sc_log(card->ctx, "symmetric keyref not supported."); return SC_ERROR_NOT_SUPPORTED; } if (se_num > 0) @@ -881,7 +877,74 @@ free(buf); return buflen; } +/* + MyEID does not support RAW RSA signature for 2048 bit key. + (Source: MyEID reference manual 2.1.4) + + This function uses decipher operation for calculating RAW 2048 bit signature. +*/ +static int +myeid_compute_raw_2048_signature(struct sc_card *card, const u8 * data, size_t datalen, + u8 * out, size_t outlen) +{ + int r; + struct sc_context *ctx; + struct myeid_private_data *priv; + struct sc_apdu apdu; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + sc_security_env_t env; + + ctx = card->ctx; + LOG_FUNC_CALLED(ctx); + priv = (myeid_private_data_t *) card->drv_data; + +/* security env change - use DECIPHER operation */ + memcpy(&env, priv->sec_env, sizeof(sc_security_env_t)); + env.flags |= SC_SEC_ENV_ALG_REF_PRESENT; + env.flags |= SC_SEC_ENV_FILE_REF_PRESENT; + env.flags |= SC_SEC_ENV_KEY_REF_PRESENT; + env.operation = SC_SEC_OPERATION_DECIPHER; + myeid_set_security_env_rsa(card, &env, 0); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 0; /* there is no response to 1st part of data */ + +/* prepare 1st part of data */ + sbuf[0] = 0x81; + memcpy(sbuf + 1, data, datalen / 2); + apdu.lc = datalen / 2 + 1; + apdu.datalen = apdu.lc; + apdu.data = sbuf; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { +/* prepare 2nd part of data */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = datalen; + sbuf[0] = 0x82; + memcpy(sbuf + 1, data + datalen / 2, datalen / 2); + apdu.lc = datalen / 2 + 1; + apdu.datalen = apdu.lc; + apdu.data = sbuf; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { + int len = apdu.resplen > outlen ? outlen : apdu.resplen; + memcpy(out, apdu.resp, len); + LOG_FUNC_RETURN(card->ctx, len); + } + } + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); +} static int myeid_compute_signature(struct sc_card *card, const u8 * data, size_t datalen, @@ -919,6 +982,9 @@ if ((datalen + pad_chars) > 256) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + if (datalen == 256 && priv->sec_env->algorithm == SC_ALGORITHM_RSA) + return myeid_compute_raw_2048_signature(card, data, datalen, out, outlen); + /* INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x9E Resp: Digital Signature * P2: 0x9A Cmd: Input for Digital Signature */ @@ -926,17 +992,9 @@ apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; - if (datalen == 256) { - apdu.p2 = data[0]; - memcpy(sbuf, data+1, datalen-1); - apdu.lc = datalen - 1; - apdu.datalen = datalen - 1; - } - else { - memcpy(sbuf + pad_chars, data, datalen); - apdu.lc = datalen + pad_chars; - apdu.datalen = datalen + pad_chars; - } + memcpy(sbuf + pad_chars, data, datalen); + apdu.lc = datalen + pad_chars; + apdu.datalen = datalen + pad_chars; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); @@ -1209,7 +1267,6 @@ if(mode == LOAD_KEY_MODULUS && value_len >= 256) { - r=0; if((value_len % 2) > 0 && value[0] == 0x00) { value_len--; diff -Nru opensc-0.17.0/src/libopensc/card-npa.c opensc-0.19.0/src/libopensc/card-npa.c --- opensc-0.17.0/src/libopensc/card-npa.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-npa.c 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,7 @@ /* * card-npa.c: Recognize known German identity cards * - * Copyright (C) 2011-2015 Frank Morgner + * Copyright (C) 2011-2018 Frank Morgner * * This file is part of OpenSC. * @@ -65,22 +65,6 @@ } } -static struct sc_atr_table npa_atrs[] = { - {"3B:8A:80:01:80:31:F8:73:F7:41:E0:82:90:00:75", - "FF:FF:FF:FF:FF:FF:00:FF:00:00:FF:FF:FF:FF:00", - "German ID card (neuer Personalausweis, nPA)", SC_CARD_TYPE_NPA, 0, NULL}, - {"3B:88:80:01:00:00:00:00:00:00:00:00:09", NULL, - "German ID card (neuer Personalausweis, nPA)", SC_CARD_TYPE_NPA, 0, NULL}, - {"3B:87:80:01:80:31:B8:73:84:01:E0:19", NULL, - "German ID card (neuer Personalausweis, nPA)", SC_CARD_TYPE_NPA, 0, NULL}, - {"3B:84:80:01:00:00:90:00:95", NULL, - "German ID card (Test neuer Personalausweis)", SC_CARD_TYPE_NPA_TEST, 0, NULL}, - {"3B:88:80:01:00:E1:F3:5E:13:77:83:00:00", - "FF:FF:FF:FF:00:FF:FF:FF:FF:FF:FF:FF:00", - "German ID card (Test Online-Ausweisfunktion)", SC_CARD_TYPE_NPA_ONLINE, 0, NULL}, - {NULL, NULL, NULL, 0, 0, NULL} -}; - static struct sc_card_operations npa_ops; static struct sc_card_driver npa_drv = { "German ID card (neuer Personalausweis, nPA)", @@ -149,9 +133,45 @@ static int npa_match_card(sc_card_t * card) { - if (_sc_match_atr(card, npa_atrs, &card->type) < 0) - return 0; - return 1; + int r = 0; + + if (0 == r && SC_SUCCESS == sc_enum_apps(card)) { + unsigned char esign_aid_0[] = { + 0xE8, 0x28, 0xBD, 0x08, 0x0F, 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E, + }, esign_aid_1[] = { + 0xa0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01, + }, esign_aid_2[] = { + 0xe8, 0x07, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x02, + }, esign_aid_3[] = { + 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E, + }; + int i, found_0 = 0, found_1 = 0, found_2 = 0, found_3 = 0; + for (i = 0; i < card->app_count; i++) { + struct sc_app_info *app_info = card->app[i]; + if (sizeof esign_aid_0 == app_info->aid.len + && 0 == memcmp(esign_aid_0, app_info->aid.value, + sizeof esign_aid_0)) + found_0 = 1; + if (sizeof esign_aid_1 == app_info->aid.len + && 0 == memcmp(esign_aid_1, app_info->aid.value, + sizeof esign_aid_1)) + found_1 = 1; + if (sizeof esign_aid_2 == app_info->aid.len + && 0 == memcmp(esign_aid_2, app_info->aid.value, + sizeof esign_aid_2)) + found_2 = 1; + if (sizeof esign_aid_3 == app_info->aid.len + && 0 == memcmp(esign_aid_3, app_info->aid.value, + sizeof esign_aid_3)) + found_3 = 1; + } + if (found_0 && found_1 && found_2 && found_3) { + card->type = SC_CARD_TYPE_NPA; + r = 1; + } + } + + return r; } static void npa_get_cached_pace_params(sc_card_t *card, @@ -291,11 +311,11 @@ } /* FIXME set flags with opensc.conf */ - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_ALL; - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_TA; - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_CA; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_ALL; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_TA; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_CA; - /* FIXME show an alert to the user if can == NULL */ + /* FIXME show an alert to the user if CAN is NULL */ r = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02); if (SC_SUCCESS != r) { sc_log(card->ctx, "Error verifying CAN.\n"); @@ -313,7 +333,7 @@ } r = perform_chip_authentication(card, &ef_cardsecurity, &ef_cardsecurity_len); if ( SC_SUCCESS != r) { - sc_log(card->ctx, "Error verifying the chips authenticy.\n"); + sc_log(card->ctx, "Error verifying the chip's authenticity.\n"); } sc_log(card->ctx, "Proved Access rights to eSign application with configured key as ST.\n"); @@ -331,6 +351,15 @@ return r; } +static int npa_finish(sc_card_t * card) +{ + sc_sm_stop(card); + npa_drv_data_free(card->drv_data); + card->drv_data = NULL; + + return SC_SUCCESS; +} + static int npa_init(sc_card_t * card) { int flags = SC_ALGORITHM_ECDSA_RAW; @@ -343,7 +372,7 @@ } card->caps |= SC_CARD_CAP_APDU_EXT | SC_CARD_CAP_RNG; - /* 1520 bytes is the minimum lenght of the communication buffer in all + /* 1520 bytes is the minimum length of the communication buffer in all * Chip/OS variants */ card->max_recv_size = 1520; card->max_send_size = 1520; @@ -367,11 +396,9 @@ if (r != SC_SUCCESS) goto err; -#ifdef ENABLE_OPENPACE - EAC_init(); -#endif card->drv_data = npa_drv_data_create(); if (!card->drv_data) { + npa_finish(card); r = SC_ERROR_OUT_OF_MEMORY; goto err; } @@ -381,25 +408,14 @@ /* unlock the eSign application for reading the certificates * by the PKCS#15 layer (i.e. sc_pkcs15_bind_internal) */ - if (SC_SUCCESS != npa_unlock_esign(card)) - sc_log(card->ctx, "Propably not all functionality will be available.\n"); + if (SC_SUCCESS != npa_unlock_esign(card)) { + sc_log(card->ctx, "Probably not all functionality will be available.\n"); + } err: return r; } -static int npa_finish(sc_card_t * card) -{ - sc_sm_stop(card); - npa_drv_data_free(card->drv_data); - card->drv_data = NULL; -#ifdef ENABLE_OPENPACE - EAC_cleanup(); -#endif - - return SC_SUCCESS; -} - static int npa_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) { @@ -451,7 +467,7 @@ /* usually 10 tries */ *tries_left = 10; data->pin1.max_tries = 10; - r = npa_pace_get_tries_left(card, + r = eac_pace_get_tries_left(card, pin_reference, tries_left); data->pin1.tries_left = *tries_left; break; @@ -460,7 +476,7 @@ /* usually 3 tries */ *tries_left = 3; data->pin1.max_tries = 3; - r = npa_pace_get_tries_left(card, + r = eac_pace_get_tries_left(card, pin_reference, tries_left); data->pin1.tries_left = *tries_left; break; @@ -511,10 +527,10 @@ && r != SC_SUCCESS && pace_output.mse_set_at_sw1 == 0x63 && (pace_output.mse_set_at_sw2 & 0xc0) == 0xc0 - && (pace_output.mse_set_at_sw2 & 0x0f) <= UC_PIN_SUSPENDED) { + && (pace_output.mse_set_at_sw2 & 0x0f) <= EAC_UC_PIN_SUSPENDED) { /* TODO ask for user consent when automatically resuming the PIN */ sc_log(card->ctx, "%s is suspended. Will try to resume it with %s.\n", - npa_secret_name(pin_reference), npa_secret_name(PACE_PIN_ID_CAN)); + eac_secret_name(pin_reference), eac_secret_name(PACE_PIN_ID_CAN)); pace_input.pin_id = PACE_PIN_ID_CAN; pace_input.pin = NULL; @@ -532,9 +548,9 @@ r = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02); if (r == SC_SUCCESS) { - sc_log(card->ctx, "%s resumed.\n", npa_secret_name(pin_reference)); + sc_log(card->ctx, "%s resumed.\n", eac_secret_name(pin_reference)); if (tries_left) { - *tries_left = MAX_PIN_TRIES; + *tries_left = EAC_MAX_PIN_TRIES; } } else { if (tries_left) { @@ -552,10 +568,10 @@ if (pin_reference == PACE_PIN_ID_PIN && tries_left) { if (*tries_left == 0) { sc_log(card->ctx, "%s is suspended and must be resumed.\n", - npa_secret_name(pin_reference)); + eac_secret_name(pin_reference)); } else if (*tries_left == 1) { sc_log(card->ctx, "%s is blocked and must be unblocked.\n", - npa_secret_name(pin_reference)); + eac_secret_name(pin_reference)); } } @@ -586,6 +602,79 @@ return r; } +#ifdef ENABLE_OPENSSL +#include +#endif + +int +npa_reset_retry_counter(sc_card_t *card, enum s_type pin_id, + int ask_for_secret, const char *new, size_t new_len) +{ + sc_apdu_t apdu; + char *p = NULL; + int r; + + if (ask_for_secret && (!new || !new_len)) { + if (!(SC_READER_CAP_PIN_PAD & card->reader->capabilities)) { +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + p = malloc(EAC_MAX_PIN_LEN+1); + if (!p) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for new PIN.\n"); + return SC_ERROR_OUT_OF_MEMORY; + } + if (0 > EVP_read_pw_string_min(p, + EAC_MIN_PIN_LEN, EAC_MAX_PIN_LEN+1, + "Please enter your new PIN: ", 0)) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read new PIN.\n"); + free(p); + return SC_ERROR_INTERNAL; + } + new_len = strlen(p); + if (new_len > EAC_MAX_PIN_LEN) + return SC_ERROR_INVALID_PIN_LENGTH; + new = p; +#else + return SC_ERROR_NOT_SUPPORTED; +#endif + } + } + + sc_format_apdu(card, &apdu, 0, 0x2C, 0, pin_id); + apdu.data = (u8 *) new; + apdu.datalen = new_len; + apdu.lc = apdu.datalen; + + if (new_len || ask_for_secret) { + apdu.p1 = 0x02; + apdu.cse = SC_APDU_CASE_3_SHORT; + } else { + apdu.p1 = 0x03; + apdu.cse = SC_APDU_CASE_1; + } + + if (ask_for_secret && !new_len) { + struct sc_pin_cmd_data data; + data.apdu = &apdu; + data.cmd = SC_PIN_CMD_CHANGE; + data.flags = SC_PIN_CMD_IMPLICIT_CHANGE; + data.pin2.encoding = SC_PIN_ENCODING_ASCII; + data.pin2.length_offset = 0; + data.pin2.offset = 5; + data.pin2.max_length = EAC_MAX_PIN_LEN; + data.pin2.min_length = EAC_MIN_PIN_LEN; + data.pin2.pad_length = 0; + r = card->reader->ops->perform_verify(card->reader, &data); + } else + r = sc_transmit_apdu(card, &apdu); + + if (p) { + sc_mem_clear(p, new_len); + free(p); + } + + return r; +} + static int npa_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left) { @@ -684,7 +773,7 @@ if (card->reader->capabilities & SC_READER_CAP_PACE_GENERIC) { /* If PACE is done between reader and card, SM is transparent to us as - * it ends at the reader. With CLA=0x0C we provoque a SM error to + * it ends at the reader. With CLA=0x0C we provoke a SM error to * disable SM on the reader. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xA4, 0x00, 0x00); apdu.cla = 0x0C; diff -Nru opensc-0.17.0/src/libopensc/card-npa.h opensc-0.19.0/src/libopensc/card-npa.h --- opensc-0.17.0/src/libopensc/card-npa.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-npa.h 2018-09-13 11:47:21.000000000 +0000 @@ -25,6 +25,8 @@ extern "C" { #endif +#include "sm/sm-eac.h" + const unsigned char esign_chat[] = { 0x7F, 0x4C, 0x0E, 0x06, 0x09, 0x04, 0x00, 0x7F, 0x00, 0x07, 0x03, 0x01, 0x02, 0x03, @@ -33,6 +35,43 @@ const unsigned char df_esign_aid[] = { 0xa0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4e}; +/** + * @brief Sends a reset retry counter APDU + * + * According to TR-03110 the reset retry counter APDU is used to set a new PIN + * or to reset the retry counter of the PIN. The standard requires this + * operation to be authorized either by an established PACE channel or by the + * effective authorization of the terminal's certificate. + * + * @param[in] card + * @param[in] pin_id Type of secret (usually PIN or CAN). You may use enum s_type from \c . + * @param[in] ask_for_secret whether to ask the user for the secret (\c 1) or not (\c 0) + * @param[in] new (optional) new secret + * @param[in] new_len (optional) length of \a new + * + * @return \c SC_SUCCESS or error code if an error occurred + */ +int npa_reset_retry_counter(sc_card_t *card, + enum s_type pin_id, int ask_for_secret, + const char *new, size_t new_len); + +/** + * @brief Send APDU to unblock the PIN + * + * @param[in] card + */ +#define npa_unblock_pin(card) \ + npa_reset_retry_counter(card, PACE_PIN, 0, NULL, 0) +/** + * @brief Send APDU to set a new PIN + * + * @param[in] card + * @param[in] newp (optional) new PIN + * @param[in] newplen (optional) length of \a new + */ +#define npa_change_pin(card, newp, newplen) \ + npa_reset_retry_counter(card, PACE_PIN, 1, newp, newplen) + #ifdef __cplusplus } #endif diff -Nru opensc-0.17.0/src/libopensc/card-oberthur.c opensc-0.19.0/src/libopensc/card-oberthur.c --- opensc-0.17.0/src/libopensc/card-oberthur.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-oberthur.c 2018-09-13 11:47:21.000000000 +0000 @@ -39,6 +39,7 @@ #include "internal.h" #include "cardctl.h" #include "pkcs15.h" +#include "gp.h" #define OBERTHUR_PIN_LOCAL 0x80 #define OBERTHUR_PIN_REFERENCE_USER 0x81 @@ -54,7 +55,7 @@ #define DES_ecb_encrypt(a,b,c,d) des_ecb_encrypt(a,b,*c,d) #endif -static struct sc_atr_table oberthur_atrs[] = { +static const struct sc_atr_table oberthur_atrs[] = { { "3B:7D:18:00:00:00:31:80:71:8E:64:77:E3:01:00:82:90:00", NULL, "Oberthur 64k v4/2.1.1", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL }, { "3B:7D:18:00:00:00:31:80:71:8E:64:77:E3:02:00:82:90:00", NULL, @@ -157,19 +158,10 @@ unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE]; struct auth_private_data *data = (struct auth_private_data *) card->drv_data; int rv, ii; - unsigned char cm[7] = {0xA0,0x00,0x00,0x00,0x03,0x00,0x00}; struct sc_path tmp_path; /* Select Card Manager (to deselect previously selected application) */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C); - apdu.lc = sizeof(cm); - /* apdu.le = sizeof(cm)+4; */ - apdu.data = cm; - apdu.datalen = sizeof(cm); - apdu.resplen = sizeof(apdu_resp); - apdu.resp = apdu_resp; - - rv = sc_transmit_apdu(card, &apdu); + rv = gp_select_card_manager(card); LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); /* Get smart card serial number */ @@ -484,6 +476,9 @@ memcpy(&path, in_path, sizeof(struct sc_path)); + if (!auth_current_df) + return SC_ERROR_OBJECT_NOT_FOUND; + sc_log(card->ctx, "in_path; type=%d, path=%s, out %p", in_path->type, sc_print_path(in_path), file_out); sc_log(card->ctx, "current path; type=%d, path=%s", @@ -1593,7 +1588,7 @@ pin_cmd.flags |= SC_PIN_CMD_NEED_PADDING; /* For Oberthur card, PIN command data length has to be 0x40. - * In PCSC10 v2.06 the uppler limit of pin.max_length is 8. + * In PCSC10 v2.06 the upper limit of pin.max_length is 8. * * The standard sc_build_pin() throws an error when 'pin.len > pin.max_length' . * So, let's build our own APDU. @@ -1775,7 +1770,7 @@ else if (!data->pin1.len && !data->pin2.len) { /* Oberthur unblock style with PIN pad. */ rv = auth_pin_change_pinpad(card, data, tries_left); - LOG_TEST_RET(card->ctx, rv, "'PIN CHANGE' failedi: SOPIN verify with pinpad failed"); + LOG_TEST_RET(card->ctx, rv, "'PIN CHANGE' failed: SOPIN verify with pinpad failed"); } else { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "'PIN CHANGE' failed"); @@ -2023,16 +2018,10 @@ struct sc_pkcs15_pubkey_rsa key; int ii, rv; size_t len = 0, der_size = 0; - char debug_buf[2048]; LOG_FUNC_CALLED(card->ctx); - debug_buf[0] = 0; - sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL, - buf, count, debug_buf, sizeof(debug_buf)); - sc_log(card->ctx, - "write_publickey in %"SC_FORMAT_LEN_SIZE_T"u bytes :\n%s", - count, debug_buf); + sc_log_hex(card->ctx, "write_publickey", buf, count); if (1+offset > sizeof(rsa_der)) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid offset value"); @@ -2121,13 +2110,16 @@ unsigned char *buf, size_t count, unsigned long flags) { int rv; - char debug_buf[2048]; struct sc_pkcs15_bignum bn[2]; unsigned char *out = NULL; bn[0].data = NULL; bn[1].data = NULL; LOG_FUNC_CALLED(card->ctx); + + if (!auth_current_ef) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid auth_current_ef"); + sc_log(card->ctx, "offset %i; size %"SC_FORMAT_LEN_SIZE_T"u; flags 0x%lX", offset, count, flags); @@ -2183,12 +2175,7 @@ rv = out_len - offset > count ? count : out_len - offset; memcpy(buf, out + offset, rv); - debug_buf[0] = 0; - sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL, - buf, rv, debug_buf, sizeof(debug_buf)); - sc_log(card->ctx, - "write_publickey in %"SC_FORMAT_LEN_SIZE_T"u bytes :\n%s", - count, debug_buf); + sc_log_hex(card->ctx, "write_publickey", buf, rv); } } else { diff -Nru opensc-0.17.0/src/libopensc/card-openpgp.c opensc-0.19.0/src/libopensc/card-openpgp.c --- opensc-0.17.0/src/libopensc/card-openpgp.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-openpgp.c 2018-09-13 11:47:21.000000000 +0000 @@ -20,11 +20,18 @@ /* * Specifications: - * http://www.g10code.de/docs/openpgp-card-1.0.pdf (obsolete) - * http://www.g10code.de/docs/openpgp-card-1.1.pdf - * http://www.g10code.de/docs/openpgp-card-2.0.pdf - * http://www.g10code.de/docs/openpgp-card-2.1.pdf (minor changes to v2.0) - * http://www.g10code.de/docs/openpgp-card-3.0.pdf (not yet supported) + * (all available from: https://gnupg.org/ftp/specs/) + * https://gnupg.org/ftp/specs/openpgp-card-1.0.pdf (obsolete) + * https://gnupg.org/ftp/specs/openpgp-card-1.1.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-2.0.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-2.1.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-2.2.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.0.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.1.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.2.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.0.pdf + * https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.1.pdf */ #if HAVE_CONFIG_H @@ -44,11 +51,22 @@ #include #endif /* ENABLE_OPENSSL */ -static struct sc_atr_table pgp_atrs[] = { - { "3b:fa:13:00:ff:81:31:80:45:00:31:c1:73:c0:01:00:00:90:00:b1", NULL, "OpenPGP card v1.0/1.1", SC_CARD_TYPE_OPENPGP_V1, 0, NULL }, - { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, "CryptoStick v1.2 (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, - { "3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4", NULL, "Gnuk v1.0.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL }, +static const char default_cardname[] = "OpenPGP card"; +static const char default_cardname_v1[] = "OpenPGP card v1.x"; +static const char default_cardname_v2[] = "OpenPGP card v2.x"; +static const char default_cardname_v3[] = "OpenPGP card v3.x"; + +static const struct sc_atr_table pgp_atrs[] = { + { "3b:fa:13:00:ff:81:31:80:45:00:31:c1:73:c0:01:00:00:90:00:b1", NULL, default_cardname_v1, SC_CARD_TYPE_OPENPGP_V1, 0, NULL }, + { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, default_cardname_v2, SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, + { + "3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4", + "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:ff:ff:00", + "Gnuk v1.0.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL + }, { "3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1", NULL, "Yubikey NEO (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, + { "3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4", NULL, "Yubikey 4 (OpenPGP v2.1)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, + { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c", NULL, default_cardname_v3, SC_CARD_TYPE_OPENPGP_V3, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -83,7 +101,11 @@ OPENPGP_CARD_1_1 = 0x0101, OPENPGP_CARD_2_0 = 0x0200, OPENPGP_CARD_2_1 = 0x0201, - OPENPGP_CARD_3_0 = 0x0300 + OPENPGP_CARD_2_2 = 0x0202, + OPENPGP_CARD_3_0 = 0x0300, + OPENPGP_CARD_3_1 = 0x0301, + OPENPGP_CARD_3_2 = 0x0302, + OPENPGP_CARD_3_3 = 0x0303, }; enum _access { /* access flags for the respective DO/file */ @@ -108,8 +130,10 @@ EXT_CAP_KEY_IMPORT = 0x0020, EXT_CAP_GET_CHALLENGE = 0x0040, EXT_CAP_SM = 0x0080, + EXT_CAP_LCS = 0x0100, EXT_CAP_CHAINING = 0x1000, - EXT_CAP_APDU_EXT = 0x2000 + EXT_CAP_APDU_EXT = 0x2000, + EXT_CAP_MSE = 0x3000 }; enum _card_state { @@ -118,6 +142,15 @@ CARD_STATE_ACTIVATED = 0x05 }; +enum _sm_algo { + SM_ALGO_NONE = 0, /* SM not supported */ + SM_ALGO_AES128 = 1, + SM_ALGO_AES256 = 2, + SM_ALGO_SCP11b = 3, + SM_ALGO_3DES = 256, /* 2.x: coded as 0 in DO C0 */ + SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */ +}; + typedef struct pgp_blob { struct pgp_blob * next; /* pointer to next sibling */ struct pgp_blob * parent; /* pointer to parent */ @@ -189,7 +222,7 @@ /* Gnuk only supports 1 key length (2048 bit) */ #define MAXLEN_RESP_PUBKEY_GNUK 271 -static struct do_info pgp1_objects[] = { /* OpenPGP card spec 1.1 */ +static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ { 0x004f, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL }, { 0x005b, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x005e, SIMPLE, READ_ALWAYS | WRITE_PIN3, sc_get_data, sc_put_data }, @@ -238,7 +271,19 @@ { 0, 0, 0, NULL, NULL }, }; -static struct do_info pgp2_objects[] = { /* OpenPGP card spec 2.0 */ +static struct do_info pgp33_objects[] = { /* OpenPGP card spec 3.3 */ + { 0x00f9, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, + /* OpenPGP card spec 3.0 - 3.2 */ + { 0x00d6, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, + { 0x00d7, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, + { 0x00d8, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, + /* DO 7F66 is CONSTRUCTED in spec; we treat it as SIMPLE: no need to parse TLV */ + { 0x7f66, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, sc_put_data }, + /* DO 7F74 is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */ + { 0x7f74, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, sc_put_data }, + /* OpenPGP card spec 2.1 & 2.2 */ + { 0x00d5, SIMPLE, READ_NEVER | WRITE_PIN3, NULL, sc_put_data }, + /* OpenPGP card spec 2.0 */ { 0x004d, CONSTRUCTED, READ_NEVER | WRITE_PIN3, NULL, sc_put_data }, { 0x004f, SIMPLE, READ_ALWAYS | WRITE_NEVER, sc_get_data, NULL }, { 0x005b, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, @@ -281,13 +326,12 @@ { 0x5f48, CONSTRUCTED, READ_NEVER | WRITE_PIN3, NULL, sc_put_data }, { 0x5f50, SIMPLE, READ_ALWAYS | WRITE_PIN3, sc_get_data, sc_put_data }, { 0x5f52, SIMPLE, READ_ALWAYS | WRITE_NEVER, sc_get_data, NULL }, - /* The 7F21 is constructed DO in spec, but in practice, its content can be retrieved - * as simple DO (no need to parse TLV). */ + /* DO 7F21 is CONSTRUCTED in spec; we treat it as SIMPLE: no need to parse TLV */ { DO_CERT, SIMPLE, READ_ALWAYS | WRITE_PIN3, sc_get_data, sc_put_data }, { 0x7f48, CONSTRUCTED, READ_NEVER | WRITE_NEVER, NULL, NULL }, { 0x7f49, CONSTRUCTED, READ_ALWAYS | WRITE_NEVER, NULL, NULL }, { DO_AUTH, CONSTRUCTED, READ_ALWAYS | WRITE_NEVER, pgp_get_pubkey, NULL }, - /* The 0xA401, 0xB601, 0xB801 are just symbolic, it does not represent any real DO. + /* The DOs 0xA401, 0xB601, 0xB801 are virtual DOs, they do not represent any real DO. * However, their R/W access condition may block the process of importing key in pkcs15init. * So we set their accesses condition as WRITE_PIN3 (writable). */ { DO_AUTH_SYM, SIMPLE, READ_ALWAYS | WRITE_PIN3, pgp_get_pubkey_pem, NULL }, @@ -298,10 +342,16 @@ { 0, 0, 0, NULL, NULL }, }; +static struct do_info *pgp30_objects = pgp33_objects + 1; +static struct do_info *pgp21_objects = pgp33_objects + 6; +static struct do_info *pgp20_objects = pgp33_objects + 7; + + #define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) + struct pgp_priv_data { - pgp_blob_t * mf; - pgp_blob_t * current; /* currently selected file */ + pgp_blob_t *mf; + pgp_blob_t *current; /* currently selected file */ enum _version bcd_version; struct do_info *pgp_objects; @@ -309,6 +359,8 @@ enum _card_state state; /* card state */ enum _ext_caps ext_caps; /* extended capabilities */ + enum _sm_algo sm_algo; /* Secure Messaging algorithm */ + size_t max_challenge_size; size_t max_cert_size; @@ -317,119 +369,183 @@ /** + * Internal: get OpenPGP application identifier from AID DO 004F + */ +static int +get_full_pgp_aid(sc_card_t *card, sc_file_t *file) +{ + int r = SC_ERROR_INVALID_ARGUMENTS; + + if (file != NULL) { + /* explicitly get the full aid */ + r = sc_get_data(card, 0x004F, file->name, sizeof file->name); + file->namelen = MAX(r, 0); + } + + return r; +} + + +#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) + +/** * ABI: check if card's ATR matches one of driver's - * or if the OpenPGP application is present. + * or if the OpenPGP application is present on the card. */ static int pgp_match_card(sc_card_t *card) { int i; + LOG_FUNC_CALLED(card->ctx); + i = _sc_match_atr(card, pgp_atrs, &card->type); if (i >= 0) { card->name = pgp_atrs[i].name; - return 1; + LOG_FUNC_RETURN(card->ctx, 1); } else { sc_path_t partial_aid; - unsigned char aid[16]; + sc_file_t *file = NULL; /* select application "OpenPGP" */ sc_format_path("D276:0001:2401", &partial_aid); partial_aid.type = SC_PATH_TYPE_DF_NAME; - if (SC_SUCCESS == iso_ops->select_file(card, &partial_aid, NULL)) { - /* read information from AID */ - i = sc_get_data(card, 0x004F, aid, sizeof aid); - if (i == 16) { - switch ((aid[6] << 8) | aid[7]) { /* BCD-coded bytes */ - case 0x0101: - card->type = SC_CARD_TYPE_OPENPGP_V1; - sc_log(card->ctx, "OpenPGPv1-type card found"); - return 1; - case 0x0200: - case 0x0201: - card->type = SC_CARD_TYPE_OPENPGP_V2; - sc_log(card->ctx, "OpenPGPv2-type card found"); - return 1; - default: - sc_log(card->ctx, "unsupported OpenPGP-type card found"); - /* fall through */ + /* OpenPGP card only supports selection *with* requested FCI */ + i = iso_ops->select_file(card, &partial_aid, &file); + if (SC_SUCCESS == i) { + card->type = SC_CARD_TYPE_OPENPGP_BASE; + card->name = default_cardname; + + if (file->namelen != 16) + (void) get_full_pgp_aid(card, file); + if (file->namelen == 16) { + unsigned char major = BCD2UCHAR(file->name[6]); + + switch (major) { + case 1: + card->type = SC_CARD_TYPE_OPENPGP_V1; + card->name = default_cardname_v1; + break; + case 2: + card->type = SC_CARD_TYPE_OPENPGP_V2; + card->name = default_cardname_v2; + break; + case 3: + card->type = SC_CARD_TYPE_OPENPGP_V3; + card->name = default_cardname_v3; + break; + default: + break; } } + sc_file_free(file); + LOG_FUNC_RETURN(card->ctx, 1); } } - return 0; + LOG_FUNC_RETURN(card->ctx, 0); } -#define BCD2CHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) - /** - * ABI: initialize driver. + * ABI: initialize driver & allocate private data. */ static int pgp_init(sc_card_t *card) { struct pgp_priv_data *priv; - sc_path_t aid; + sc_path_t path; sc_file_t *file = NULL; struct do_info *info; int r; - pgp_blob_t *child = NULL; LOG_FUNC_CALLED(card->ctx); priv = calloc (1, sizeof *priv); if (!priv) - return SC_ERROR_OUT_OF_MEMORY; + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); card->drv_data = priv; card->cla = 0x00; - /* set pointer to correct list of card objects */ - priv->pgp_objects = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? pgp2_objects : pgp1_objects; - - /* set detailed card version */ - priv->bcd_version = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? OPENPGP_CARD_2_0 : OPENPGP_CARD_1_1; - /* select application "OpenPGP" */ - sc_format_path("D276:0001:2401", &aid); - aid.type = SC_PATH_TYPE_DF_NAME; - if ((r = iso_ops->select_file(card, &aid, &file)) < 0) { + sc_format_path("D276:0001:2401", &path); + path.type = SC_PATH_TYPE_DF_NAME; + if ((r = iso_ops->select_file(card, &path, &file)) < 0) { pgp_finish(card); - LOG_FUNC_RETURN(card->ctx, r); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); } /* defensive programming check */ if (!file) { pgp_finish(card); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); } if (file->namelen != 16) { /* explicitly get the full aid */ - r = sc_get_data(card, 0x004F, file->name, sizeof file->name); + r = get_full_pgp_aid(card, file); if (r < 0) { pgp_finish(card); - return r; + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); } - file->namelen = r; } /* read information from AID */ if (file->namelen == 16) { - /* OpenPGP card spec 1.1 & 2.0, section 4.2.1 & 4.1.2.1 */ + static char card_name[SC_MAX_APDU_BUFFER_SIZE] = "OpenPGP card"; + + /* OpenPGP card spec 1.1, 2.x & 3.x, section 4.2.1 & 4.1.2.1 */ priv->bcd_version = bebytes2ushort(file->name + 6); - card->version.fw_major = card->version.hw_major = BCD2CHAR(file->name[6]); - card->version.fw_minor = card->version.hw_minor = BCD2CHAR(file->name[7]); + card->version.fw_major = card->version.hw_major = BCD2UCHAR(file->name[6]); + card->version.fw_minor = card->version.hw_minor = BCD2UCHAR(file->name[7]); - /* kludge: get card's serial number from manufacturer ID + serial number */ + /* for "standard" cards, include detailed card version & serial no. in card name */ + if (card->name == default_cardname_v1 || + card->name == default_cardname_v2 || + card->name == default_cardname_v3) { + snprintf(card_name, sizeof(card_name), + "OpenPGP card v%u.%u (%04X %08lX)", + card->version.hw_major, card->version.hw_minor, + bebytes2ushort(file->name + 8), + bebytes2ulong(file->name + 10)); + } + else if (card->name != NULL) { + /* for other cards, append serial number to the card name */ + snprintf(card_name, sizeof(card_name), + "%s (%04X %08lX)", + card->name, + bebytes2ushort(file->name + 8), + bebytes2ulong(file->name + 10)); + } + card->name = card_name; + + /* GPG compatibility: set card's serial number to manufacturer ID + serial number */ memcpy(card->serialnr.value, file->name + 8, 6); card->serialnr.len = 6; + } else { + /* set detailed card version */ + switch (card->type) { + case SC_CARD_TYPE_OPENPGP_V3: + priv->bcd_version = OPENPGP_CARD_3_0; + break; + case SC_CARD_TYPE_OPENPGP_GNUK: + case SC_CARD_TYPE_OPENPGP_V2: + priv->bcd_version = OPENPGP_CARD_2_0; + break; + default: + priv->bcd_version = OPENPGP_CARD_1_1; + break; + } } + /* set pointer to correct list of card objects */ + priv->pgp_objects = (priv->bcd_version < OPENPGP_CARD_2_0) ? pgp1x_objects + : (priv->bcd_version < OPENPGP_CARD_2_1) ? pgp20_objects + : (priv->bcd_version < OPENPGP_CARD_3_0) ? pgp21_objects + : (priv->bcd_version < OPENPGP_CARD_3_3) ? pgp30_objects + : pgp33_objects; + /* change file path to MF for re-use in MF */ sc_format_path("3f00", &file->path); @@ -445,8 +561,9 @@ /* populate MF - add matching blobs listed in the pgp_objects table */ for (info = priv->pgp_objects; (info != NULL) && (info->id > 0); info++) { - if (((info->access & READ_MASK) != READ_NEVER) && - (info->get_fn != NULL)) { + if (((info->access & READ_MASK) != READ_NEVER) && (info->get_fn != NULL)) { + pgp_blob_t *child = NULL; + child = pgp_new_blob(card, priv->mf, info->id, sc_file_new()); /* catch out of memory condition */ @@ -460,72 +577,141 @@ /* get card_features from ATR & DOs */ pgp_get_card_features(card); + /* add supported algorithms based on specification for pkcs15-init */ + if (strcmp(card->ctx->app_name, "pkcs15-init") == 0){ + unsigned long flags; + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; + flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; // Can be generated in card + + switch (card->type) { + case SC_CARD_TYPE_OPENPGP_V3: + /* RSA 1024 was removed for v3+ */ + _sc_card_add_rsa_alg(card, 2048, flags, 0); + _sc_card_add_rsa_alg(card, 3072, flags, 0); + _sc_card_add_rsa_alg(card, 4096, flags, 0); + /* TODO add ECC + * v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */ + break; + case SC_CARD_TYPE_OPENPGP_GNUK: + _sc_card_add_rsa_alg(card, 2048, flags, 0); + /* TODO add ECC for more recent Gnuk (1.2.x) + * these are not include in SC_CARD_TYPE_OPENPGP_GNUK, but + * are treated like SC_CARD_TYPE_OPENPGP_V2 + * Gnuk supports NIST, SECG and Curve25519 from version 1.2.x on */ + break; + case SC_CARD_TYPE_OPENPGP_V2: + default: + _sc_card_add_rsa_alg(card, 1024, flags, 0); + _sc_card_add_rsa_alg(card, 2048, flags, 0); + _sc_card_add_rsa_alg(card, 3072, flags, 0); + _sc_card_add_rsa_alg(card, 4096, flags, 0); + break; + } + } + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } /** - * Internal: get features of the card: capabilities, ... + * Internal: parse historic bytes to get card capabilities. */ -static int -pgp_get_card_features(sc_card_t *card) +static void +pgp_parse_hist_bytes(sc_card_t *card, u8 *ctlv, size_t ctlv_len) { struct pgp_priv_data *priv = DRVDATA(card); - unsigned char *hist_bytes = card->atr.value; - size_t atr_len = card->atr.len; - size_t i; - pgp_blob_t *blob, *blob6e, *blob73; + const u8 *ptr; - /* parse card capabilities from historical bytes */ - for (i = 0; (i < atr_len) && (hist_bytes[i] != 0x73); i++) - ; - /* IS07816-4 hist bytes 3rd function table */ - if ((hist_bytes[i] == 0x73) && (atr_len > i+3)) { + /* IS07816-4 hist bytes: 3rd function table */ + if ((ptr = sc_compacttlv_find_tag(ctlv, ctlv_len, 0x73, NULL)) != NULL) { /* bit 0x40 in byte 3 of TL 0x73 means "extended Le/Lc" */ - if (hist_bytes[i+3] & 0x40) { + if (ptr[2] & 0x40) { card->caps |= SC_CARD_CAP_APDU_EXT; priv->ext_caps |= EXT_CAP_APDU_EXT; } /* bit 0x80 in byte 3 of TL 0x73 means "Command chaining" */ - if (hist_bytes[i+3] & 0x80) + if ((ptr[2] & 0x80) && + (priv->bcd_version >= OPENPGP_CARD_3_0)) { priv->ext_caps |= EXT_CAP_CHAINING; + } + } + + if ((priv->bcd_version >= OPENPGP_CARD_3_0) && + ((ptr = sc_compacttlv_find_tag(ctlv, ctlv_len, 0x31, NULL)) != NULL)) { + // ToDo ... + } +} + + +/** + * Internal: get features of the card: capabilities, ... + */ +static int +pgp_get_card_features(sc_card_t *card) +{ + struct pgp_priv_data *priv = DRVDATA(card); + u8 *hist_bytes = card->reader->atr_info.hist_bytes; + size_t hist_bytes_len = card->reader->atr_info.hist_bytes_len; + size_t i; + pgp_blob_t *blob, *blob6e, *blob73; + + /* parse card capabilities from historical bytes in ATR */ + if (hist_bytes_len > 0) { + /* category indicator 0x00, 0x10 or 0x80 => compact TLV (ISO) */ + switch (hist_bytes[0]) { + case 0x00: + if (hist_bytes_len > 4) { + pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-4); + } + break; + case 0x80: + if (hist_bytes_len > 1) { + pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-1); + } + break; + case 0x10: + if (hist_bytes_len > 2) { + pgp_parse_hist_bytes(card, hist_bytes+2, hist_bytes_len-2); + } + break; + } } + /* v1.1 does not support lifecycle via ACTIVATE & TERMINATE: set default */ + priv->ext_caps &= ~EXT_CAP_LCS; + if (priv->bcd_version >= OPENPGP_CARD_2_0) { /* get card capabilities from "historical bytes" DO */ if ((pgp_get_blob(card, priv->mf, 0x5f52, &blob) >= 0) && (blob->data != NULL) && (blob->data[0] == 0x00)) { - /* find beginning of "interesting" bytes */ - for (i = 0; (i < blob->len) && (blob->data[i] != 0x73); i++) - ; - /* IS07816-4 hist bytes 3rd function table */ - if ((blob->data[i] == 0x73) && (blob->len > i+3)) { - /* bit 0x40 in byte 3 of TL 0x73 means "extended Le/Lc" */ - if (blob->data[i+3] & 0x40) { - card->caps |= SC_CARD_CAP_APDU_EXT; - priv->ext_caps |= EXT_CAP_APDU_EXT; - } - /* bit 0x80 in byte 3 of TL 0x73 means "Command chaining" */ - if (blob->data[i+3] & 0x80) - priv->ext_caps |= EXT_CAP_CHAINING; + if (hist_bytes_len > 4) { + pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-4); } /* get card status from historical bytes status indicator */ - if ((blob->data[0] == 0x00) && (blob->len >= 4)) + if ((blob->data[0] == 0x00) && (blob->len >= 4)) { priv->state = blob->data[blob->len-3]; + /* state not CARD_STATE_UNKNOWN => LCS supported */ + if (priv->state != CARD_STATE_UNKNOWN) + priv->ext_caps |= EXT_CAP_LCS; + } } } + if (priv->bcd_version >= OPENPGP_CARD_3_1) { + card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; + } + if ((pgp_get_blob(card, priv->mf, 0x006e, &blob6e) >= 0) && (pgp_get_blob(card, blob6e, 0x0073, &blob73) >= 0)) { /* get "extended capabilities" DO */ if ((pgp_get_blob(card, blob73, 0x00c0, &blob) >= 0) && (blob->data != NULL) && (blob->len > 0)) { - /* in v2.0 bit 0x04 in first byte means "algorithm attributes changeable */ + /* v2.0+: bit 0x04 in first byte means "algorithm attributes changeable" */ if ((blob->data[0] & 0x04) && - (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)) + (priv->bcd_version >= OPENPGP_CARD_2_0)) priv->ext_caps |= EXT_CAP_ALG_ATTR_CHANGEABLE; /* bit 0x08 in first byte means "support for private use DOs" */ if (blob->data[0] & 0x08) @@ -541,19 +727,38 @@ card->caps |= SC_CARD_CAP_RNG; priv->ext_caps |= EXT_CAP_GET_CHALLENGE; } - /* in v2.0 bit 0x80 in first byte means "support Secure Messaging" */ + /* v2.0+: bit 0x80 in first byte means "support Secure Messaging" */ if ((blob->data[0] & 0x80) && - (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)) + (priv->bcd_version >= OPENPGP_CARD_2_0)) priv->ext_caps |= EXT_CAP_SM; if ((priv->bcd_version >= OPENPGP_CARD_2_0) && (blob->len >= 10)) { - /* max. challenge size is at bytes 3-4 */ + /* v2.0+: max. challenge size is at bytes 3-4 */ priv->max_challenge_size = bebytes2ushort(blob->data + 2); - /* max. cert size it at bytes 5-6 */ + /* v2.0+: max. cert size it at bytes 5-6 */ priv->max_cert_size = bebytes2ushort(blob->data + 4); - /* max. send/receive sizes are at bytes 7-8 resp. 9-10 */ - card->max_send_size = bebytes2ushort(blob->data + 6); - card->max_recv_size = bebytes2ushort(blob->data + 8); + + if (priv->bcd_version < OPENPGP_CARD_3_0) { + /* v2.x: SM algorithm is at byte 2: 0 == 3DES */ + priv->sm_algo = blob->data[1]; + if ((priv->sm_algo == SM_ALGO_NONE) && (priv->ext_caps & EXT_CAP_SM)) + priv->sm_algo = SM_ALGO_3DES; + + /* v2.x: max. send/receive sizes are at bytes 7-8 resp. 9-10 */ + card->max_send_size = bebytes2ushort(blob->data + 6); + card->max_recv_size = bebytes2ushort(blob->data + 8); + } + else { + /* v3.0+: SM algorithm is at byte 2: 0 == UNKNOWN */ + priv->sm_algo = blob->data[1]; + if ((priv->sm_algo == SM_ALGO_NONE) && (priv->ext_caps & EXT_CAP_SM)) + priv->sm_algo = SM_ALGO_UNKNOWN; + } + if (priv->bcd_version >= OPENPGP_CARD_3_3 && (blob->len >= 10)) { + /* v3.3+: MSE for key numbers 2(DEC) and 3(AUT) supported */ + if (blob->data[9]) + priv->ext_caps |= EXT_CAP_MSE; + } } } @@ -564,24 +769,40 @@ card->max_pin_len = blob->data[1]; } - /* get supported algorithms & key lengths from "algorithm attributes" DOs */ + /* get _current_ algorithms & key lengths from "algorithm attributes" DOs + * + * All available algorithms should be already provided by pgp_init. However, if another + * algorithm is found in the "algorithm attributes" DOs, it is supported by the card as + * well and therefore added + * see OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */ for (i = 0x00c1; i <= 0x00c3; i++) { unsigned long flags; /* Is this correct? */ - /* OpenPGP card spec 1.1 & 2.0, section 7.2.9 & 7.2.10 */ + /* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 / v3.x section 7.2.11 & 7.2.12 */ flags = SC_ALGORITHM_RSA_PAD_PKCS1; flags |= SC_ALGORITHM_RSA_HASH_NONE; /* Can be generated in card */ flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; - if ((pgp_get_blob(card, blob73, i, &blob) >= 0) && - (blob->data != NULL) && (blob->len >= 4)) { - if (blob->data[0] == 0x01) { /* Algorithm ID [RFC4880]: RSA */ - unsigned int keylen = bebytes2ushort(blob->data + 1); /* Measured in bit */ + /* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */ + if ((pgp_get_blob(card, blob73, i, &blob) >= 0) && (blob->data != NULL)) { + if (blob->len >= 3 && blob->data[0] == 0x01) { /* RSA [RFC 4880] */ + unsigned int keybits = bebytes2ushort(blob->data + 1); - _sc_card_add_rsa_alg(card, keylen, flags, 0); + _sc_card_add_rsa_alg(card, keybits, flags, 0); } + /* v3.0+: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */ + } + } + + if (priv->bcd_version >= OPENPGP_CARD_3_0) { + /* v3.0+: get length info from "extended length information" DO */ + if ((pgp_get_blob(card, blob6e, 0x7f66, &blob) >= 0) && + (blob->data != NULL) && (blob->len >= 8)) { + /* kludge: treat as SIMPLE DO and use appropriate offsets */ + card->max_send_size = bebytes2ushort(blob->data + 2); + card->max_recv_size = bebytes2ushort(blob->data + 6); } } } @@ -591,7 +812,7 @@ /** - * ABI: terminate driver. + * ABI: terminate driver & free private data. */ static int pgp_finish(sc_card_t *card) @@ -749,13 +970,15 @@ *p = blob; } else { - u8 id_str[2]; + char path[10] = "0000"; /* long enough */ /* no parent: set file's path = file's id */ - /* FIXME sc_format_path expects an hex string of a file - * identifier. ushort2bebytes instead delivers a two bytes binary - * string */ - sc_format_path((char *) ushort2bebytes(id_str, file_id), &blob->file->path); + if (4 != snprintf(path, sizeof(path), "%04X", file_id & 0xFFFF)) { + free(blob); + return NULL; + } + + sc_format_path(path, &blob->file->path); } /* find matching DO info: set file type depending on it */ @@ -869,7 +1092,7 @@ } -/* +/** * Internal: enumerate contents of a data blob. * The OpenPGP card has a TLV encoding according ASN.1 BER-encoding rules. */ @@ -893,14 +1116,20 @@ const u8 *data = in; pgp_blob_t *new; + if (!in) + return SC_ERROR_OBJECT_NOT_VALID; + r = sc_asn1_read_tag(&data, blob->len - (in - blob->data), &cla, &tag, &len); - if (r < 0) { + if (r < 0 || data == NULL) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unexpected end of contents\n"); return SC_ERROR_OBJECT_NOT_VALID; } + if (data + len > blob->data + blob->len) + return SC_ERROR_OBJECT_NOT_VALID; + /* undo ASN1's split of tag & class */ for (tmptag = tag; tmptag > 0x0FF; tmptag >>= 8) { cla <<= 8; @@ -989,7 +1218,7 @@ for (child = root->files; child; child = child->next) { /* The DO of SIMPLE type or the DO holding certificate * does not contain children */ - if (child->info->type == SIMPLE || child->id == DO_CERT) + if ((child->info && child->info->type == SIMPLE) || child->id == DO_CERT) continue; r = pgp_seek_blob(card, child, id, ret); if (r == 0) @@ -1063,7 +1292,7 @@ /** - * ABI: SELECT FILE. + * ABI: ISO 7816-4 SELECT FILE - search given file & make it the currently selected one. */ static int pgp_select_file(sc_card_t *card, const sc_path_t *path, sc_file_t **ret) @@ -1104,7 +1333,7 @@ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } - /* ignore explicitely mentioned MF at the path's beginning */ + /* ignore explicitly mentioned MF at the path's beginning */ path_start = pgp_strip_path(card, path); /* starting with the MF ... */ @@ -1114,7 +1343,7 @@ unsigned int id = bebytes2ushort(path->value + n); int r = pgp_get_blob(card, blob, id, &blob); - /* This file ID is refered when importing key&certificate via pkcs15init, like above. + /* This file ID is referred when importing key&certificate via pkcs15init, like above. * We pretend to successfully find this inexistent file. */ if (id == 0x4402 || id == 0x5f48) { if (ret == NULL) @@ -1143,7 +1372,7 @@ /** - * ABI: LIST FILES. + * ABI: ISO 7816-4 LIST FILES - enumerate all files in current DF. */ static int pgp_list_files(sc_card_t *card, u8 *buf, size_t buflen) @@ -1180,7 +1409,30 @@ /** - * ABI: READ BINARY. + * ABI: ISO 7816-4 GET CHALLENGE - generate random byte sequence. + */ +static int +pgp_get_challenge(struct sc_card *card, u8 *rnd, size_t len) +{ + struct pgp_priv_data *priv; + + LOG_FUNC_CALLED(card->ctx); + + priv = DRVDATA(card); + if (0 == (priv->ext_caps & EXT_CAP_GET_CHALLENGE)) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + } + + if (priv->max_challenge_size > 0 && len > priv->max_challenge_size) { + len = priv->max_challenge_size; + } + + LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len)); +} + + +/** + * ABI: ISO 7816-4 READ BINARY - read data from currently selected EF. */ static int pgp_read_binary(sc_card_t *card, unsigned int idx, @@ -1216,7 +1468,7 @@ /** - * ABI: WRITE BINARY. + * ABI: ISO 7816-4 WRITE BINARY - write data to currently selected EF. */ static int pgp_write_binary(sc_card_t *card, unsigned int idx, @@ -1227,7 +1479,7 @@ /** - * Internal: get public key from card: as DF + sub-wEFs. + * Internal: get public key from card - as DF + sub-wEFs. */ static int pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) @@ -1259,7 +1511,7 @@ /** - * Internal: get public key from card: as one wEF. + * Internal: get public key from card - as one wEF. */ static int pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) @@ -1301,7 +1553,7 @@ /** - * ABI: GET DATA. + * ABI: ISO 7816-4 GET DATA - get contents of a DO. */ static int pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) @@ -1409,7 +1661,7 @@ LOG_FUNC_CALLED(card->ctx); - /* Extended Header list (004D DO) needs a variant of PUT DATA command */ + /* Extended Header list (DO 004D) needs a variant of PUT DATA command */ if (tag == 0x004D) { ins = 0xDB; p1 = 0x3F; @@ -1447,7 +1699,7 @@ /** - * ABI: PUT DATA. + * ABI: ISO 7816-4 PUT DATA - write contents of a DO. */ static int pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len) @@ -1518,7 +1770,7 @@ /** - * ABI: PIN cmd: verify/change/unblock a PIN. + * ABI: ISO 7816-9 PIN CMD - verify/change/unblock a PIN. */ static int pgp_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) @@ -1599,7 +1851,40 @@ /** - * ABI: set security environment. + * ABI: ISO 7816-8 LOGOUT - reset all access rights gained. + */ +int pgp_logout(struct sc_card *card) +{ + int r = SC_SUCCESS; + struct pgp_priv_data *priv = DRVDATA(card); + + LOG_FUNC_CALLED(card->ctx); + + if (priv->bcd_version >= OPENPGP_CARD_3_1) { + unsigned char pin_reference; + for (pin_reference = 0x81; pin_reference <= 0x83; pin_reference++) { + int tmp = iso7816_logout(card, pin_reference); + if (r == SC_SUCCESS) { + r = tmp; + } + } + } else { + sc_path_t path; + sc_file_t *file = NULL; + + /* select application "OpenPGP" */ + sc_format_path("D276:0001:2401", &path); + path.type = SC_PATH_TYPE_DF_NAME; + r = iso_ops->select_file(card, &path, &file); + sc_file_free(file); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + +/** + * ABI: ISO 7816-8 SET SECURITY ENVIRONMENT. */ static int pgp_set_security_env(sc_card_t *card, @@ -1651,8 +1936,53 @@ } +/** + * set MANAGE SECURITY ENVIRONMENT as documented in 7.2.18 since OpenPGP Card v3.3 + * + * "This optional command (announced in Extended Capabilities) assigns a specific key to a + * command. The DEC-key (Key-Ref 2) can be assigned to the command INTERNAL AUTHENTICATE + * and the AUT-Key (Key.Ref 3) can be linked to the command PSO:DECIPHER also." + * + * key: Key-Ref to change (2 for DEC-Key or 3 for AUT-Key) + * p2: Usage to set (0xb8 for PSO:DECIPHER or 0xa4 for INTERNAL AUTHENTICATE) + **/ +static int +pgp_set_MSE(sc_card_t *card, int key, u8 p2) +{ + struct pgp_priv_data *priv = DRVDATA(card); + sc_apdu_t apdu; + u8 apdu_case = SC_APDU_CASE_3; + u8 apdu_data[3]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + // check if MSE is supported + if (!(priv->ext_caps & EXT_CAP_MSE)) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + + // create apdu + sc_format_apdu(card, &apdu, apdu_case, 0x22, 0x41, p2); + apdu.lc = 3; + apdu_data[0] = 0x83; + apdu_data[1] = 0x01; + apdu_data[2] = key; + apdu.data = apdu_data; + apdu.datalen = 3; + + // transmit apdu + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + /** - * ABI: COMPUTE DIGITAL SIGNATURE. + * ABI: ISO 7816-8 COMPUTE DIGITAL SIGNATURE. */ static int pgp_compute_signature(sc_card_t *card, const u8 *data, @@ -1708,7 +2038,7 @@ /** - * ABI: DECIPHER. + * ABI: ISO 7816-8 DECIPHER - perform deciphering operation. */ static int pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen, @@ -1723,11 +2053,11 @@ LOG_FUNC_CALLED(card->ctx); - /* There's some funny padding indicator that must be - * prepended... hmm. */ + /* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11 */ if (!(temp = malloc(inlen + 1))) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); - temp[0] = '\0'; + /* padding byte: 0x00 = RSA; 0x02 = AES [v2.1+ only] */ + temp[0] = 0x00; memcpy(temp + 1, in, inlen); in = temp; inlen += 1; @@ -1766,6 +2096,13 @@ apdu.resp = out; apdu.resplen = outlen; + /* For OpenPGP Card >=v3.3, key slot 3 instead of 2 can be used for deciphering, + * but this has to be set via MSE beforehand on every usage (slot 2 is used by default) + * see section 7.2.18 of the specification of OpenPGP Card v3.3 */ + if (priv->bcd_version >= OPENPGP_CARD_3_3 && env->key_ref[0] == 0x02){ + pgp_set_MSE(card, 3, 0xb8); + } + r = sc_transmit_apdu(card, &apdu); free(temp); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); @@ -1773,6 +2110,11 @@ r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); + /* For OpenPGP Card >=v3.3, use key slot 2 for deciphering again (set to default) */ + if (priv->bcd_version >= OPENPGP_CARD_3_3 && env->key_ref[0] == 0x02){ + pgp_set_MSE(card, 2, 0xb8); + } + LOG_FUNC_RETURN(card->ctx, (int)apdu.resplen); } @@ -2020,6 +2362,7 @@ pubkey.u.rsa.exponent.len = exponent_len >> 3; r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len); + LOG_TEST_RET(card->ctx, r, "Cannot encode pubkey."); sc_log(card->ctx, "Update blob content."); r = pgp_set_blob(pk_blob, data, len); @@ -2056,6 +2399,8 @@ r = sc_asn1_read_tag((const u8**)&part, data_len - (in - data), &cla, &tag, &len); + if (part == NULL) + r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; LOG_TEST_RET(card->ctx, r, "Unexpected end of contents."); /* undo ASN1's split of tag & class */ for (tmptag = tag; tmptag > 0x0FF; tmptag >>= 8) { @@ -2471,8 +2816,8 @@ { sc_context_t *ctx = card->ctx; sc_cardctl_openpgp_keygen_info_t pubkey; - u8 *data; - size_t len; + u8 *data = NULL; + size_t len = 0; int r; LOG_FUNC_CALLED(ctx); @@ -2568,7 +2913,7 @@ * according to https://www.crypto-stick.com/en/faq * (How to reset a Crypto Stick? question). * Gnuk is known not to support this feature. */ - static const char *apdu_hex[] = { + const char *apdu_hex[] = { /* block PIN1 */ "00:20:00:81:08:40:40:40:40:40:40:40:40", "00:20:00:81:08:40:40:40:40:40:40:40:40", @@ -2581,47 +2926,56 @@ "00:20:00:83:08:40:40:40:40:40:40:40:40", /* TERMINATE */ "00:e6:00:00", - /* ACTIVATE */ - "00:44:00:00", NULL }; + sc_apdu_t apdu; int i; int r = SC_SUCCESS; + struct pgp_priv_data *priv = DRVDATA(card); LOG_FUNC_CALLED(card->ctx); - /* check card version */ - if (card->type != SC_CARD_TYPE_OPENPGP_V2) { - sc_log(card->ctx, "Card is not OpenPGP v2"); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NO_CARD_SUPPORT); - } - sc_log(card->ctx, "Card is OpenPGP v2. Erase card."); - - /* iterate over the commands above */ - for (i = 0; apdu_hex[i] != NULL; i++) { - u8 apdu_bin[25]; /* large enough to convert apdu_hex */ - size_t apdu_bin_len = sizeof(apdu_bin); - sc_apdu_t apdu; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - - /* convert hex array to bin array */ - r = sc_hex_to_bin(apdu_hex[i], apdu_bin, &apdu_bin_len); - LOG_TEST_RET(card->ctx, r, "Failed to convert APDU bytes"); - - /* build APDU from binary array */ - r = sc_bytes2apdu(card->ctx, apdu_bin, apdu_bin_len, &apdu); - if (r) { - sc_log(card->ctx, "Failed to build APDU"); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); - } + if ((priv->ext_caps & EXT_CAP_LCS) == 0) { + LOG_TEST_RET(card->ctx, SC_ERROR_NO_CARD_SUPPORT, + "Card does not offer life cycle management"); + } + + switch (priv->state) { + case CARD_STATE_ACTIVATED: + /* iterate over the commands above */ + for (i = 0; apdu_hex[i] != NULL; i++) { + u8 apdu_bin[25]; /* large enough to convert apdu_hex */ + size_t apdu_bin_len = sizeof(apdu_bin); + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + + /* convert hex array to bin array */ + r = sc_hex_to_bin(apdu_hex[i], apdu_bin, &apdu_bin_len); + LOG_TEST_RET(card->ctx, r, "Failed to convert APDU bytes"); + + /* build APDU from binary array */ + r = sc_bytes2apdu(card->ctx, apdu_bin, apdu_bin_len, &apdu); + if (r) { + sc_log(card->ctx, "Failed to build APDU"); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); - /* send APDU to card */ - sc_log(card->ctx, "Sending APDU%d %s", i, apdu_hex[i]); - r = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(card->ctx, r, "Transmitting APDU failed"); + /* send APDU to card */ + sc_log(card->ctx, "Sending APDU%d %s", i, apdu_hex[i]); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "Transmitting APDU failed"); + } + /* fall through */ + case CARD_STATE_INITIALIZATION: + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x44, 0, 0); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "Transmitting APDU failed"); + break; + default: + LOG_TEST_RET(card->ctx, SC_ERROR_NO_CARD_SUPPORT, + "Card does not offer life cycle management"); } LOG_FUNC_RETURN(card->ctx, r); @@ -2629,7 +2983,7 @@ /** - * ABI: card ctl: perform special card-specific operations. + * ABI: ISO 7816-9 CARD CTL - perform special card-specific operations. */ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) @@ -2666,7 +3020,7 @@ /** - * Internal: delete key. + * Internal: delete key (GnuK only). */ static int gnuk_delete_key(sc_card_t *card, u8 key_id) @@ -2708,7 +3062,7 @@ /** - * ABI: DELETE FILE. + * ABI: ISO 7816-9 DELETE FILE - delete EF or DF given. */ static int pgp_delete_file(sc_card_t *card, const sc_path_t *path) @@ -2727,7 +3081,7 @@ /* save "current" blob */ blob = priv->current; - /* do try to delete MF */ + /* don't try to delete MF */ if (blob == priv->mf) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); @@ -2758,7 +3112,7 @@ /** - * ABI: UPDATE BINARY. + * ABI: ISO 7816-4 UPDATE BINARY - update data in current EF. */ static int pgp_update_binary(sc_card_t *card, unsigned int idx, @@ -2786,10 +3140,49 @@ /** - * ABI: driver binding stuff. + * ABI: card reader lock obtained - re-select card applet if necessary. + */ +static int pgp_card_reader_lock_obtained(sc_card_t *card, int was_reset) +{ + struct pgp_priv_data *priv = DRVDATA(card); /* may be null during initialization */ + int r = SC_SUCCESS; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (card->flags & SC_CARD_FLAG_KEEP_ALIVE + && was_reset <= 0 + && priv != NULL && priv->mf && priv->mf->file) { + /* check whether applet is still selected */ + unsigned char aid[16]; + + r = sc_get_data(card, 0x004F, aid, sizeof aid); + if ((size_t) r != priv->mf->file->namelen + || 0 != memcmp(aid, priv->mf->file->name, r)) { + /* reselect is required */ + was_reset = 1; + } + r = SC_SUCCESS; + } + + if (was_reset > 0) { + sc_file_t *file = NULL; + sc_path_t path; + /* select application "OpenPGP" */ + sc_format_path("D276:0001:2401", &path); + path.type = SC_PATH_TYPE_DF_NAME; + r = iso_ops->select_file(card, &path, &file); + sc_file_free(file); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + +/** + * API: integrate OpenPGP driver into OpenSC's driver list. */ -static struct sc_card_driver * -sc_get_driver(void) +struct sc_card_driver * +sc_get_openpgp_driver(void) { struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); @@ -2801,9 +3194,11 @@ pgp_ops.finish = pgp_finish; pgp_ops.select_file = pgp_select_file; pgp_ops.list_files = pgp_list_files; + pgp_ops.get_challenge = pgp_get_challenge; pgp_ops.read_binary = pgp_read_binary; pgp_ops.write_binary = pgp_write_binary; pgp_ops.pin_cmd = pgp_pin_cmd; + pgp_ops.logout = pgp_logout; pgp_ops.get_data = pgp_get_data; pgp_ops.put_data = pgp_put_data; pgp_ops.set_security_env= pgp_set_security_env; @@ -2812,16 +3207,7 @@ pgp_ops.card_ctl = pgp_card_ctl; pgp_ops.delete_file = pgp_delete_file; pgp_ops.update_binary = pgp_update_binary; + pgp_ops.card_reader_lock_obtained = pgp_card_reader_lock_obtained; return &pgp_drv; } - - -/** - * ABI: driver binding stuff. - */ -struct sc_card_driver * -sc_get_openpgp_driver(void) -{ - return sc_get_driver(); -} diff -Nru opensc-0.17.0/src/libopensc/card-piv.c opensc-0.19.0/src/libopensc/card-piv.c --- opensc-0.17.0/src/libopensc/card-piv.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-piv.c 2018-09-13 11:47:21.000000000 +0000 @@ -3,8 +3,7 @@ * card-default.c: Support for cards with no driver * * Copyright (C) 2001, 2002 Juha Yrjölä - * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert - * Copyright (C) 2016 Douglas E. Engert + * Copyright (C) 2005-2016 Douglas E. Engert * Copyright (C) 2006, Identity Alliance, Thomas Harning * Copyright (C) 2007, EMC, Russell Larner * @@ -141,8 +140,13 @@ int flags; } piv_obj_cache_t; +enum { + PIV_STATE_NORMAL = 0, + PIV_STATE_MATCH, + PIV_STATE_INIT +}; + typedef struct piv_private_data { - sc_file_t *aid_file; int enumtag; int selected_obj; /* The index into the piv_objects last selected */ int return_only_cert; /* return the cert from the object */ @@ -160,33 +164,35 @@ char * offCardCertURL; int pin_preference; /* set from Discovery object */ int logged_in; + int pstate; int pin_cmd_verify; + int context_specific; int pin_cmd_noparse; unsigned int pin_cmd_verify_sw1; unsigned int pin_cmd_verify_sw2; int tries_left; /* SC_PIN_CMD_GET_INFO tries_left from last */ unsigned int card_issues; /* card_issues flags for this card */ int object_test_verify; /* Can test this object to set verification state of card */ - int neo_version; /* 3 byte version number of NEO or Ybuikey4 as integer */ + int yubico_version; /* 3 byte version number of NEO or Yubikey4 as integer */ } piv_private_data_t; #define PIV_DATA(card) ((piv_private_data_t*)card->drv_data) struct piv_aid { int enumtag; - size_t len_short; /* min lenght without version */ + size_t len_short; /* min length without version */ size_t len_long; /* With version and other stuff */ u8 *value; }; /* - * The Generic entry should be the "A0 00 00 03 08 00 00 01 00 " + * The Generic entry should be the "A0 00 00 03 08 00 00 10 00 " * NIST published this on 10/6/2005 * 800-73-2 Part 1 now refers to version "02 00" * i.e. "A0 00 00 03 08 00 00 01 00 02 00". * but we don't need the version number. but could get it from the PIX. * - * 800-73-3 Part 1 now referes to "01 00" i.e. going back to 800-73-1. + * 800-73-3 Part 1 now refers to "01 00" i.e. going back to 800-73-1. * The main differences between 73-1, and 73-3 are the addition of the * key History object and keys, as well as Discovery and Iris objects. * These can be discovered by trying GET DATA @@ -205,6 +211,8 @@ /* will also test after first PIN verify if protected object can be used instead */ #define CI_CANT_USE_GETDATA_FOR_STATE 0x00000008U /* No object to test verification inplace of VERIFY Lc=0 */ #define CI_LEAKS_FILE_NOT_FOUND 0x00000010U /* GET DATA of empty object returns 6A 82 even if PIN not verified */ +#define CI_DISCOVERY_USELESS 0x00000020U /* Discovery can not be used to query active AID */ +#define CI_PIV_AID_LOSE_STATE 0x00000040U /* PIV AID can lose the login state run with out it*/ #define CI_OTHER_AID_LOSE_STATE 0x00000100U /* Other drivers match routines may reset our security state and lose AID!!! */ #define CI_NFC_EXPOSE_TOO_MUCH 0x00000200U /* PIN, crypto and objects exposed over NFS in violation of 800-73-3 */ @@ -388,12 +396,13 @@ static struct sc_card_operations piv_ops; static struct sc_card_driver piv_drv = { - "PIV-II for multiple cards", + "Personal Identity Verification Card", "PIV-II", &piv_ops, NULL, 0, NULL }; +static int piv_match_card_continued(sc_card_t *card); static int piv_find_obj_by_containerid(sc_card_t *card, const u8 * str) @@ -412,7 +421,7 @@ } /* - * If ptr == NULL, just return the size of the tag and lenght and data + * If ptr == NULL, just return the size of the tag and length and data * otherwise, store tag and length at **ptr, and increment */ @@ -458,7 +467,7 @@ * Send a command and receive data. There is always something to send. * Used by GET DATA, PUT DATA, GENERAL AUTHENTICATE * and GENERATE ASYMMETRIC KEY PAIR. - * GET DATA may call to get the first 128 bytes to get the lenght from the tag. + * GET DATA may call to get the first 128 bytes to get the length from the tag. * * A caller may provide a buffer, and length to read. If not provided, * an internal 4096 byte buffer is used, and a copy is returned to the @@ -470,6 +479,7 @@ size_t * recvbuflen) { int r; + int r_tag ; sc_apdu_t apdu; u8 rbufinitbuf[4096]; u8 *rbuf; @@ -563,15 +573,12 @@ * the buffer is bigger, so it will not produce "ASN1.tag too long!" */ body = rbuf; - if (sc_asn1_read_tag(&body, 0xffff, &cla_out, &tag_out, &bodylen) != SC_SUCCESS) { - /* only early beta cards had this problem */ - sc_log(card->ctx, "***** received buffer tag MISSING "); + r_tag = sc_asn1_read_tag(&body, apdu.resplen, &cla_out, &tag_out, &bodylen); + sc_log(card->ctx, "r_tag:%d body:%p", r_tag, body); + if ( (r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS) + || body == NULL) { body = rbuf; - /* some readers/cards might return 6c 00 */ - if (apdu.sw1 == 0x61 || apdu.sw2 == 0x6c ) - bodylen = 12000; - else - bodylen = apdu.resplen; + bodylen = apdu.resplen; } rbuflen = body - rbuf + bodylen; @@ -669,6 +676,9 @@ in_len = rbuflen; r = sc_asn1_read_tag(&cp, rbuflen, &cla_out, &tag_out, &in_len); + if (cp == NULL) { + r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; + } if (r != SC_SUCCESS) { sc_log(card->ctx, "Tag buffer not found"); goto err; @@ -744,10 +754,9 @@ /* find the PIV AID on the card. If card->type already filled in, * then look for specific AID only - * Assumes that priv may not be present */ -static int piv_find_aid(sc_card_t * card, sc_file_t *aid_file) +static int piv_find_aid(sc_card_t * card) { sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; @@ -760,7 +769,7 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - /* first see if the default applcation will return a template + /* first see if the default application will return a template * that we know about. */ @@ -816,7 +825,7 @@ r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) { if (card->type != 0 && card->type == piv_aids[i].enumtag) - LOG_FUNC_RETURN(card->ctx, i); + LOG_FUNC_RETURN(card->ctx, (r < 0)? r: i); continue; } @@ -828,8 +837,6 @@ if (apdu.resp[0] != 0x6f || apdu.resp[1] > apdu.resplen - 2 ) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT); - card->ops->process_fci(card, aid_file, apdu.resp+2, apdu.resp[1]); - LOG_FUNC_RETURN(card->ctx, i); } @@ -846,6 +853,7 @@ u8 **buf, size_t *buf_len) { int r; + int r_tag; int f = -1; size_t len; u8 tagbuf[16]; @@ -871,9 +879,11 @@ goto err; } body = tagbuf; - if (sc_asn1_read_tag(&body, 0xfffff, &cla_out, &tag_out, &bodylen) != SC_SUCCESS) { + r_tag = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen); + if ((r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS) + || body == NULL) { sc_log(card->ctx, "DER problem"); - r = SC_ERROR_INVALID_ASN1_OBJECT; + r = SC_ERROR_FILE_NOT_FOUND; goto err; } rbuflen = body - tagbuf + bodylen; @@ -883,7 +893,7 @@ goto err; } memcpy(*buf, tagbuf, len); /* copy first or only part */ - if (rbuflen > len) { + if (rbuflen > len + sizeof(tagbuf)) { len = read(f, *buf + sizeof(tagbuf), rbuflen - sizeof(tagbuf)); /* read rest */ if (len != rbuflen - sizeof(tagbuf)) { r = SC_ERROR_INVALID_ASN1_OBJECT; @@ -912,6 +922,8 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_log(card->ctx, "#%d", enumtag); + sc_lock(card); /* do check len and get data in same transaction */ + /* assert(enumtag >= 0 && enumtag < PIV_OBJ_LAST_ENUM); */ tag_len = piv_objects[enumtag].tag_len; @@ -934,9 +946,12 @@ rbuflen = sizeof(rbufinitbuf); r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, &rbuf, &rbuflen); if (r > 0) { + int r_tag; body = rbuf; - if (sc_asn1_read_tag(&body, 0xffff, &cla_out, &tag_out, &bodylen) != SC_SUCCESS) { - sc_log(card->ctx, "***** received buffer tag MISSING "); + r_tag = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen); + if ((r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS) + || body == NULL) { + sc_log(card->ctx, "r_tag:%d body:%p", r_tag, body); r = SC_ERROR_FILE_NOT_FOUND; goto err; } @@ -963,6 +978,7 @@ r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, buf, buf_len); err: + sc_unlock(card); LOG_FUNC_RETURN(card->ctx, r); } @@ -1296,7 +1312,7 @@ p += count; put_tag_and_len(0x71, 1, &p); /* Use 01 as per NIST 800-73-3 */ - *p++ = (flags)? 0x01:0x00; /* certinfo, i.e. gziped? */ + *p++ = (flags)? 0x01:0x00; /* certinfo, i.e. gzipped? */ put_tag_and_len(0xFE,0,&p); /* LRC tag */ sc_log(card->ctx, "DEE buf %p len %"SC_FORMAT_LEN_PTRDIFF_T"u %"SC_FORMAT_LEN_SIZE_T"u", @@ -1316,10 +1332,10 @@ * Note: the select file will have saved the object type for us * Write is used by piv-tool, so we will use flags: * length << 8 | 8bits: - * object xxxx0000 - * uncompresed cert xxx00001 - * compressed cert xxx10001 - * pubkey xxxx0010 + * object xxxx0000 + * uncompressed cert xxx00001 + * compressed cert xxx10001 + * pubkey xxxx0010 * * to indicate we are writing a cert and if is compressed * or if we are writing a pubkey in to the cache. @@ -1418,8 +1434,8 @@ /* * Card initialization is NOT standard. - * Some cards use mutual or external authentication usings 3des or aes key. We - * will read in the key from a file either binary or hex encided. + * Some cards use mutual or external authentication using 3des or aes key. We + * will read in the key from a file either binary or hex encoded. * This is only needed during initialization/personalization of the card */ @@ -1512,7 +1528,7 @@ r = SC_ERROR_OUT_OF_MEMORY; goto err; } - keybuf[fsize] = 0x00; /* incase it is text need null */ + keybuf[fsize] = 0x00; /* in case it is text need null */ if (fread(keybuf, 1, fsize, f) != fsize) { sc_log(card->ctx, " Unable to read key\n"); @@ -1619,7 +1635,7 @@ r = piv_get_key(card, alg_id, &key, &keylen); if (r) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error getting General Auth key\n"); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error getting General Auth key\n"); goto err; } @@ -1899,7 +1915,7 @@ r = piv_get_key(card, alg_id, &key, &keylen); if (r) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error geting General Auth key\n"); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error getting General Auth key\n"); goto err; } @@ -2072,8 +2088,6 @@ const u8 *fascn; const u8 *guid; size_t rbuflen = 0, bodylen, fascnlen, guidlen; - u8 temp[2000]; - size_t templen = sizeof(temp); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (card->serialnr.len) { @@ -2081,15 +2095,12 @@ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } - /* ensure we've got the PIV selected, and nothing else is in process */ - /* This fixes several problems due to previous incomplete APDUs during card detection */ - /* Note: We need the temp because (some?) Oberthur cards don't like selecting an applet without response data */ - /* 800-73-3 part1 draft, and CIO Council docs imply for PIV Compatible card - * The FASC-N Agency code should be 9999 and there should be a GUID - * based on RFC 4122. RIf so and the GUID is not all 0's + /* + * 800-73-3 Part 1 and CIO Council docs say for PIV Compatible cards + * the FASC-N Agency code should be 9999 and there should be a GUID + * based on RFC 4122. If GUID present and not zero * we will use the GUID as the serial number. */ - piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); r = piv_get_cached_data(card, PIV_OBJ_CHUI, &rbuf, &rbuflen); LOG_TEST_RET(card->ctx, r, "Failure retrieving CHUI"); @@ -2112,7 +2123,7 @@ fascn, fascnlen, guid, guidlen, gbits); if (fascn && fascnlen == 25) { - /* test if guid and the fascn starts with ;9999 (in ISO 4bit + partiy code) */ + /* test if guid and the fascn starts with ;9999 (in ISO 4bit + parity code) */ if (!(gbits && fascn[0] == 0xD4 && fascn[1] == 0xE7 && fascn[2] == 0x39 && (fascn[3] | 0x7F) == 0xFF)) { serial->len = fascnlen < SC_MAX_SERIALNR ? fascnlen : SC_MAX_SERIALNR; @@ -2189,7 +2200,7 @@ return piv_general_external_authenticate(card, *(opts+1), *(opts+2)); break; - case'M': + case 'M': return piv_general_mutual_authenticate(card, *(opts+1), *(opts+2)); break; @@ -2215,54 +2226,41 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { - u8 sbuf[16]; + /* Dynamic Authentication Template (Challenge) */ + u8 sbuf[] = {0x7c, 0x02, 0x81, 0x00}; u8 *rbuf = NULL; - size_t rbuflen = 0; - u8 *p, *q; + const u8 *p; + size_t rbuf_len = 0, out_len = 0; int r; + unsigned int tag, cla; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + LOG_FUNC_CALLED(card->ctx); - sc_log(card->ctx, "challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len); + /* NIST 800-73-3 says use 9B, previous verisons used 00 */ + r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); + LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed"); - r = sc_lock(card); - if (r != SC_SUCCESS) - LOG_FUNC_RETURN(card->ctx, r); + p = rbuf; + r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len); + if (r < 0 || (cla|tag) != 0x7C) { + LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Dynamic Authentication Template"); + } - p = sbuf; - *p++ = 0x7c; - *p++ = 0x02; - *p++ = 0x81; - *p++ = 0x00; + rbuf_len = out_len; + r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len); + if (r < 0 || (cla|tag) != 0x81) { + LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Challenge"); + } - /* assuming 8 byte response ? */ - /* should take what the card returns */ - while (len > 0) { - size_t n = len > 8 ? 8 : len; - - /* NIST 800-73-3 says use 9B, previous verisons used 00 */ - r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, p - sbuf, &rbuf, &rbuflen); - if (r < 0) { - sc_unlock(card); - LOG_FUNC_RETURN(card->ctx, r); - } - q = rbuf; - if ( (*q++ != 0x7C) - || (*q++ != rbuflen - 2) - || (*q++ != 0x81) - || (*q++ != rbuflen - 4)) { - r = SC_ERROR_INVALID_DATA; - sc_unlock(card); - LOG_FUNC_RETURN(card->ctx, r); - } - memcpy(rnd, q, n); - len -= n; - rnd += n; - free(rbuf); - rbuf = NULL; + if (len < out_len) { + out_len = len; } + memcpy(rnd, p, out_len); + + r = (int) out_len; - r = sc_unlock(card); +err: + free(rbuf); LOG_FUNC_RETURN(card->ctx, r); @@ -2333,7 +2331,7 @@ u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */ u8 *rbuf = NULL; - size_t rbuflen; + size_t rbuflen = 0; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); @@ -2372,15 +2370,15 @@ r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref, sbuf, p - sbuf, &rbuf, &rbuflen); - if ( r >= 0) { - body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x7c, &bodylen); - + if (r >= 0) { + body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x7c, &bodylen); if (body) { tag = sc_asn1_find_tag(card->ctx, body, bodylen, 0x82, &taglen); if (tag) { memcpy(out, tag, taglen); r = taglen; - } + } else + r = SC_ERROR_INVALID_DATA; } else r = SC_ERROR_INVALID_DATA; } @@ -2508,7 +2506,7 @@ /* only support single EF in current application */ /* - * PIV emulates files, and only does so becauses sc_pkcs15_* uses + * PIV emulates files, and only does so because sc_pkcs15_* uses * select_file and read_binary. The emulation adds path emulated structures * so piv_select_file will find it. * there is no dir. Only direct access to emulated files @@ -2577,12 +2575,10 @@ } -static int piv_process_discovery(sc_card_t *card) +static int piv_parse_discovery(sc_card_t *card, u8 * rbuf, size_t rbuflen, int aid_only) { piv_private_data_t * priv = PIV_DATA(card); - int r; - u8 * rbuf = NULL; - size_t rbuflen = 0; + int r = 0; const u8 * body; size_t bodylen; const u8 * aid; @@ -2592,20 +2588,6 @@ unsigned int cla_out, tag_out; - r = piv_get_cached_data(card, PIV_OBJ_DISCOVERY, &rbuf, &rbuflen); - if (r <= 0) { - priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; - /* Discovery object is only object that has 3 byte Lc= 50017E - * and pree 800-73-3 cards may treat this as a strange error. - * So treat any error as not present - */ - r = 0; - goto err; - } - - sc_log(card->ctx, "Discovery = %p:%"SC_FORMAT_LEN_SIZE_T"u", rbuf, - rbuflen); - /* the object is now cached, see what we have */ if (rbuflen != 0) { body = rbuf; if ((r = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen)) != SC_SUCCESS) { @@ -2625,19 +2607,21 @@ if (aid == NULL || aidlen < piv_aids[0].len_short || memcmp(aid,piv_aids[0].value,piv_aids[0].len_short) != 0) { /*TODO look at long */ sc_log(card->ctx, "Discovery object not PIV"); - r = SC_SUCCESS; /* not an error could be some other appl */ + r = SC_ERROR_INVALID_CARD; /* This is an error */ goto err; } - pinp = sc_asn1_find_tag(card->ctx, body, bodylen, 0x5F2F, &pinplen); - sc_log(card->ctx, - "Discovery pinp=%p:%"SC_FORMAT_LEN_SIZE_T"u", - pinp, pinplen); - if (pinp && pinplen == 2) { - sc_log(card->ctx, "Discovery pinp flags=0x%2.2x 0x%2.2x",*pinp, *(pinp+1)); - r = SC_SUCCESS; - if (*pinp == 0x60 && *(pinp+1) == 0x20) { /* use Global pin */ - sc_log(card->ctx, "Pin Preference - Global"); - priv->pin_preference = 0x00; + if (aid_only == 0) { + pinp = sc_asn1_find_tag(card->ctx, body, bodylen, 0x5F2F, &pinplen); + sc_log(card->ctx, + "Discovery pinp=%p:%"SC_FORMAT_LEN_SIZE_T"u", + pinp, pinplen); + if (pinp && pinplen == 2) { + sc_log(card->ctx, "Discovery pinp flags=0x%2.2x 0x%2.2x",*pinp, *(pinp+1)); + r = SC_SUCCESS; + if (*pinp == 0x60 && *(pinp+1) == 0x20) { /* use Global pin */ + sc_log(card->ctx, "Pin Preference - Global"); + priv->pin_preference = 0x00; + } } } } @@ -2647,6 +2631,60 @@ LOG_FUNC_RETURN(card->ctx, r); } + +/* normal way to get the discovery object via cache */ +static int piv_process_discovery(sc_card_t *card) +{ + int r; + u8 * rbuf = NULL; + size_t rbuflen = 0; + + r = piv_get_cached_data(card, PIV_OBJ_DISCOVERY, &rbuf, &rbuflen); + /* Note rbuf and rbuflen are now pointers into cache */ + if (r < 0) + goto err; + + sc_log(card->ctx, "Discovery = %p:%"SC_FORMAT_LEN_SIZE_T"u", rbuf, + rbuflen); + /* the object is now cached, see what we have */ + r = piv_parse_discovery(card, rbuf, rbuflen, 0); + +err: + LOG_FUNC_RETURN(card->ctx, r); +} + + +static int piv_find_discovery(sc_card_t *card) +{ + int r = 0; + u8 rbuf[256]; + size_t rbuflen = sizeof(rbuf); + u8 * arbuf = rbuf; + piv_private_data_t * priv = PIV_DATA(card); + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* + * During piv_match or piv_card_reader_lock_obtained, + * we use the discovery object to test if card present, and + * if PIV AID is active. So we can not use the cache + */ + + /* If not valid, read, cache and test */ + if (!(priv->obj_cache[PIV_OBJ_DISCOVERY].flags & PIV_OBJ_CACHE_VALID)) { + r = piv_process_discovery(card); + } else { + /* if already in cache,force read */ + r = piv_get_data(card, PIV_OBJ_DISCOVERY, &arbuf, &rbuflen); + if (r >= 0) + /* make sure it is PIV AID */ + r = piv_parse_discovery(card, rbuf, rbuflen, 1); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + /* * The history object lists what retired keys and certs are on the card * or listed in the offCardCertURL. The user may have read the offCardURL file, @@ -2736,7 +2774,7 @@ } } else { - sc_log(card->ctx, "Problem with Histroy object\n"); + sc_log(card->ctx, "Problem with History object\n"); goto err; } } @@ -2799,8 +2837,8 @@ body = ocfhfbuf; if (sc_asn1_read_tag(&body, ocfhflen, &cla_out, - &tag_out, &bodylen) != SC_SUCCESS || - cla_out+tag_out != 0x30) { + &tag_out, &bodylen) != SC_SUCCESS + || cla_out+tag_out != 0x30) { sc_log(card->ctx, "DER problem"); r = SC_ERROR_INVALID_ASN1_OBJECT; goto err; @@ -2809,15 +2847,15 @@ while (bodylen > 0) { seqtag = seq; if (sc_asn1_read_tag(&seq, bodylen, &cla_out, - &tag_out, &seqlen) != SC_SUCCESS || - cla_out+tag_out != 0x30) { + &tag_out, &seqlen) != SC_SUCCESS + || cla_out+tag_out != 0x30) { sc_log(card->ctx, "DER problem"); r = SC_ERROR_INVALID_ASN1_OBJECT; goto err; } keyref = sc_asn1_find_tag(card->ctx, seq, seqlen, 0x04, &keyreflen); if (!keyref || keyreflen != 1 || - (*keyref < 0x82 && *keyref > 0x95)) { + (*keyref < 0x82 || *keyref > 0x95)) { sc_log(card->ctx, "DER problem"); r = SC_ERROR_INVALID_ASN1_OBJECT; goto err; @@ -2883,7 +2921,6 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (priv) { - sc_file_free(priv->aid_file); if (priv->w_buf) free(priv->w_buf); if (priv->offCardCertURL) @@ -2902,21 +2939,52 @@ free(priv->obj_cache[i].internal_obj_data); } free(priv); + card->drv_data = NULL; /* priv */ } return 0; } - static int piv_match_card(sc_card_t *card) { - int i, k; - size_t j; - u8 *p, *pe; - sc_file_t aidfile; - int type = -1; - piv_private_data_t *priv; + int r = 0; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + /* piv_match_card may be called with card->type, set by opensc.conf */ + /* user provide card type must be one we know */ + switch (card->type) { + case -1: + case SC_CARD_TYPE_PIV_II_GENERIC: + case SC_CARD_TYPE_PIV_II_HIST: + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: + case SC_CARD_TYPE_PIV_II_GI_DE: + break; + default: + return 0; /* can not handle the card */ + } + /* its one we know, or we can test for it in piv_init */ + /* + * We will call piv_match_card_continued here then + * again in piv_init to avoid any issues with passing + * anything from piv_match_card + * to piv_init as had been done in the past + */ + r = piv_match_card_continued(card); + if (r == 1) { + /* clean up what we left in card */ + sc_unlock(card); + piv_finish(card); + } + + return r; +} + + +static int piv_match_card_continued(sc_card_t *card) +{ + int i; + int type = -1; + piv_private_data_t *priv = NULL; + int saved_type = card->type; /* Since we send an APDU, the card's logout function may be called... * however it may be in dirty memory */ @@ -2930,6 +2998,7 @@ case SC_CARD_TYPE_PIV_II_HIST: case SC_CARD_TYPE_PIV_II_NEO: case SC_CARD_TYPE_PIV_II_YUBIKEY4: + case SC_CARD_TYPE_PIV_II_GI_DE: type = card->type; break; default: @@ -2953,24 +3022,35 @@ !(memcmp(card->reader->atr_info.hist_bytes, "Yubikey", 7))) { type = SC_CARD_TYPE_PIV_II_NEO; } - else if (card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */ - p = card->reader->atr_info.hist_bytes; - pe = p + card->reader->atr_info.hist_bytes_len; - p++; /* skip 0x80u byte */ - while (p < pe && type == -1) { - j = *p & 0x0fu; /* length */ - if ((*p++ & 0xf0u) == 0xf0u) { /*looking for 15 */ - if ((p + j) <= pe) { - for (k = 0; piv_aids[k].len_long != 0; k++) { - if (j == piv_aids[k].len_long - && !memcmp(p, piv_aids[k].value,j)) { - type = SC_CARD_TYPE_PIV_II_HIST; - break; - } - } + /* + * https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp1239.pdf + * lists 2 ATRS with historical bytes: + * 73 66 74 65 2D 63 64 30 38 30 + * 73 66 74 65 20 63 64 31 34 34 + * will check for 73 66 74 65 + */ + else if (card->reader->atr_info.hist_bytes_len >= 4 + && !(memcmp(card->reader->atr_info.hist_bytes, "sfte", 4))) { + type = SC_CARD_TYPE_PIV_II_GI_DE; + } + + else if (card->reader->atr_info.hist_bytes_len > 0 + && card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */ + size_t datalen; + const u8 *data = sc_compacttlv_find_tag(card->reader->atr_info.hist_bytes + 1, + card->reader->atr_info.hist_bytes_len - 1, + 0xF0, &datalen); + + if (data != NULL) { + int k; + + for (k = 0; piv_aids[k].len_long != 0; k++) { + if (datalen == piv_aids[k].len_long + && !memcmp(data, piv_aids[k].value, datalen)) { + type = SC_CARD_TYPE_PIV_II_HIST; + break; } } - p += j; } } } @@ -2978,11 +3058,7 @@ type = SC_CARD_TYPE_PIV_II_GENERIC; } - /* Detect by selecting applet */ - i = piv_find_aid(card, &aidfile); - - if (i < 0) - return 0; /* don't match. Does not have a PIV applet. */ + /* allocate and init basic fields */ priv = calloc(1, sizeof(piv_private_data_t)); @@ -2992,45 +3068,99 @@ if (card->type == -1) card->type = type; - card->drv_data = priv; - priv->aid_file = sc_file_new(); + card->drv_data = priv; /* will free if no match, or pass on to piv_init */ priv->selected_obj = -1; priv->pin_preference = 0x80; /* 800-73-3 part 1, table 3 */ priv->logged_in = SC_PIN_STATE_UNKNOWN; priv->tries_left = 10; /* will assume OK at start */ + priv->pstate = PIV_STATE_MATCH; - /* Some objects will only be present if Histroy object says so */ + /* Some objects will only be present if History object says so */ for (i=0; i < PIV_OBJ_LAST_ENUM -1; i++) if(piv_objects[i].flags & PIV_OBJECT_NOT_PRESENT) priv->obj_cache[i].flags |= PIV_OBJ_CACHE_NOT_PRESENT; + sc_lock(card); + + /* + * detect if active AID is PIV. NIST 800-73 says Only one PIV application per card + * and PIV must be the default application + * This can avoid doing doing a select_aid and losing the login state on some cards + * We may get interference on some cards by other drivers trying SELECT_AID before + * we get to see if PIV application is still active. + * putting PIV driver first might help. + * This may fail if the wrong AID is active + */ + i = piv_find_discovery(card); + + if (i < 0) { + /* Detect by selecting applet */ + i = piv_find_aid(card); + } + + if (i >= 0) { + /* + * We now know PIV AID is active, test DISCOVERY object + * Some CAC cards with PIV don't support DISCOVERY and return + * SC_ERROR_INCORRECT_PARAMETERS. Any error other then + * SC_ERROR_FILE_NOT_FOUND means we cannot use discovery + * to test for active AID. + */ + int i7e = piv_find_discovery(card); + + if (i7e != 0 && i7e != SC_ERROR_FILE_NOT_FOUND) { + priv->card_issues |= CI_DISCOVERY_USELESS; + priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; + } + } + + if (i < 0) { + /* don't match. Does not have a PIV applet. */ + sc_unlock(card); + piv_finish(card); + card->type = saved_type; + return 0; + } + + /* Matched, caller will use or free priv and sc_lock as needed */ + priv->pstate=PIV_STATE_INIT; return 1; /* match */ } static int piv_init(sc_card_t *card) { - int r; - piv_private_data_t * priv = PIV_DATA(card); + int r = 0; + piv_private_data_t * priv = NULL; sc_apdu_t apdu; unsigned long flags; unsigned long ext_flags; - u8 neo_version_buf[3]; + u8 yubico_version_buf[3]; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + /* continue the matching get a lock and the priv */ + r = piv_match_card_continued(card); + if (r != 1) { + sc_log(card->ctx,"piv_match_card_continued failed"); + piv_finish(card); + /* tell sc_connect_card to try other drivers */ + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); + } + + priv = PIV_DATA(card); - /* can not force the PIV driver to use non-PIV cards as tested in piv_card_match */ + /* can not force the PIV driver to use non-PIV cards as tested in piv_card_match_continued */ if (!priv || card->type == -1) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NO_CARD_SUPPORT); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); sc_log(card->ctx, "Max send = %"SC_FORMAT_LEN_SIZE_T"u recv = %"SC_FORMAT_LEN_SIZE_T"u card->type = %d", card->max_send_size, card->max_recv_size, card->type); card->cla = 0x00; if(card->name == NULL) - card->name = "PIV-II card"; + card->name = card->driver->name; /* * Set card_issues based on card type either set by piv_match_card or by opensc.conf @@ -3043,48 +3173,63 @@ apdu.lc = 0; apdu.data = NULL; apdu.datalen = 0; - apdu.resp = neo_version_buf; - apdu.resplen = sizeof(neo_version_buf); + apdu.resp = yubico_version_buf; + apdu.resplen = sizeof(yubico_version_buf); apdu.le = apdu.resplen; r = sc_transmit_apdu(card, &apdu); - priv->neo_version = (neo_version_buf[0]<<16) | (neo_version_buf[1] <<8) | neo_version_buf[2]; - sc_log(card->ctx, "NEO card->type=%d, r=0x%08x version=0x%08x", card->type, r, priv->neo_version); + priv->yubico_version = (yubico_version_buf[0]<<16) | (yubico_version_buf[1] <<8) | yubico_version_buf[2]; + sc_log(card->ctx, "Yubico card->type=%d, r=0x%08x version=0x%08x", card->type, r, priv->yubico_version); break; } /* - * set card_issues flags based card->type and new versions - * YubiKey NEO and Ybuikey 4 have PIV applets, with compliance issues - * with the the NIST 800-73-3 specs The OpenSC developers do not have - * access to the different versions the NEO and 4, so it is a best - * if using a protected object can be use to test verify state. - * TODO use NEO version numbers to set the flags. Allows for finer control - * but needs input from Yubico or users. + * Set card_issues flags based card->type and version numbers if available. + * + * YubiKey NEO, Yubikey 4 and other devices with PIV applets, have compliance + * issues with the NIST 800-73-3 specs. The OpenSC developers do not have + * access to all the different devices or versions of the devices. + * Vendor and user input is welcome on any compliance issues. + * + * For the Yubico devices The assumption is also made that if a bug is + * fixed in a Yubico version that means it is fixed on both NEO and Yubikey 4. + * + * The flags CI_CANT_USE_GETDATA_FOR_STATE and CI_DISCOVERY_USELESS + * may be set earlier or later then in the following code. */ switch(card->type) { case SC_CARD_TYPE_PIV_II_NEO: - priv->card_issues = CI_NO_EC384 + priv->card_issues |= CI_NO_EC384 | CI_VERIFY_630X - | CI_VERIFY_LC0_FAIL | CI_OTHER_AID_LOSE_STATE | CI_LEAKS_FILE_NOT_FOUND | CI_NFC_EXPOSE_TOO_MUCH; + if (priv->yubico_version < 0x00040302) + priv->card_issues |= CI_VERIFY_LC0_FAIL; break; case SC_CARD_TYPE_PIV_II_YUBIKEY4: - priv->card_issues = CI_VERIFY_LC0_FAIL - | CI_OTHER_AID_LOSE_STATE + priv->card_issues |= CI_OTHER_AID_LOSE_STATE | CI_LEAKS_FILE_NOT_FOUND; + if (priv->yubico_version < 0x00040302) + priv->card_issues |= CI_VERIFY_LC0_FAIL; break; case SC_CARD_TYPE_PIV_II_HIST: - priv->card_issues = 0; + priv->card_issues |= 0; + break; + + case SC_CARD_TYPE_PIV_II_GI_DE: + priv->card_issues |= CI_VERIFY_LC0_FAIL + | CI_PIV_AID_LOSE_STATE + | CI_OTHER_AID_LOSE_STATE;; + /* TODO may need more research */ break; case SC_CARD_TYPE_PIV_II_GENERIC: - priv->card_issues = CI_VERIFY_LC0_FAIL + priv->card_issues |= CI_VERIFY_LC0_FAIL | CI_OTHER_AID_LOSE_STATE; + /* TODO may need more research */ break; default: @@ -3103,7 +3248,7 @@ flags = SC_ALGORITHM_RSA_RAW; - _sc_card_add_rsa_alg(card, 1024, flags, 0); /* manditory */ + _sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */ _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ @@ -3121,14 +3266,17 @@ * 800-73-3 cards may have a history object and/or a discovery object * We want to process them now as this has information on what * keys and certs the card has and how the pin might be used. + * If they fail, ignore it there are optional and introduced in + * NIST 800-73-3 and NIST 800-73-2 so some older cards may + * not handle the request. */ - r = piv_process_history(card); + piv_process_history(card); - r = piv_process_discovery(card); + piv_process_discovery(card); - if (r > 0) - r = 0; - LOG_FUNC_RETURN(card->ctx, r); + priv->pstate=PIV_STATE_NORMAL; + sc_unlock(card) ; /* obtained in piv_match */ + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -3145,7 +3293,16 @@ if (priv->pin_cmd_verify) { priv->pin_cmd_verify_sw1 = sw1; priv->pin_cmd_verify_sw2 = sw2; + } else { + /* a command has completed and it is not verify */ + /* If we are in a context_specific sequence, unlock */ + if (priv->context_specific) { + sc_log(card->ctx,"Clearing CONTEXT_SPECIFIC lock"); + priv->context_specific = 0; + sc_unlock(card); + } } + if (priv->card_issues & CI_VERIFY_630X) { /* Handle the Yubikey NEO or any other PIV card which returns in response to a verify @@ -3192,7 +3349,7 @@ * If we can't determine the security state from this process, * set card_issues CI_CANT_USE_GETDATA_FOR_STATE * and return SC_ERROR_PIN_CODE_INCORRECT - * The curcomvention is to add a dummy Printed Info object in the card. + * The circumvention is to add a dummy Printed Info object in the card. * so we will have an object to test. * * We save the object's number to use in the future. @@ -3274,6 +3431,16 @@ data->pin1.tries_left = priv->tries_left; if (tries_left) *tries_left = priv->tries_left; + + /* + * If called to check on the login state for a context specific login + * return not logged in. Needed because of logic in e6f7373ef066 + */ + if (data->pin_type == SC_AC_CONTEXT_SPECIFIC) { + data->pin1.logged_in = 0; + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + if (priv->logged_in == SC_PIN_STATE_LOGGED_IN) { /* Avoid status requests when the user is logged in to handle NIST * 800-73-4 Part 2: @@ -3287,21 +3454,41 @@ } } + /* + * If this was for a CKU_CONTEXT_SPECFIC login, lock the card one more time. + * to avoid any interference from other applications. + * Sc_unlock will be called at a later time after the next card command + * that should be a crypto operation. If its not then it is a error by the + * calling application. + */ + if (data->cmd == SC_PIN_CMD_VERIFY && data->pin_type == SC_AC_CONTEXT_SPECIFIC) { + priv->context_specific = 1; + sc_log(card->ctx,"Starting CONTEXT_SPECIFIC verify"); + sc_lock(card); + } + priv->pin_cmd_verify = 1; /* tell piv_check_sw its a verify to save sw1, sw2 */ r = iso_drv->ops->pin_cmd(card, data, tries_left); priv->pin_cmd_verify = 0; + /* if verify failed, release the lock */ + if (data->cmd == SC_PIN_CMD_VERIFY && r < 0 && priv->context_specific) { + sc_log(card->ctx,"Clearing CONTEXT_SPECIFIC"); + priv->context_specific = 0; + sc_unlock(card); + } + /* if access to applet is know to be reset by other driver we select_aid and try again */ if ( priv->card_issues & CI_OTHER_AID_LOSE_STATE && priv->pin_cmd_verify_sw1 == 0x6DU) { sc_log(card->ctx, "AID may be lost doing piv_find_aid and retry pin_cmd"); - r = piv_find_aid(card, priv->aid_file); /* return not tested */ + piv_find_aid(card); priv->pin_cmd_verify = 1; /* tell piv_check_sw its a verify to save sw1, sw2 */ r = iso_drv->ops->pin_cmd(card, data, tries_left); priv->pin_cmd_verify = 0; } - /* If verify worked, we are loged_in */ + /* If verify worked, we are logged_in */ if (data->cmd == SC_PIN_CMD_VERIFY) { if (r >= 0) priv->logged_in = SC_PIN_STATE_LOGGED_IN; @@ -3355,21 +3542,63 @@ } +/* + * Called when a sc_lock gets a reader lock and PCSC SCardBeginTransaction + * If SCardBeginTransaction may pass back tha a card reset was seen since + * the last transaction completed. + * There may have been one or more resets, by other card drivers in different + * processes, and they may have taken action already + * and changed the AID and or may have sent a VERIFY with PIN + * So test the state of the card. + * this is very similar to what the piv_match routine does, + */ + static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) { int r = 0; - u8 temp[2000]; + u8 temp[256]; size_t templen = sizeof(temp); piv_private_data_t * priv = PIV_DATA(card); /* may be null */ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - if (was_reset > 0) { - if (priv) - priv->logged_in = SC_PIN_STATE_UNKNOWN; - r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); + /* We have a PCSC transaction and sc_lock */ + if (priv == NULL || priv->pstate == PIV_STATE_MATCH) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + priv ? "PIV_STATE_MATCH" : "priv==NULL"); + r = 0; /* do nothing, piv_match will take care of it */ + goto err; + } + + /* make sure our application is active */ + + /* first see if AID is active AID by reading discovery object '7E' */ + /* If not try selecting AID */ + + /* but if card does not support DISCOVERY object we can not use it */ + if (priv->card_issues & CI_DISCOVERY_USELESS) { + r = SC_ERROR_NO_CARD_SUPPORT; + } else { + r = piv_find_discovery(card); + } + + if (r < 0) { + if (was_reset > 0 || !(priv->card_issues & CI_PIV_AID_LOSE_STATE)) { + r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); + } else { + r = 0; /* cant do anything with this card, hope there was no interference */ + } } + if (r < 0) /* bad error return will show up in sc_lock as error*/ + goto err; + + if (was_reset > 0) + priv->logged_in = SC_PIN_STATE_UNKNOWN; + + r = 0; + +err: LOG_FUNC_RETURN(card->ctx, r); } diff -Nru opensc-0.17.0/src/libopensc/card-rtecp.c opensc-0.19.0/src/libopensc/card-rtecp.c --- opensc-0.17.0/src/libopensc/card-rtecp.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-rtecp.c 2018-09-13 11:47:21.000000000 +0000 @@ -41,7 +41,7 @@ NULL, 0, NULL }; -static struct sc_atr_table rtecp_atrs[] = { +static const struct sc_atr_table rtecp_atrs[] = { /* Rutoken ECP */ { "3B:8B:01:52:75:74:6F:6B:65:6E:20:45:43:50:A0", NULL, "Rutoken ECP", SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, @@ -275,7 +275,7 @@ set_acl_from_sec_attr(card, file); else r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - if (r) + if (r && !file_out) sc_file_free(file); else { diff -Nru opensc-0.17.0/src/libopensc/card-rutoken.c opensc-0.19.0/src/libopensc/card-rutoken.c --- opensc-0.17.0/src/libopensc/card-rutoken.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-rutoken.c 2018-09-13 11:47:21.000000000 +0000 @@ -84,7 +84,7 @@ NULL, 0, NULL }; -static struct sc_atr_table rutoken_atrs[] = { +static const struct sc_atr_table rutoken_atrs[] = { { "3b:6f:00:ff:00:56:72:75:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv Rutoken S */ { "3b:6f:00:ff:00:56:75:61:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv uaToken S */ { NULL, NULL, NULL, 0, 0, NULL } @@ -132,6 +132,10 @@ ret = token_init(card, "uaToken S card"); else ret = token_init(card, "Rutoken S card"); + + if (ret != SC_SUCCESS) { + ret = SC_ERROR_INVALID_CARD; + } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); } @@ -358,7 +362,6 @@ u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; sc_file_t *file = NULL; size_t pathlen; - u8 t0, t1; int ret; assert(card && card->ctx); @@ -428,15 +431,6 @@ if (apdu.resplen > 1 && apdu.resplen >= (size_t)apdu.resp[1] + 2) { ret = card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]); - if (ret == SC_SUCCESS) - { - t0 = file->id & 0xFF; - t1 = (file->id >> 8) & 0xFF; - file->id = (t0 << 8) | t1; - t0 = file->size & 0xFF; - t1 = (file->size >> 8) & 0xFF; - file->size = (t0 << 8) | t1; - } } if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t)) set_acl_from_sec_attr(card, file); @@ -452,6 +446,33 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); } +static int rutoken_process_fci(struct sc_card *card, sc_file_t *file, + const unsigned char *buf, size_t buflen) +{ + size_t taglen; + int ret; + const unsigned char *tag; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + ret = iso_ops->process_fci(card, file, buf, buflen); + if (ret == SC_SUCCESS) + { + /* Rutoken S returns buffers in little-endian. */ + /* Set correct file id. */ + file->id = ((file->id & 0xFF) << 8) | ((file->id >> 8) & 0xFF); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " file identifier: 0x%04X", file->id); + /* Determine file size. */ + tag = sc_asn1_find_tag(card->ctx, buf, buflen, 0x80, &taglen); + /* Rutoken S always returns 2 bytes. */ + if (tag != NULL && taglen == 2) + { + file->size = (tag[1] << 8) | tag[0]; + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", file->size); + } + } + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); +} + static int rutoken_construct_fci(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen) { @@ -925,7 +946,8 @@ apdu.cse = SC_APDU_CASE_2_SHORT; break; case select_next: - apdu.p2 = 0x02; + apdu.p2 = 0x02; + /* fall through */ case select_by_id: data[0] = pInfo->DoId; apdu.data = data; @@ -1115,33 +1137,25 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); } -static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count) +static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t len) { - sc_apdu_t apdu; - u8 rbuf[32]; - size_t n; - int ret = SC_SUCCESS; /* if count == 0 */ + unsigned char rbuf[32]; + size_t out_len; + int r; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); - apdu.le = sizeof(rbuf); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); + LOG_FUNC_CALLED(card->ctx); - while (count > 0) - { - ret = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed"); - ret = sc_check_sw(card, apdu.sw1, apdu.sw2); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Get challenge failed"); - if (apdu.resplen != sizeof(rbuf)) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN); - n = count < sizeof(rbuf) ? count : sizeof(rbuf); - memcpy(rnd, rbuf, n); - count -= n; - rnd += n; + r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); + + if (len < (size_t) r) { + out_len = len; + } else { + out_len = (size_t) r; } - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret); + memcpy(rnd, rbuf, out_len); + + LOG_FUNC_RETURN(card->ctx, out_len); } static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial) @@ -1285,7 +1299,7 @@ rutoken_ops.list_files = rutoken_list_files; rutoken_ops.check_sw = rutoken_check_sw; rutoken_ops.card_ctl = rutoken_card_ctl; - /* process_fci */ + rutoken_ops.process_fci = rutoken_process_fci; rutoken_ops.construct_fci = rutoken_construct_fci; rutoken_ops.pin_cmd = NULL; diff -Nru opensc-0.17.0/src/libopensc/card-sc-hsm.c opensc-0.19.0/src/libopensc/card-sc-hsm.c --- opensc-0.17.0/src/libopensc/card-sc-hsm.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-sc-hsm.c 2018-09-13 11:47:21.000000000 +0000 @@ -60,70 +60,72 @@ /* Known ATRs for SmartCard-HSMs */ -static struct sc_atr_table sc_hsm_atrs[] = { +static const struct sc_atr_table sc_hsm_atrs[] = { /* standard version */ {"3B:FE:18:00:00:81:31:FE:45:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:FA", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL}, {"3B:8E:80:01:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:18", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL}, + {"3B:DE:18:FF:81:91:FE:1F:C3:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:1C", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL}, + {"3B:80:80:01:01", NULL, NULL, SC_CARD_TYPE_SC_HSM_SOC, 0, NULL}, // SoC Sample Card { "3B:84:80:01:47:6f:49:44:00", "FF:FF:FF:FF:FF:FF:FF:FF:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:85:80:01:47:6f:49:44:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:86:80:01:47:6f:49:44:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:87:80:01:47:6f:49:44:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:88:80:01:47:6f:49:44:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:89:80:01:47:6f:49:44:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8a:80:01:47:6f:49:44:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8b:80:01:47:6f:49:44:00:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8c:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8d:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8e:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, { "3B:8f:80:01:47:6f:49:44:00:00:00:00:00:00:00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00:00:00", - "GoID", SC_CARD_TYPE_SC_HSM_SOC, 0, NULL + "GoID", SC_CARD_TYPE_SC_HSM_GOID, 0, NULL }, {NULL, NULL, NULL, 0, 0, NULL} }; @@ -190,7 +192,7 @@ return rv; } - if ((in_path->value[0] == 0x3F) && (in_path->value[1] == 0x00)) { + 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 if (in_path->len == 2) { file = sc_file_new(); @@ -225,20 +227,49 @@ +static int sc_hsm_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len) +{ + LOG_FUNC_CALLED(card->ctx); + + if (len > 1024) { + len = 1024; + } + + LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len)); +} + + + static int sc_hsm_match_card(struct sc_card *card) { sc_path_t path; - int i, r; + int i, r, type = 0; + sc_file_t *file = NULL; - i = _sc_match_atr(card, sc_hsm_atrs, &card->type); - if (i >= 0) + i = _sc_match_atr(card, sc_hsm_atrs, &type); + if (i >= 0 && type != SC_CARD_TYPE_SC_HSM_SOC) { + card->type = type; return 1; + } 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 = sc_hsm_select_file(card, &path, &file); LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application"); - card->type = SC_CARD_TYPE_SC_HSM; + // Validate that card returns a FCP with a proprietary tag 85 with value longer than 2 byte (Fixes #1377) + if (file != NULL) { + i = file->prop_attr_len; + sc_file_free(file); + if (i < 2) { + return 0; + } + } + + if (type == SC_CARD_TYPE_SC_HSM_SOC) { + card->type = SC_CARD_TYPE_SC_HSM_SOC; + } else { + card->type = SC_CARD_TYPE_SC_HSM; + } return 1; } @@ -284,7 +315,9 @@ }; /* Select MinBioClient */ +#ifdef ENABLE_SM sc_sm_stop(card); +#endif sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C); apdu.data = minBioClient_aid.value; apdu.datalen = minBioClient_aid.len; @@ -303,30 +336,62 @@ 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"); + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + /* 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"); + /* 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"); + /* 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"); + } else { +#ifdef ENABLE_SM + unsigned sm_mode = card->sm_ctx.sm_mode; +#endif + + /* verify PIN */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x85); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed"); + +#ifdef ENABLE_SM + /* temporary disable SM, change reference data does not reach the applet */ + card->sm_ctx.sm_mode = SM_MODE_NONE; +#endif + + /* change PIN */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x24, 0x01, 0x85); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); +#ifdef ENABLE_SM + /* restore SM if possible */ + card->sm_ctx.sm_mode = sm_mode; +#endif + 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"); + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + /* 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; } @@ -338,6 +403,10 @@ sc_path_t path; int r; + if (card->type == SC_CARD_TYPE_SC_HSM_GOID) { + return SC_ERROR_NOT_SUPPORTED; + } + /* Select MinBioClient */ r = sc_hsm_soc_select_minbioclient(card); LOG_TEST_RET(card->ctx, r, "Could not select MinBioClient application"); @@ -373,19 +442,24 @@ 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; + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + 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 */ + 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); + if (card->type == SC_CARD_TYPE_SC_HSM_GOID) { + apdu.cla = 0x80; + } apdu.resp = rbuf; apdu.resplen = sizeof rbuf; r = sc_transmit_apdu(card, &apdu); @@ -402,6 +476,7 @@ +#ifdef ENABLE_SM #ifdef ENABLE_OPENPACE #include "sm/sm-eac.h" #include @@ -498,7 +573,7 @@ goto err; } EVP_PKEY_free(ctx->ca_ctx->ka_ctx->key); - CRYPTO_add(&ctx->ta_ctx->pub_key->references, 1, CRYPTO_LOCK_EVP_PKEY); + EVP_PKEY_up_ref(ctx->ta_ctx->pub_key); ctx->ca_ctx->ka_ctx->key = ctx->ta_ctx->pub_key; /* generate keys for CA */ @@ -524,6 +599,7 @@ return SC_ERROR_NOT_SUPPORTED; } #endif +#endif @@ -533,7 +609,9 @@ sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; sc_apdu_t apdu; u8 cmdbuff[16]; +#ifdef ENABLE_SM u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; +#endif int r; int cmd = data->cmd; size_t pin2_len = data->pin2.len; @@ -558,16 +636,32 @@ return sc_hsm_soc_unblock(card, data, tries_left); } +#ifdef ENABLE_SM /* For contactless cards always establish a secure channel before PIN * verification. Also, Session PIN generation requires SM. */ - if ((card->type == SC_CARD_TYPE_SC_HSM_SOC || card->reader->uid.len - || cmd == SC_PIN_CMD_GET_SESSION_PIN) - && (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 ((card->type == SC_CARD_TYPE_SC_HSM_SOC + || card->type == SC_CARD_TYPE_SC_HSM_GOID + || card->reader->uid.len || cmd == SC_PIN_CMD_GET_SESSION_PIN) + && (data->cmd != SC_PIN_CMD_GET_INFO)) { + struct sc_pin_cmd_data check_sm_pin_data; + memset(&check_sm_pin_data, 0, sizeof(check_sm_pin_data)); + check_sm_pin_data.cmd = SC_PIN_CMD_GET_INFO; + check_sm_pin_data.pin_type = data->pin_type; + check_sm_pin_data.pin_reference = data->pin_reference; + + r = SC_ERROR_NOT_ALLOWED; + if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT) { + /* check if the existing SM channel is still valid */ + r = sc_pin_cmd(card, &check_sm_pin_data, NULL); + } + if (r == SC_ERROR_ASN1_OBJECT_NOT_FOUND || r == SC_ERROR_NOT_ALLOWED) { + /* need to establish a new SM channel */ + LOG_TEST_RET(card->ctx, + sc_hsm_perform_chip_authentication(card), + "Could not perform chip authentication"); + } } +#endif if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) && (data->cmd == SC_PIN_CMD_VERIFY) @@ -604,6 +698,7 @@ data->apdu = &apdu; } +#ifdef ENABLE_SM 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 */ @@ -612,6 +707,7 @@ apdu.resplen = sizeof rbuf; data->apdu = &apdu; } +#endif data->pin1.offset = 5; data->pin1.length_offset = 4; @@ -627,11 +723,17 @@ data->cmd = SC_PIN_CMD_GET_SESSION_PIN; if (data->pin_reference == 0x81) { u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; +#ifdef ENABLE_SM 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); } +#else + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Session PIN generation only supported in SM"); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +#endif sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x5A, 0x01, data->pin_reference); apdu.cla = 0x80; apdu.resp = recvbuf; @@ -669,7 +771,9 @@ 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)); +#ifdef ENABLE_SM sc_sm_stop(card); +#endif sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); @@ -746,15 +850,15 @@ *p++ = idx & 0xFF; *p++ = 0x53; if (count < 128) { - *p++ = count; + *p++ = (u8) count; len = 6; } else if (count < 256) { *p++ = 0x81; - *p++ = count; + *p++ = (u8) count; len = 7; } else { *p++ = 0x82; - *p++ = count >> 8; + *p++ = (count >> 8) & 0xFF; *p++ = count & 0xFF; len = 8; } @@ -882,6 +986,8 @@ } else { priv->algorithm = ALGO_RSA_PKCS1; } + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) { + priv->algorithm = ALGO_RSA_PSS; } else { if (env->operation == SC_SEC_OPERATION_DECIPHER) { priv->algorithm = ALGO_RSA_DECRYPT; @@ -936,8 +1042,12 @@ fieldsizebytes = 32; } else if (datalen <= 90) { // 320 bit curve = 40 * 2 + 10 byte maximum DER signature fieldsizebytes = 40; - } else { + } else if (datalen <= 106) { // 384 bit curve = 48 * 2 + 10 byte maximum DER signature + fieldsizebytes = 48; + } else if (datalen <= 138) { // 512 bit curve = 64 * 2 + 10 byte maximum DER signature fieldsizebytes = 64; + } else { + fieldsizebytes = 66; } sc_log(card->ctx, @@ -990,8 +1100,7 @@ { int r; sc_apdu_t apdu; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 rbuf[514]; sc_hsm_private_data_t *priv; if (card == NULL || data == NULL || out == NULL) { @@ -1003,19 +1112,13 @@ LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); } - // check if datalen exceeds the buffer size - if (datalen > SC_MAX_APDU_BUFFER_SIZE) { - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - } - - sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x68, priv->env->key_ref[0], priv->algorithm); + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x68, priv->env->key_ref[0], priv->algorithm); apdu.cla = 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); - apdu.le = 256; + apdu.le = 512; - memcpy(sbuf, data, datalen); - apdu.data = sbuf; + apdu.data = data; apdu.lc = datalen; apdu.datalen = datalen; r = sc_transmit_apdu(card, &apdu); @@ -1045,7 +1148,7 @@ int r; size_t len; sc_apdu_t apdu; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 rbuf[514]; sc_hsm_private_data_t *priv; if (card == NULL || crgram == NULL || out == NULL) { @@ -1054,11 +1157,11 @@ LOG_FUNC_CALLED(card->ctx); priv = (sc_hsm_private_data_t *) card->drv_data; - sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x62, priv->env->key_ref[0], priv->algorithm); + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x62, priv->env->key_ref[0], priv->algorithm); apdu.cla = 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); - apdu.le = 256; + apdu.le = 512; apdu.data = (u8 *)crgram; apdu.lc = crgram_len; @@ -1130,7 +1233,7 @@ int r; size_t tilen; sc_apdu_t apdu; - u8 ibuff[50], *p; + u8 ibuff[50+0xFF], *p; LOG_FUNC_CALLED(card->ctx); @@ -1140,8 +1243,11 @@ memcpy(p, params->options, 2); p += 2; + if (params->user_pin_len > 0xFF) { + return SC_ERROR_INVALID_ARGUMENTS; + } *p++ = 0x81; // User PIN - *p++ = params->user_pin_len; + *p++ = (u8) params->user_pin_len; memcpy(p, params->user_pin, params->user_pin_len); p += params->user_pin_len; @@ -1250,7 +1356,7 @@ { sc_context_t *ctx = card->ctx; sc_apdu_t apdu; - u8 data[MAX_EXT_APDU_LENGTH]; + u8 data[1500]; int r; LOG_FUNC_CALLED(card->ctx); @@ -1421,7 +1527,7 @@ static int sc_hsm_generate_keypair(sc_card_t *card, sc_cardctl_sc_hsm_keygen_info_t *keyinfo) { - u8 rbuf[1024]; + u8 rbuf[1200]; int r; sc_apdu_t apdu; @@ -1484,12 +1590,12 @@ static int sc_hsm_init(struct sc_card *card) { -#ifdef _WIN32 +#if defined(ENABLE_OPENPACE) && defined(_WIN32) char expanded_val[PATH_MAX]; size_t expanded_len = PATH_MAX; #endif int flags,ext_flags; - sc_file_t *file; + sc_file_t *file = NULL; sc_path_t path; sc_hsm_private_data_t *priv = card->drv_data; @@ -1502,11 +1608,13 @@ card->drv_data = priv; } - flags = SC_ALGORITHM_RSA_RAW|SC_ALGORITHM_ONBOARD_KEY_GEN; + flags = SC_ALGORITHM_RSA_RAW|SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_ONBOARD_KEY_GEN; _sc_card_add_rsa_alg(card, 1024, flags, 0); _sc_card_add_rsa_alg(card, 1536, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); + _sc_card_add_rsa_alg(card, 3072, flags, 0); + _sc_card_add_rsa_alg(card, 4096, flags, 0); flags = SC_ALGORITHM_ECDSA_RAW| SC_ALGORITHM_ECDH_CDH_RAW| @@ -1525,19 +1633,25 @@ _sc_card_add_ec_alg(card, 224, flags, ext_flags, NULL); _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); _sc_card_add_ec_alg(card, 320, flags, ext_flags, NULL); + _sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL); + _sc_card_add_ec_alg(card, 512, flags, ext_flags, NULL); + _sc_card_add_ec_alg(card, 521, flags, ext_flags, NULL); 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) { + && file && file->prop_attr && file->prop_attr_len >= 2) { 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]; + u8 type = 0xFF; + u8 major = file->prop_attr[file->prop_attr_len - 2]; + u8 minor = file->prop_attr[file->prop_attr_len - 1]; char p00[] = "SmartCard-HSM Applet for JCOP"; char p01[] = "SmartCard-HSM Demo Applet for JCOP"; char *p = "SmartCard-HSM"; + if (file->prop_attr_len >= 3) { + type = file->prop_attr[file->prop_attr_len - 3]; + } switch (type) { case 0x00: p = p00; @@ -1554,11 +1668,12 @@ if (file->prop_attr[1] & 0x04) { card->caps |= SC_CARD_CAP_SESSION_PIN; } - sc_file_free(file); } + sc_file_free(file); card->max_send_size = 1431; // 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY - if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + if (card->type == SC_CARD_TYPE_SC_HSM_SOC + || card->type == SC_CARD_TYPE_SC_HSM_GOID) { 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 @@ -1586,7 +1701,9 @@ static int sc_hsm_finish(sc_card_t * card) { sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; +#ifdef ENABLE_SM sc_sm_stop(card); +#endif if (priv->serialno) { free(priv->serialno); } @@ -1596,10 +1713,6 @@ free(priv->EF_C_DevAut); free(priv); -#ifdef ENABLE_OPENPACE - EAC_cleanup(); -#endif - return SC_SUCCESS; } @@ -1615,6 +1728,7 @@ sc_hsm_ops = *iso_drv->ops; sc_hsm_ops.match_card = sc_hsm_match_card; sc_hsm_ops.select_file = sc_hsm_select_file; + sc_hsm_ops.get_challenge = sc_hsm_get_challenge; sc_hsm_ops.read_binary = sc_hsm_read_binary; sc_hsm_ops.update_binary = sc_hsm_update_binary; sc_hsm_ops.list_files = sc_hsm_list_files; diff -Nru opensc-0.17.0/src/libopensc/card-sc-hsm.h opensc-0.19.0/src/libopensc/card-sc-hsm.h --- opensc-0.17.0/src/libopensc/card-sc-hsm.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-sc-hsm.h 2018-09-13 11:47:21.000000000 +0000 @@ -38,6 +38,7 @@ #define ALGO_RSA_PKCS1_SHA1 0x31 /* RSA signature with SHA-1 hash and PKCS#1 V1.5 padding */ #define ALGO_RSA_PKCS1_SHA256 0x33 /* RSA signature with SHA-256 hash and PKCS#1 V1.5 padding */ +#define ALGO_RSA_PSS 0x40 /* RSA signature with external hash and PKCS#1 PSS padding*/ #define ALGO_RSA_PSS_SHA1 0x41 /* RSA signature with SHA-1 hash and PKCS#1 PSS padding */ #define ALGO_RSA_PSS_SHA256 0x43 /* RSA signature with SHA-256 hash and PKCS#1 PSS padding */ diff -Nru opensc-0.17.0/src/libopensc/card-setcos.c opensc-0.19.0/src/libopensc/card-setcos.c --- opensc-0.17.0/src/libopensc/card-setcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-setcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -33,7 +33,7 @@ #define _FINEID_BROKEN_SELECT_FLAG 1 -static struct sc_atr_table setcos_atrs[] = { +static const struct sc_atr_table setcos_atrs[] = { /* some Nokia branded SC */ { "3B:1F:11:00:67:80:42:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_GENERIC, 0, NULL }, /* RSA SecurID 3100 */ @@ -405,7 +405,7 @@ return 0; } -/* The ACs are allways for the SETEC_LCSI_ACTIVATED state, even if +/* The ACs are always for the SETEC_LCSI_ACTIVATED state, even if * we have to create the file in the SC_FILE_STATUS_INITIALISATION state. */ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file) { @@ -485,7 +485,7 @@ } } - /* Add the commands that are allways allowed */ + /* Add the commands that are always allowed */ if (bCommands_always) { bBuf[len++] = 1; bBuf[len++] = bCommands_always; @@ -499,7 +499,7 @@ else bBuf[len++] = pins[i] & 0x07; /* pin ref */ } - /* Add ommands that require the key */ + /* Add commands that require the key */ if (bCommands_key) { bBuf[len++] = 2 | 0x20; /* indicate keyNumber present */ bBuf[len++] = bCommands_key; @@ -574,8 +574,8 @@ if (card->type == SC_CARD_TYPE_SETCOS_44 || card->type == SC_CARD_TYPE_SETCOS_NIDEL || SETCOS_IS_EID_APPLET(card)) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "asymmetric keyref not supported.\n"); + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "symmetric keyref not supported.\n"); return SC_ERROR_NOT_SUPPORTED; } if (se_num > 0) { @@ -619,7 +619,7 @@ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT && !(card->type == SC_CARD_TYPE_SETCOS_NIDEL || card->type == SC_CARD_TYPE_SETCOS_FINEID_V2_2048)) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; @@ -786,17 +786,19 @@ int iOperation; const int* p_idx; - /* Check all sub-AC definitions whitin the total AC */ + /* Check all sub-AC definitions within the total AC */ while (len > 1) { /* minimum length = 2 */ - int iACLen = buf[iOffset] & 0x0F; + size_t iACLen = buf[iOffset] & 0x0F; + if (iACLen > len) + break; iPinCount = -1; /* default no pin required */ iMethod = SC_AC_NONE; /* default no authentication required */ if (buf[iOffset] & 0X80) { /* AC in adaptive coding */ /* Evaluates only the command-byte, not the optional P1/P2/Option bytes */ - int iParmLen = 1; /* command-byte is always present */ - int iKeyLen = 0; /* Encryption key is optional */ + size_t iParmLen = 1; /* command-byte is always present */ + size_t iKeyLen = 0; /* Encryption key is optional */ if (buf[iOffset] & 0x20) iKeyLen++; if (buf[iOffset+1] & 0x40) iParmLen++; @@ -806,7 +808,10 @@ /* Get KeyNumber if available */ if(iKeyLen) { - int iSC = buf[iOffset+iACLen]; + int iSC; + if (len < 1+(size_t)iACLen) + break; + iSC = buf[iOffset+iACLen]; switch( (iSC>>5) & 0x03 ){ case 0: @@ -825,11 +830,15 @@ /* Get PinNumber if available */ if (iACLen > (1+iParmLen+iKeyLen)) { /* check via total length if pin is present */ + if (len < 1+1+1+(size_t)iParmLen) + break; iKeyRef = buf[iOffset+1+1+iParmLen]; /* PTL + AM-header + parameter-bytes */ iMethod = SC_AC_CHV; } /* Convert SETCOS command to OpenSC command group */ + if (len < 1+2) + break; switch(buf[iOffset+2]){ case 0x2A: /* crypto operation */ iOperation = SC_AC_OP_CRYPTO; @@ -863,7 +872,10 @@ iPinCount = iACLen - 1; if (buf[iOffset] & 0x20) { - int iSC = buf[iOffset + iACLen]; + int iSC; + if (len < 1 + (size_t)iACLen) + break; + iSC = buf[iOffset + iACLen]; switch( (iSC>>5) & 0x03 ) { case 0: @@ -884,6 +896,8 @@ /* Pin present ? */ if ( iPinCount > 0 ) { + if (len < 1 + 2) + break; iKeyRef = buf[iOffset + 2]; /* pin ref */ iMethod = SC_AC_CHV; } @@ -1038,7 +1052,7 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - /* Setup key-generation paramters */ + /* Setup key-generation parameters */ len = 0; if (data->op_type == OP_TYPE_GENERATE) sbuf[len++] = 0x92; /* algo ID: RSA CRT */ diff -Nru opensc-0.17.0/src/libopensc/cards.h opensc-0.19.0/src/libopensc/cards.h --- opensc-0.17.0/src/libopensc/cards.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/cards.h 2018-09-13 11:47:21.000000000 +0000 @@ -95,6 +95,7 @@ SC_CARD_TYPE_STARCOS_BASE = 7000, SC_CARD_TYPE_STARCOS_GENERIC, SC_CARD_TYPE_STARCOS_V3_4, + SC_CARD_TYPE_STARCOS_V3_5, /* tcos driver */ SC_CARD_TYPE_TCOS_BASE = 8000, @@ -106,6 +107,7 @@ SC_CARD_TYPE_OPENPGP_BASE = 9000, SC_CARD_TYPE_OPENPGP_V1, SC_CARD_TYPE_OPENPGP_V2, + SC_CARD_TYPE_OPENPGP_V3, SC_CARD_TYPE_OPENPGP_GNUK, /* jcop driver */ @@ -136,6 +138,7 @@ SC_CARD_TYPE_PIV_II_HIST, SC_CARD_TYPE_PIV_II_NEO, SC_CARD_TYPE_PIV_II_YUBIKEY4, + SC_CARD_TYPE_PIV_II_GI_DE, /* MuscleApplet */ SC_CARD_TYPE_MUSCLE_BASE = 15000, @@ -200,10 +203,12 @@ SC_CARD_TYPE_IASECC_SAGEM, SC_CARD_TYPE_IASECC_AMOS, SC_CARD_TYPE_IASECC_MI, + SC_CARD_TYPE_IASECC_MI2, /* SmartCard-HSM */ SC_CARD_TYPE_SC_HSM = 26000, SC_CARD_TYPE_SC_HSM_SOC = 26001, + SC_CARD_TYPE_SC_HSM_GOID = 26002, /* Spanish DNIe card */ SC_CARD_TYPE_DNIE_BASE = 27000, diff -Nru opensc-0.17.0/src/libopensc/card-starcos.c opensc-0.19.0/src/libopensc/card-starcos.c --- opensc-0.17.0/src/libopensc/card-starcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-starcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -31,12 +31,18 @@ #include "internal.h" #include "iso7816.h" -static struct sc_atr_table starcos_atrs[] = { +static const struct sc_atr_table starcos_atrs[] = { { "3B:B7:94:00:c0:24:31:fe:65:53:50:4b:32:33:90:00:b4", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL }, { "3B:B7:94:00:81:31:fe:65:53:50:4b:32:33:90:00:d1", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL }, { "3b:b7:18:00:c0:3e:31:fe:65:53:50:4b:32:34:90:00:25", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL }, - /* STARCOS 3.4 */ { "3b:d8:18:ff:81:b1:fe:45:1f:03:80:64:04:1a:b4:03:81:05:61", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL }, + { "3b:d3:96:ff:81:b1:fe:45:1f:07:80:81:05:2d", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL }, + { "3B:9B:96:C0:0A:31:FE:45:80:67:04:1E:B5:01:00:89:4C:81:05:45", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, + { "3B:DB:96:FF:81:31:FE:45:80:67:05:34:B5:02:01:C0:A1:81:05:3C", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, + { "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:C0:81:05:02", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, + { "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:31:31:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, + { "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:30:30:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, + { "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:E0:81:05:22", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -44,7 +50,7 @@ static struct sc_card_operations *iso_ops = NULL; static struct sc_card_driver starcos_drv = { - "STARCOS SPK 2.3/2.4/3.4", + "STARCOS", "starcos", &starcos_ops, NULL, 0, NULL @@ -84,15 +90,6 @@ } \ } while (0); -#define CHECK_ONLY_SUPPORTED_V3_4(card) \ - do { \ - if ((card)->type != SC_CARD_TYPE_STARCOS_V3_4) { \ - sc_debug((card)->ctx, SC_LOG_DEBUG_NORMAL, \ - "only supported for STARCOS 3.4 cards"); \ - return SC_ERROR_NOT_SUPPORTED; \ - } \ - } while (0); - /* the starcos part */ static int starcos_match_card(sc_card_t *card) { @@ -113,7 +110,7 @@ if (ex_data == NULL) return SC_ERROR_OUT_OF_MEMORY; - card->name = "STARCOS SPK 2.3"; + card->name = "STARCOS"; card->cla = 0x00; card->drv_data = (void *)ex_data; @@ -128,8 +125,14 @@ card->caps = SC_CARD_CAP_RNG; - if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { - card->name = "STARCOS SPK 3.4"; + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) + card->name = "STARCOS 3.4"; + else + card->name = "STARCOS 3.5"; + card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; + flags |= SC_CARD_FLAG_RNG | SC_ALGORITHM_RSA_HASH_SHA224 | SC_ALGORITHM_RSA_HASH_SHA256 @@ -510,7 +513,8 @@ apdu.data = (u8*)data; apdu.datalen = 2; - if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { if (id_hi == 0x3f && id_lo == 0x0) { apdu.p1 = 0x0; apdu.p2 = 0x0; @@ -538,7 +542,9 @@ apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU re-transmit failed"); - } else if (card->type == SC_CARD_TYPE_STARCOS_V3_4 && apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) { + } else if ((card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) + && apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) { /* not a file, could be a path */ bIsDF = 1; apdu.p1 = 0x1; @@ -602,7 +608,8 @@ *file_out = file; } else { /* ok, assume we have a EF */ - if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { if (isFCP) { r = process_fcp_v3_4(card->ctx, file, apdu.resp, apdu.resplen); @@ -689,8 +696,9 @@ if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 )) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); - if (card->type != SC_CARD_TYPE_STARCOS_V3_4 || - (pathlen == 0 && card->cache.current_path.type != SC_PATH_TYPE_DF_NAME)) { + if (card->type != SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5 + || (pathlen == 0 && card->cache.current_path.type != SC_PATH_TYPE_DF_NAME)) { /* unify path (the first FID should be MF) */ if (path[0] != 0x3f || path[1] != 0x00) { @@ -715,9 +723,9 @@ && card->cache.current_path.value[i+1] == path[i+1] ) bMatch += 2; - if (card->type == SC_CARD_TYPE_STARCOS_V3_4 && - bMatch > 0 && - (size_t) bMatch < card->cache.current_path.len) { + if ((card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) + && bMatch > 0 && (size_t) bMatch < card->cache.current_path.len) { /* we're in the wrong folder, start traversing from root */ bMatch = 0; card->cache.current_path.len = 0; @@ -727,7 +735,7 @@ if ( card->cache.valid && bMatch >= 0 ) { if ( pathlen - bMatch == 2 ) - /* we are in the rigth directory */ + /* we are in the right directory */ return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out, 1); else if ( pathlen - bMatch > 2 ) { @@ -785,6 +793,17 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); } +static int starcos_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len) +{ + LOG_FUNC_CALLED(card->ctx); + + if (len > 8) { + len = 8; + } + + LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len)); +} + #define STARCOS_AC_ALWAYS 0x9f #define STARCOS_AC_NEVER 0x5f #define STARCOS_PINID2STATE(a) ((((a) & 0x0f) == 0x01) ? ((a) & 0x0f) : (0x0f - ((0x0f & (a)) >> 1))) @@ -814,9 +833,9 @@ * \param card pointer to the sc_card object * \param file pointer to the sc_file object * \param data pointer to a sc_starcos_create_data structure - * \return SC_SUCCESS if no error occured otherwise error code + * \return SC_SUCCESS if no error occurred otherwise error code * - * This function tries to create a somewhat useable Starcos spk 2.3 acl + * This function tries to create a somewhat usable Starcos spk 2.3 acl * from the OpenSC internal acl (storing the result in the supplied * sc_starcos_create_data structure). */ @@ -1060,7 +1079,7 @@ * \param file pointer to a sc_file object * \return SC_SUCCESS or error code * - * This function finishs the creation of a DF (or MF) and activates + * This function finishes the creation of a DF (or MF) and activates * the ACs. */ static int starcos_create_end(sc_card_t *card, sc_file_t *file) @@ -1150,8 +1169,7 @@ r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - /* invalidate cache */ - card->cache.valid = 0; + sc_invalidate_cache(card); if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85) /* no MF to delete, ignore error */ return SC_SUCCESS; @@ -1318,31 +1336,52 @@ p = sbuf; - if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { - if (operation != SC_SEC_OPERATION_SIGN) { - /* we only support signatures for now */ - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "not supported for STARCOS 3.4 cards"); - return SC_ERROR_NOT_SUPPORTED; \ - } - + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { if (!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) || !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || env->key_ref_len != 1) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); } - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6); /* don't know what these mean but doesn't matter as card seems to take * algorithm / cipher from PKCS#1 padding prefix */ *p++ = 0x84; *p++ = 0x01; - *p++ = 0x84; + if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) { + *p++ = *env->key_ref | 0x80; + } else { + *p++ = *env->key_ref; + } + + switch (operation) { + case SC_SEC_OPERATION_SIGN: + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6); + + /* algorithm / cipher selector? */ + *p++ = 0x89; + *p++ = 0x02; + *p++ = 0x13; + *p++ = 0x23; + break; + + case SC_SEC_OPERATION_DECIPHER: + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8); - /* algorithm / cipher selector? */ - *p++ = 0x89; - *p++ = 0x02; - *p++ = 0x13; - *p++ = 0x23; + /* algorithm / cipher selector? */ + *p++ = 0x89; + *p++ = 0x02; + *p++ = 0x11; + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) + *p++ = 0x30; + else + *p++ = 0x31; + break; + + default: + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "not supported for STARCOS 3.4 cards"); + return SC_ERROR_NOT_SUPPORTED; + } apdu.data = sbuf; apdu.datalen = p - sbuf; @@ -1365,7 +1404,7 @@ /* copy key reference, if present */ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; @@ -1490,7 +1529,8 @@ if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) { /* compute signature with the COMPUTE SIGNATURE command */ - if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { size_t tmp_len; sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, @@ -1598,6 +1638,63 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); } +static int starcos_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) +{ + if (card->type == SC_CARD_TYPE_STARCOS_V3_4 + || card->type == SC_CARD_TYPE_STARCOS_V3_5) { + int r; + size_t card_max_send_size = card->max_send_size; + size_t reader_max_send_size = card->reader->max_send_size; + int caps = card->caps; + sc_apdu_t apdu; + + u8 *sbuf = malloc(crgram_len + 1); + if (sbuf == NULL) + return SC_ERROR_OUT_OF_MEMORY; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86); + apdu.resp = out; + apdu.resplen = outlen; + apdu.le = outlen; + + sbuf[0] = 0x81; + memcpy(sbuf + 1, crgram, crgram_len); + apdu.data = sbuf; + apdu.lc = crgram_len + 1; + apdu.datalen = crgram_len + 1; + + if (sc_get_max_send_size(card) < crgram_len + 1) { + /* Starcos doesn't support chaining for PSO:DEC, so we just _hope_ + * that both, the reader and the card are able to send enough data. + * (data is prefixed with 1 byte padding content indicator) */ + card->max_send_size = crgram_len + 1; + card->reader->max_send_size = crgram_len + 1; + card->caps |= SC_CARD_CAP_APDU_EXT; + } + + r = sc_transmit_apdu(card, &apdu); + sc_mem_clear(sbuf, crgram_len + 1); + + /* reset whatever we've modified above */ + card->max_send_size = card_max_send_size; + card->reader->max_send_size = reader_max_send_size; + card->caps = caps; + + free(sbuf); + + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + LOG_FUNC_RETURN(card->ctx, apdu.resplen); + else + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); + } else { + return iso_ops->decipher(card, crgram, crgram_len, out, outlen); + } +} + static int starcos_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) { const int err_count = sizeof(starcos_errors)/sizeof(starcos_errors[0]); @@ -1635,29 +1732,46 @@ if (!serial) return SC_ERROR_INVALID_ARGUMENTS; + /* see if we have cached serial number */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; } - CHECK_NOT_SUPPORTED_V3_4(card); - /* get serial number via GET CARD DATA */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00); - apdu.cla |= 0x80; - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = 256; - apdu.lc = 0; - apdu.datalen = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) - return SC_ERROR_INTERNAL; - /* cache serial number */ - memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR)); - card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR); + + switch (card->type) { + case SC_CARD_TYPE_STARCOS_V3_4: + case SC_CARD_TYPE_STARCOS_V3_5: + card->serialnr.len = SC_MAX_SERIALNR; + r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0); + if (r < 0) { + card->serialnr.len = 0; + return r; + } + break; + + default: + /* get serial number via GET CARD DATA */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00); + apdu.cla |= 0x80; + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 256; + apdu.lc = 0; + apdu.datalen = 0; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) + return SC_ERROR_INTERNAL; + /* cache serial number */ + memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR)); + card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR); + break; + } + /* copy and return serial number */ memcpy(serial, &card->serialnr, sizeof(*serial)); + return SC_SUCCESS; } @@ -1720,15 +1834,19 @@ static int starcos_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) { - int ret; - - CHECK_ONLY_SUPPORTED_V3_4(card); + int r; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); - data->flags |= SC_PIN_CMD_NEED_PADDING; - data->pin1.encoding = SC_PIN_ENCODING_GLP; - ret = iso_ops->pin_cmd(card, data, tries_left); - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret); + switch (card->type) { + case SC_CARD_TYPE_STARCOS_V3_4: + case SC_CARD_TYPE_STARCOS_V3_5: + data->flags |= SC_PIN_CMD_NEED_PADDING; + data->pin1.encoding = SC_PIN_ENCODING_GLP; + /* fall through */ + default: + r = iso_ops->pin_cmd(card, data, tries_left); + } + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } static struct sc_card_driver * sc_get_driver(void) @@ -1742,11 +1860,13 @@ starcos_ops.init = starcos_init; starcos_ops.finish = starcos_finish; starcos_ops.select_file = starcos_select_file; + starcos_ops.get_challenge = starcos_get_challenge; starcos_ops.check_sw = starcos_check_sw; starcos_ops.create_file = starcos_create_file; starcos_ops.delete_file = NULL; starcos_ops.set_security_env = starcos_set_security_env; starcos_ops.compute_signature = starcos_compute_signature; + starcos_ops.decipher = starcos_decipher; starcos_ops.card_ctl = starcos_card_ctl; starcos_ops.logout = starcos_logout; starcos_ops.pin_cmd = starcos_pin_cmd; diff -Nru opensc-0.17.0/src/libopensc/card-tcos.c opensc-0.19.0/src/libopensc/card-tcos.c --- opensc-0.17.0/src/libopensc/card-tcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-tcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -33,17 +33,18 @@ #include "asn1.h" #include "cardctl.h" -static struct sc_atr_table tcos_atrs[] = { +static const struct sc_atr_table tcos_atrs[] = { /* Infineon SLE44 */ { "3B:BA:13:00:81:31:86:5D:00:64:05:0A:02:01:31:80:90:00:8B", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL }, /* Infineon SLE66S */ { "3B:BA:14:00:81:31:86:5D:00:64:05:14:02:02:31:80:90:00:91", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL }, /* Infineon SLE66CX320P */ { "3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL }, - /* Infoneon SLE66CX322P */ + /* Infineon SLE66CX322P */ { "3B:BA:96:00:81:31:86:5D:00:64:05:7B:02:03:31:80:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL }, /* Philips P5CT072 */ { "3B:BF:96:00:81:31:FE:5D:00:64:04:11:03:01:31:C0:73:F7:01:D0:00:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL }, + { "3B:BF:96:00:81:31:FE:5D:00:64:04:11:04:0F:31:C0:73:F7:01:D0:00:90:00:74", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL }, /* Philips P5CT080 */ { "3B:BF:B6:00:81:31:FE:5D:00:64:04:28:03:02:31:C0:73:F7:01:D0:00:90:00:67", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } @@ -342,7 +343,6 @@ sc_apdu_t apdu; sc_file_t *file=NULL; u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; - unsigned int i; int r, pathlen; assert(card != NULL && in_path != NULL); @@ -406,42 +406,7 @@ *file_out = file; file->path = *in_path; - for(i=2; i+1size=0; - for(j=0; jsize = (file->size<<8) | d[j]; - break; - case 0x82: - file->shareable = (d[0] & 0x40) ? 1 : 0; - file->ef_structure = d[0] & 7; - switch ((d[0]>>3) & 7) { - case 0: file->type = SC_FILE_TYPE_WORKING_EF; break; - case 7: file->type = SC_FILE_TYPE_DF; break; - default: - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "invalid file type %02X in file descriptor\n", d[0]); - SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED); - } - break; - case 0x83: - file->id = (d[0]<<8) | d[1]; - break; - case 0x84: - memcpy(file->name, d, len); - file->namelen = len; - break; - case 0x86: - sc_file_set_sec_attr(file, d, len); - break; - default: - if (len>0) sc_file_set_prop_attr(file, d, len); - } - } - file->magic = SC_FILE_MAGIC; + iso_ops->process_fci(card, file, apdu.resp, apdu.resplen); parse_sec_attr(card, file, file->sec_attr, file->sec_attr_len); @@ -545,7 +510,7 @@ p = sbuf; *p++=0x80; *p++=0x01; *p++=tcos3 ? 0x0A : 0x10; if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { - *p++ = (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) ? 0x83 : 0x84; + *p++ = (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) ? 0x83 : 0x84; *p++ = env->key_ref_len; memcpy(p, env->key_ref, env->key_ref_len); p += env->key_ref_len; @@ -705,33 +670,25 @@ static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) { - int r; - u8 buf[64]; - size_t len; - sc_path_t tpath; - sc_file_t *tfile = NULL; + int r; - if (!serial) return SC_ERROR_INVALID_ARGUMENTS; + if (!serial) + return SC_ERROR_INVALID_ARGUMENTS; /* see if we have cached serial number */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; } - sc_format_path("3F002F02", &tpath); - r = sc_select_file(card, &tpath, &tfile); - if (r < 0) return r; - - len = tfile->size; - sc_file_free(tfile); - if (len > sizeof(buf) || len < 12) return SC_ERROR_INTERNAL; - - r = sc_read_binary(card, 0, buf, len, 0); - if (r < 0) return r; - if (buf[0] != 0x5a || buf[1] > len - 2) return SC_ERROR_INTERNAL; - card->serialnr.len = buf[1]; - memcpy(card->serialnr.value, buf+2, buf[1]); + card->serialnr.len = sizeof card->serialnr.value; + r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0); + if (r < 0) { + card->serialnr.len = 0; + return r; + } + + /* copy and return serial number */ memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; diff -Nru opensc-0.17.0/src/libopensc/card-westcos.c opensc-0.19.0/src/libopensc/card-westcos.c --- opensc-0.17.0/src/libopensc/card-westcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/card-westcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -152,7 +152,7 @@ return iso_ops->check_sw(card, sw1, sw2); } -static struct sc_atr_table westcos_atrs[] = { +static const struct sc_atr_table westcos_atrs[] = { /* westcos 2ko */ { "3F:69:00:00:00:64:01:00:00:00:80:90:00", "ff:ff:ff:ff:ff:ff:ff:00:00:00:f0:ff:ff", NULL, 0x00, 0, NULL }, /* westcos applet */ @@ -349,7 +349,7 @@ file->ef_structure = SC_FILE_EF_CYCLIC; break; default: - type = "unknow"; + type = "unknown"; } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " type: %s\n", type); @@ -361,13 +361,7 @@ if (tag != NULL && taglen > 0 && taglen <= 16) { memcpy(file->name, tag, taglen); file->namelen = taglen; - { - char tbuf[128]; - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, - file->name, file->namelen, tbuf, sizeof(tbuf)); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - " File name: %s\n", tbuf); - } + sc_log_hex(card->ctx, " File name", file->name, file->namelen); } if (file->type == SC_FILE_TYPE_DF) { tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen); @@ -458,7 +452,7 @@ acl = sc_file_get_acl_entry(file, operation); if (acl == NULL) { - /* par defaut always */ + /* per default always */ *buf = 0xff; *buf_key = 0x00; return 0; @@ -978,7 +972,7 @@ data.pin1.data = priv_data->default_key.key_value; return sc_pin_cmd(card, &data, NULL); case SC_CARDCTL_WESTCOS_CHANGE_KEY: - if (1) { + { int lrc; u8 temp[7]; sc_changekey_t *ck = (sc_changekey_t *) ptr; diff -Nru opensc-0.17.0/src/libopensc/ctbcs.h opensc-0.19.0/src/libopensc/ctbcs.h --- opensc-0.17.0/src/libopensc/ctbcs.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/ctbcs.h 2018-09-13 11:47:21.000000000 +0000 @@ -107,7 +107,7 @@ #define CTBCS_P2_INPUT_ASTERISKS 0x02 /* Echo input as asterisks */ /* - * Tags for paramaters to input, output et al. + * Tags for parameters to input, output et al. */ #define CTBCS_TAG_PROMPT 0x50 #define CTBCS_TAG_VERIFY_CMD 0x52 @@ -143,9 +143,9 @@ */ #define CTBCS_SW1_RESET_CT_OK 0x90 /* Reset CT successful */ #define CTBCS_SW2_RESET_CT_OK 0x00 -#define CTBCS_SW1_RESET_SYNC_OK 0x90 /* Synchoronous ICC, */ +#define CTBCS_SW1_RESET_SYNC_OK 0x90 /* Synchronous ICC, */ #define CTBCS_SW2_RESET_SYNC_OK 0x00 /* reset successful */ -#define CTBCS_SW1_RESET_ASYNC_OK 0x90 /* Asynchoronous ICC, */ +#define CTBCS_SW1_RESET_ASYNC_OK 0x90 /* Asynchronous ICC, */ #define CTBCS_SW2_RESET_ASYNC_OK 0x01 /* reset successful */ #define CTBCS_SW1_RESET_ERROR 0x64 /* Reset not successful */ #define CTBCS_SW2_RESET_ERROR 0x00 @@ -153,9 +153,9 @@ /* * Return codes for Request ICC */ -#define CTBCS_SW1_REQUEST_SYNC_OK 0x90 /* Synchoronous ICC, */ +#define CTBCS_SW1_REQUEST_SYNC_OK 0x90 /* Synchronous ICC, */ #define CTBCS_SW2_REQUEST_SYNC_OK 0x00 /* reset successful */ -#define CTBCS_SW1_REQUEST_ASYNC_OK 0x90 /* Asynchoronous ICC, */ +#define CTBCS_SW1_REQUEST_ASYNC_OK 0x90 /* Asynchronous ICC, */ #define CTBCS_SW2_REQUEST_ASYNC_OK 0x01 /* reset successful */ #define CTBCS_SW1_REQUEST_NO_CARD 0x62 /* No card present */ #define CTBCS_SW2_REQUEST_NO_CARD 0x00 @@ -169,9 +169,9 @@ /* * Return codes for Eject ICC */ -#define CTBCS_SW1_EJECT_OK 0x90 /* Command succesful, */ +#define CTBCS_SW1_EJECT_OK 0x90 /* Command successful, */ #define CTBCS_SW2_EJECT_OK 0x00 -#define CTBCS_SW1_EJECT_REMOVED 0x90 /* Command succesful, */ +#define CTBCS_SW1_EJECT_REMOVED 0x90 /* Command successful, */ #define CTBCS_SW2_EJECT_REMOVED 0x01 /* Card removed */ #define CTBCS_SW1_EJECT_NOT_REMOVED 0x62 /* Card not removed */ #define CTBCS_SW2_EJECT_NOT_REMOVED 0x00 diff -Nru opensc-0.17.0/src/libopensc/ctx.c opensc-0.19.0/src/libopensc/ctx.c --- opensc-0.17.0/src/libopensc/ctx.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/ctx.c 2018-09-13 11:47:21.000000000 +0000 @@ -39,9 +39,31 @@ #include "common/libscdl.h" #include "internal.h" +static int ignored_reader(sc_context_t *ctx, sc_reader_t *reader) +{ + if (ctx != NULL && reader != NULL && reader->name != NULL) { + size_t i; + const scconf_list *list; + + for (i = 0; ctx->conf_blocks[i]; i++) { + list = scconf_find_list(ctx->conf_blocks[i], "ignored_readers"); + while (list != NULL) { + if (strstr(reader->name, list->data) != NULL) { + sc_log(ctx, "Ignoring reader \'%s\' because of \'%s\'\n", + reader->name, list->data); + return 1; + } + list = list->next; + } + } + } + + return 0; +} + int _sc_add_reader(sc_context_t *ctx, sc_reader_t *reader) { - if (reader == NULL) { + if (reader == NULL || ignored_reader(ctx, reader)) { return SC_ERROR_INVALID_ARGUMENTS; } reader->ctx = ctx; @@ -76,11 +98,9 @@ { "gpk", (void *(*)(void)) sc_get_gpk_driver }, #endif { "gemsafeV1", (void *(*)(void)) sc_get_gemsafeV1_driver }, - { "miocos", (void *(*)(void)) sc_get_miocos_driver }, { "asepcos", (void *(*)(void)) sc_get_asepcos_driver }, { "starcos", (void *(*)(void)) sc_get_starcos_driver }, { "tcos", (void *(*)(void)) sc_get_tcos_driver }, - { "jcop", (void *(*)(void)) sc_get_jcop_driver }, #ifdef ENABLE_OPENSSL { "oberthur", (void *(*)(void)) sc_get_oberthur_driver }, { "authentic", (void *(*)(void)) sc_get_authentic_driver }, @@ -98,20 +118,23 @@ #endif { "rutoken", (void *(*)(void)) sc_get_rutoken_driver }, { "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver }, - { "westcos", (void *(*)(void)) sc_get_westcos_driver }, { "myeid", (void *(*)(void)) sc_get_myeid_driver }, - { "sc-hsm", (void *(*)(void)) sc_get_sc_hsm_driver }, #if defined(ENABLE_OPENSSL) && defined(ENABLE_SM) { "dnie", (void *(*)(void)) sc_get_dnie_driver }, #endif { "masktech", (void *(*)(void)) sc_get_masktech_driver }, + { "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver }, + { "westcos", (void *(*)(void)) sc_get_westcos_driver }, -/* Here should be placed drivers that need some APDU transactions to - * recognise its cards. */ +/* Here should be placed drivers that need some APDU transactions in the + * driver's `match_card()` function. */ + /* MUSCLE card applet returns 9000 on whatever AID is selected, see + * https://github.com/JavaCardOS/MuscleCard-Applet/blob/master/musclecard/src/com/musclecard/CardEdge/CardEdge.java#L326 + * put the muscle driver first to cope with this bug. */ + { "muscle", (void *(*)(void)) sc_get_muscle_driver }, + { "sc-hsm", (void *(*)(void)) sc_get_sc_hsm_driver }, { "mcrd", (void *(*)(void)) sc_get_mcrd_driver }, { "setcos", (void *(*)(void)) sc_get_setcos_driver }, - { "muscle", (void *(*)(void)) sc_get_muscle_driver }, - { "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver }, { "PIV-II", (void *(*)(void)) sc_get_piv_driver }, { "cac", (void *(*)(void)) sc_get_cac_driver }, { "itacns", (void *(*)(void)) sc_get_itacns_driver }, @@ -129,21 +152,24 @@ { NULL, NULL } }; +static const struct _sc_driver_entry old_card_drivers[] = { + { "miocos", (void *(*)(void)) sc_get_miocos_driver }, + { "jcop", (void *(*)(void)) sc_get_jcop_driver }, + { NULL, NULL } +}; + struct _sc_ctx_options { struct _sc_driver_entry cdrv[SC_MAX_CARD_DRIVERS]; int ccount; - char *forced_card_driver; }; int -sc_ctx_win32_get_config_value(char *name_env, char *name_reg, char *name_key, - char *out, size_t *out_len) +sc_ctx_win32_get_config_value(const char *name_env, + const char *name_reg, const char *name_key, + void *out, size_t *out_len) { #ifdef _WIN32 - char temp[PATH_MAX + 1]; - char *value = NULL; - DWORD temp_len = PATH_MAX; long rc; HKEY hKey; @@ -151,9 +177,14 @@ return SC_ERROR_INVALID_ARGUMENTS; if (name_env) { - value = getenv(name_env); - if (value) - goto done; + char *value = value = getenv(name_env); + if (value) { + if (strlen(value) < *out_len) + return SC_ERROR_NOT_ENOUGH_MEMORY; + memcpy(out, value, strlen(value)); + *out_len = strlen(value); + return SC_SUCCESS; + } } if (!name_reg) @@ -164,36 +195,26 @@ rc = RegOpenKeyExA(HKEY_CURRENT_USER, name_key, 0, KEY_QUERY_VALUE, &hKey); if (rc == ERROR_SUCCESS) { - temp_len = PATH_MAX; - rc = RegQueryValueEx( hKey, name_reg, NULL, NULL, (LPBYTE) temp, &temp_len); - if ((rc == ERROR_SUCCESS) && (temp_len < PATH_MAX)) - value = temp; + DWORD len = *out_len; + rc = RegQueryValueEx(hKey, name_reg, NULL, NULL, out, &len); RegCloseKey(hKey); - } - - if (!value) { - rc = RegOpenKeyExA( HKEY_LOCAL_MACHINE, name_key, 0, KEY_QUERY_VALUE, &hKey ); if (rc == ERROR_SUCCESS) { - temp_len = PATH_MAX; - rc = RegQueryValueEx( hKey, name_reg, NULL, NULL, (LPBYTE) temp, &temp_len); - if ((rc == ERROR_SUCCESS) && (temp_len < PATH_MAX)) - value = temp; - RegCloseKey(hKey); + *out_len = len; + return SC_SUCCESS; } } -done: - if (value) { - if (strlen(value) >= *out_len) - return SC_ERROR_BUFFER_TOO_SMALL; - strcpy(out, value); - *out_len = strlen(out); - return SC_SUCCESS; + rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, name_key, 0, KEY_QUERY_VALUE, &hKey); + if (rc == ERROR_SUCCESS) { + DWORD len = *out_len; + rc = RegQueryValueEx(hKey, name_reg, NULL, NULL, out, &len); + RegCloseKey(hKey); + if (rc == ERROR_SUCCESS) { + *out_len = len; + return SC_SUCCESS; + } } - memset(out, 0, *out_len); - *out_len = 0; - return SC_ERROR_OBJECT_NOT_FOUND; #else return SC_ERROR_NOT_SUPPORTED; @@ -256,6 +277,19 @@ } } +static void add_old_drvs(struct _sc_ctx_options *opts) +{ + const struct _sc_driver_entry *lst; + int i; + + lst = old_card_drivers; + i = 0; + while (lst[i].name != NULL) { + add_drv(opts, lst[i].name); + i++; + } +} + static void set_defaults(sc_context_t *ctx, struct _sc_ctx_options *opts) { ctx->debug = 0; @@ -286,12 +320,10 @@ ctx->debug_file = NULL; } - if (ctx->reopen_log_file) { - if (!ctx->debug_filename) { - if (!filename) - filename = "stderr"; - ctx->debug_filename = strdup(filename); - } + if (!ctx->debug_filename) { + if (!filename) + filename = "stderr"; + ctx->debug_filename = strdup(filename); } if (!filename) @@ -310,25 +342,35 @@ return SC_SUCCESS; } +static void +set_drivers(struct _sc_ctx_options *opts, const scconf_list *list) +{ + const char *s_internal = "internal", *s_old = "old"; + if (list != NULL) + del_drvs(opts); + while (list != NULL) { + if (strcmp(list->data, s_internal) == 0) + add_internal_drvs(opts); + else if (strcmp(list->data, s_old) == 0) + add_old_drvs(opts); + else + add_drv(opts, list->data); + list = list->next; + } +} static int load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options *opts) { int err = 0; const scconf_list *list; - const char *val, *s_internal = "internal"; + const char *val; int debug; #ifdef _WIN32 char expanded_val[PATH_MAX]; DWORD expanded_len; #endif -#ifdef _WIN32 - ctx->reopen_log_file = 1; -#else - ctx->reopen_log_file = scconf_get_bool(block, "reopen_debug_file", 0); -#endif - debug = scconf_get_int(block, "debug", ctx->debug); if (debug > ctx->debug) ctx->debug = debug; @@ -347,10 +389,6 @@ sc_ctx_log_to_file(ctx, NULL); } - if (scconf_get_bool (block, "paranoid-memory", - ctx->flags & SC_CTX_FLAG_PARANOID_MEMORY)) - ctx->flags |= SC_CTX_FLAG_PARANOID_MEMORY; - if (scconf_get_bool (block, "disable_popups", ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS)) ctx->flags |= SC_CTX_FLAG_DISABLE_POPUPS; @@ -359,23 +397,8 @@ ctx->flags & SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER)) ctx->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER; - val = scconf_get_str(block, "force_card_driver", NULL); - if (val) { - if (opts->forced_card_driver) - free(opts->forced_card_driver); - opts->forced_card_driver = strdup(val); - } - list = scconf_find_list(block, "card_drivers"); - if (list != NULL) - del_drvs(opts); - while (list != NULL) { - if (strcmp(list->data, s_internal) == 0) - add_internal_drvs(opts); - else - add_drv(opts, list->data); - list = list->next; - } + set_drivers(opts, list); return err; } @@ -429,7 +452,7 @@ const char *(*modversion)(void) = NULL; const char *(**tmodv)(void) = &modversion; - if (name == NULL) { /* should not occurr, but... */ + if (name == NULL) { /* should not occur, but... */ sc_log(ctx, "No module specified"); return NULL; } @@ -507,11 +530,20 @@ } ent = &opts->cdrv[i]; - for (j = 0; internal_card_drivers[j].name != NULL; j++) + for (j = 0; internal_card_drivers[j].name != NULL; j++) { if (strcmp(ent->name, internal_card_drivers[j].name) == 0) { func = (struct sc_card_driver *(*)(void)) internal_card_drivers[j].func; break; } + } + if (func == NULL) { + for (j = 0; old_card_drivers[j].name != NULL; j++) { + if (strcmp(ent->name, old_card_drivers[j].name) == 0) { + func = (struct sc_card_driver *(*)(void)) old_card_drivers[j].func; + break; + } + } + } /* if not initialized assume external module */ if (func == NULL) *(void **)(tfunc) = load_dynamic_driver(ctx, &dll, ent->name); @@ -603,6 +635,8 @@ if (!strcmp(list->data, "rng")) flags = SC_CARD_FLAG_RNG; + else if (!strcmp(list->data, "keep_alive")) + flags = SC_CARD_FLAG_KEEP_ALIVE; else if (sscanf(list->data, "%x", &flags) != 1) flags = 0; @@ -635,13 +669,14 @@ memset(ctx->conf_blocks, 0, sizeof(ctx->conf_blocks)); #ifdef _WIN32 - temp_len = PATH_MAX; + temp_len = PATH_MAX-1; r = sc_ctx_win32_get_config_value("OPENSC_CONF", "ConfigFile", "Software\\OpenSC Project\\OpenSC", temp_path, &temp_len); if (r) { sc_log(ctx, "process_config_file doesn't find opensc config file. Please set the registry key."); return; } + temp_path[temp_len] = '\0'; conf_path = temp_path; #else conf_path = getenv("OPENSC_CONF"); @@ -669,6 +704,8 @@ ctx->conf = NULL; return; } + /* needs to be after the log file is known */ + sc_log(ctx, "Used configuration file '%s'", conf_path); blocks = scconf_find_blocks(ctx->conf, NULL, "app", ctx->app_name); if (blocks && blocks[0]) ctx->conf_blocks[count++] = blocks[0]; @@ -753,6 +790,7 @@ sc_context_t *ctx; struct _sc_ctx_options opts; int r; + char *driver; if (ctx_out == NULL || parm == NULL) return SC_ERROR_INVALID_ARGUMENTS; @@ -776,6 +814,7 @@ set_defaults(ctx, &opts); if (0 != list_init(&ctx->readers)) { + sc_release_context(ctx); return SC_ERROR_OUT_OF_MEMORY; } list_attributes_seeker(&ctx->readers, reader_list_seeker); @@ -808,20 +847,17 @@ return r; } + driver = getenv("OPENSC_DRIVER"); + if (driver) { + scconf_list *list = NULL; + scconf_list_add(&list, driver); + set_drivers(&opts, list); + scconf_list_destroy(list); + } + load_card_drivers(ctx, &opts); load_card_atrs(ctx); - if (!opts.forced_card_driver) { - char *driver = getenv("OPENSC_DRIVER"); - if(driver) { - opts.forced_card_driver = strdup(driver); - } - } - if (opts.forced_card_driver) { - if (SC_SUCCESS != sc_set_card_driver(ctx, opts.forced_card_driver)) - sc_log(ctx, "Warning: Could not load %s.", opts.forced_card_driver); - free(opts.forced_card_driver); - } del_drvs(&opts); sc_ctx_detect_readers(ctx); *ctx_out = ctx; diff -Nru opensc-0.17.0/src/libopensc/cwa14890.c opensc-0.19.0/src/libopensc/cwa14890.c --- opensc-0.17.0/src/libopensc/cwa14890.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/cwa14890.c 2018-09-13 11:47:21.000000000 +0000 @@ -51,7 +51,7 @@ * according to iso7816-4 sect 5.2.2. * * Notice that current implementation does not handle properly - * multibyte tag id. Just asume that tag is 1-byte length + * multibyte tag id. Just assume that tag is 1-byte length * Also, encodings for data length longer than 0x01000000 bytes * are not supported (tag 0x84) */ @@ -83,7 +83,7 @@ return; if (flag == 0) { /* apdu command */ if (apdu->datalen > 0) { /* apdu data to show */ - sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL, apdu->data, apdu->datalen, buf, sizeof(buf)); + sc_hex_dump(apdu->data, apdu->datalen, buf, sizeof(buf)); sc_log(card->ctx, "\nAPDU before encode: ==================================================\nCLA: %02X INS: %02X P1: %02X P2: %02X Lc: %02"SC_FORMAT_LEN_SIZE_T"X Le: %02"SC_FORMAT_LEN_SIZE_T"X DATA: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n", apdu->cla, apdu->ins, apdu->p1, apdu->p2, @@ -95,7 +95,7 @@ apdu->lc, apdu->le); } } else { /* apdu response */ - sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL, apdu->resp, apdu->resplen, buf, sizeof(buf)); + sc_hex_dump(apdu->resp, apdu->resplen, buf, sizeof(buf)); sc_log(card->ctx, "\nAPDU response after decode: ==========================================\nSW1: %02X SW2: %02X RESP: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n", apdu->sw1, apdu->sw2, apdu->resplen, buf); @@ -135,7 +135,7 @@ * * Adds an 0x80 at the end of buffer and as many zeroes to get len * multiple of 8 - * Buffer must be long enougth to store additional bytes + * Buffer must be long enough to store additional bytes * * @param buffer where to compose data * @param len pointer to buffer length @@ -151,10 +151,10 @@ /** * compose a BER-TLV data in provided buffer. * - * Multybyte tag id are not supported + * Multibyte tag id are not supported * Also multibyte id 0x84 is unhandled * - * Notice that TLV is composed starting at offset lenght from + * Notice that TLV is composed starting at offset length from * the buffer. Consecutive calls to cwa_add_tlv, appends a new * TLV at the end of the buffer * @@ -176,7 +176,7 @@ /* preliminary checks */ if (!card || !card->ctx || !out || !outlen) return SC_ERROR_INVALID_ARGUMENTS; - /* comodity vars */ + /* commodity vars */ ctx = card->ctx; LOG_FUNC_CALLED(ctx); @@ -215,7 +215,7 @@ * Parse and APDU Response and extract specific BER-TLV data. * * NOTICE that iso7816 sect 5.2.2 states that Tag length may be 1 to n bytes - * length. In this code we'll assume allways tag lenght = 1 byte + * length. In this code we'll assume always tag length = 1 byte * * FIXME use `sc_asn1_read_tag` or similar instead * @@ -237,7 +237,7 @@ /* preliminary checks */ if (!card || !card->ctx) return SC_ERROR_INVALID_ARGUMENTS; - /* comodity vars */ + /* commodity vars */ ctx = card->ctx; LOG_FUNC_CALLED(ctx); @@ -316,11 +316,11 @@ * * This routine uses Root CA public key data From Annex III of manual * to verify intermediate CA icc certificate provided by card - * if verify sucess, then extract public keys from intermediate CA + * if verify success, then extract public keys from intermediate CA * and verify icc certificate * * @param card pointer to sc_card_contex - * @param sub_ca_cert icc intermediate CA certificate readed from card + * @param sub_ca_cert icc intermediate CA certificate read from card * @param icc_ca icc certificate from card * @return SC_SUCCESS if verification is ok; else error code */ @@ -328,7 +328,7 @@ cwa_provider_t * provider, X509 * sub_ca_cert, X509 * icc_cert) { - char *msg; + char *msg = NULL; int res = SC_SUCCESS; EVP_PKEY *root_ca_key = NULL; EVP_PKEY *sub_ca_key = NULL; @@ -421,8 +421,8 @@ /** * Alternate implementation for set_security environment. * - * Used to handle raw apdu data in set_security_env() on SM stblishment - * Standard set_securiy_env() method has sc_security_env->buffer limited + * Used to handle raw apdu data in set_security_env() on SM establishment + * Standard set_security_env() method has sc_security_env->buffer limited * to 8 bytes; so cannot send some of required SM commands. * * @param card pointer to card data @@ -543,7 +543,7 @@ then, we should encrypt with our private key and then with icc pub key returning resulting data */ - char *msg; /* to store error messages */ + char *msg = NULL; /* to store error messages */ int res = SC_SUCCESS; u8 *buf1; /* where to encrypt with icc pub key */ u8 *buf2; /* where to encrypt with ifd pub key */ @@ -941,7 +941,7 @@ } len2 = BN_bn2bin(sigbn, buf2); /* copy result to buffer */ if (len2 <= 0) { - msg = "Verify Signature: cannot conver bignum to buffer"; + msg = "Verify Signature: cannot convert bignum to buffer"; res = SC_ERROR_INTERNAL; goto verify_internal_done; } @@ -982,11 +982,11 @@ /** * Create Secure Messaging channel. * - * This is the main entry point for CWA14890 SM chanel creation. + * This is the main entry point for CWA14890 SM channel creation. * It closely follows cwa standard, with a minor modification: - * - ICC serial number is taken at the begining of SM creation + * - ICC serial number is taken at the beginning of SM creation * - ICC and IFD certificate agreement process is reversed, to allow - * card to retain key references on further proccess (this behavior + * card to retain key references on further process (this behavior * is also defined in standard) * * Based on Several documents: @@ -1029,7 +1029,7 @@ return SC_ERROR_INVALID_ARGUMENTS; if (!provider) return SC_ERROR_SM_NOT_INITIALIZED; - /* comodity vars */ + /* commodity vars */ ctx = card->ctx; LOG_FUNC_CALLED(ctx); @@ -1085,7 +1085,7 @@ /* Read Intermediate CA from card */ if (!provider->cwa_get_icc_intermediate_ca_cert) { sc_log(ctx, - "Step 8.4.1.6: Skip Retrieveing ICC intermediate CA"); + "Step 8.4.1.6: Skip Retrieving ICC intermediate CA"); ca_cert = NULL; } else { sc_log(ctx, "Step 8.4.1.7: Retrieving ICC intermediate CA"); @@ -1187,7 +1187,7 @@ res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen); if (res != SC_SUCCESS) { msg = - "Cannot compose tlv for setting intermeditate CA key reference"; + "Cannot compose tlv for setting intermediate CA key reference"; goto csc_end; } res = cwa_set_security_env(card, 0x81, 0xB6, tlv, tlvlen); @@ -1196,7 +1196,7 @@ goto csc_end; } - /* Send IFD certiticate in CVC format C_CV_IFD */ + /* Send IFD certificate in CVC format C_CV_IFD */ sc_log(ctx, "Step 8.4.1.5: Send CVC IFD Certificate for ICC verification"); res = provider->cwa_get_cvc_ifd_cert(card, &cert, &certlen); @@ -1291,7 +1291,7 @@ /* get challenge: retrieve 8 random bytes from card */ sc_log(ctx, "Step 8.4.1.11: Prepare External Auth: Get Challenge"); - res = card->ops->get_challenge(card, sm->icc.rnd, sizeof(sm->icc.rnd)); + res = sc_get_challenge(card, sm->icc.rnd, sizeof(sm->icc.rnd)); if (res != SC_SUCCESS) { msg = "Get Challenge failed"; goto csc_end; @@ -1431,11 +1431,9 @@ sizeof(u8)); ccbuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen), sizeof(u8)); - if (!to->resp) { - /* if no response create a buffer for the encoded response */ - to->resp = calloc(MAX_RESP_BUFFER_SIZE, sizeof(u8)); - to->resplen = MAX_RESP_BUFFER_SIZE; - } + /* always create a new buffer for the encoded response */ + to->resp = calloc(MAX_RESP_BUFFER_SIZE, sizeof(u8)); + to->resplen = MAX_RESP_BUFFER_SIZE; if (!apdubuf || !ccbuf || (!from->resp && !to->resp)) { res = SC_ERROR_OUT_OF_MEMORY; goto err; @@ -1475,7 +1473,7 @@ /* start kriptbuff with iso padding indicator */ *cryptbuf = 0x01; - /* aply TDES + CBC with kenc and iv=(0,..,0) */ + /* apply TDES + CBC with kenc and iv=(0,..,0) */ DES_ede3_cbc_encrypt(msgbuf, cryptbuf + 1, dlen, &k1, &k2, &k1, &iv, DES_ENCRYPT); /* compose data TLV and add to result buffer */ @@ -1536,7 +1534,7 @@ /* compose and add computed MAC TLV to result buffer */ tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4; - sc_log(ctx, "Using TLV lenght: %"SC_FORMAT_LEN_SIZE_T"u", tlv_len); + sc_log(ctx, "Using TLV length: %"SC_FORMAT_LEN_SIZE_T"u", tlv_len); res = cwa_compose_tlv(card, 0x8E, tlv_len, macbuf, &apdubuf, &apdulen); if (res != SC_SUCCESS) { msg = "Encode APDU compose_tlv(0x87) failed"; diff -Nru opensc-0.17.0/src/libopensc/cwa14890.h opensc-0.19.0/src/libopensc/cwa14890.h --- opensc-0.17.0/src/libopensc/cwa14890.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/cwa14890.h 2018-09-13 11:47:21.000000000 +0000 @@ -60,9 +60,9 @@ * * This code is called before any operation required in * standard cwa14890 SM stablisment process. It's usually - * used for adquiring/initialize data to be used in the + * used for acquiring/initialize data to be used in the * process (i.e: retrieve card serial number), to make sure - * that no extra apdu is sent during the SM stablishment procedure + * that no extra apdu is sent during the SM establishment procedure * * @param card pointer to card driver structure * @param provider pointer to SM data provider for DNIe @@ -74,8 +74,8 @@ /** * CWA-14890 SM stablisment post-operations. * - * This code is called after sucessfull SM chanel stablishment - * procedure, and before returning from create_sm_chanel() function + * This code is called after successful SM channel establishment + * procedure, and before returning from create_sm_channel() function * May be use for store data, trace, logs and so * * @param card pointer to card driver structure @@ -115,7 +115,7 @@ /** * Get RSA IFD (Terminal) private key data. * - * Notice that resulting data should be keept in memory as little + * Notice that resulting data should be kept in memory as little * as possible Erasing them once used * * @param card pointer to card driver structure @@ -131,7 +131,7 @@ * * But to do this, an special OpenSSL with PACE extensions is * needed. In the meantime, let's use binary buffers to get - * CVC and key references, until an CV_CERT hancling API + * CVC and key references, until an CV_CERT handling API * become available in standard OpenSSL * *@see http://openpace.sourceforge.net @@ -150,7 +150,7 @@ * @return SC_SUCCESS if ok; else error code */ int (*cwa_get_cvc_ca_cert) (sc_card_t * card, u8 ** cert, - size_t * lenght); + size_t * length); /** * Retrieve IFD (application) CVC certificate and length. @@ -165,7 +165,7 @@ * @return SC_SUCCESS if ok; else error code */ int (*cwa_get_cvc_ifd_cert) (sc_card_t * card, u8 ** cert, - size_t * lenght); + size_t * length); /** * Retrieve public key reference for Root CA to validate CVC intermediate CA certs. diff -Nru opensc-0.17.0/src/libopensc/cwa-dnie.c opensc-0.19.0/src/libopensc/cwa-dnie.c --- opensc-0.17.0/src/libopensc/cwa-dnie.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/cwa-dnie.c 2018-09-13 11:47:21.000000000 +0000 @@ -314,7 +314,7 @@ goto dnie_read_file_end; } fsize = (*file)->size; - /* reserve enought space to read data from card */ + /* reserve enough space to read data from card */ if (fsize <= 0) { res = SC_ERROR_FILE_TOO_SMALL; msg = "provided buffer size is too small"; @@ -330,7 +330,7 @@ sc_log(ctx, "read_binary(): expected '%"SC_FORMAT_LEN_SIZE_T"u' bytes", fsize); res = sc_read_binary(card, 0, data, fsize, 0L); - if (res < 0) { /* read_binary returns number of bytes readed */ + if (res < 0) { /* read_binary returns number of bytes read */ res = SC_ERROR_CARD_CMD_FAILED; msg = "read_binary() failed"; goto dnie_read_file_err; @@ -361,7 +361,7 @@ * No validation is done except that received data is effectively a certificate * @param card Pointer to card driver structure * @param certpat path to requested certificate - * @param cert where to store resultig data + * @param cert where to store resulting data * @return SC_SUCCESS if ok, else error code */ static int dnie_read_certificate(sc_card_t * card, char *certpath, X509 ** cert) @@ -436,7 +436,7 @@ EVP_PKEY_free(*root_ca_key); if (root_ca_rsa) RSA_free(root_ca_rsa); - sc_log(card->ctx, "Cannot set RSA valuses for CA public key"); + sc_log(card->ctx, "Cannot set RSA values for CA public key"); return SC_ERROR_INTERNAL; } @@ -457,7 +457,7 @@ * (in CardVerifiable Certificate format) to be sent to the * card in External Authentication process * As this is local provider, just points to provided static data, - * and allways return success + * and always return success * * @param card Pointer to card driver Certificate * @param cert Where to store resulting byte array @@ -479,7 +479,7 @@ * (in CardVerifiable Certificate format) to be sent to the * card in External Authentication process * As this is local provider, just points to provided static data, - * and allways return success + * and always return success * * @param card Pointer to card driver Certificate * @param cert Where to store resulting byte array @@ -502,7 +502,7 @@ * (in CardVerifiable Certificate format) to be sent to the * card in External Authentication process * As this is local provider, just points to provided static data, - * and allways return success + * and always return success * * @param card Pointer to card driver Certificate * @param cert Where to store resulting byte array @@ -651,7 +651,7 @@ * Retrieve public key reference for intermediate CA to validate IFD cert. * * This is required in the process of On card external authenticate - * As this driver is for local SM authentication SC_SUCCESS is allways returned + * As this driver is for local SM authentication SC_SUCCESS is always returned * * @param card Pointer to card driver structure * @param buf where to store resulting key reference @@ -671,7 +671,7 @@ * * This tells the card with in memory key reference is to be used * when CVC cert is sent for external auth procedure - * As this driver is for local SM authentication SC_SUCCESS is allways returned + * As this driver is for local SM authentication SC_SUCCESS is always returned * * @param card pointer to card driver structure * @param buf where to store data to be sent @@ -690,7 +690,7 @@ * * This tells the card with in memory key reference is to be used * when CVC cert is sent for external auth procedure - * As this driver is for local SM authentication SC_SUCCESS is allways returned + * As this driver is for local SM authentication SC_SUCCESS is always returned * * @param card pointer to card driver structure * @param buf where to store data to be sent @@ -708,7 +708,7 @@ /** * Retrieve key reference for ICC privkey. * - * In local SM stablishment, just retrieve key reference from static + * In local SM establishment, just retrieve key reference from static * data tables and just return success * * @param card pointer to card driver structure @@ -772,7 +772,7 @@ struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; res = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); - LOG_TEST_RET(card->ctx, res, "Error in gettting serial number"); + LOG_TEST_RET(card->ctx, res, "Error in getting serial number"); /* copy into sn_icc buffer.Remember that dnie sn has 7 bytes length */ memset(sm->icc.sn, 0, sizeof(sm->icc.sn)); memcpy(&sm->icc.sn[1], serial.value, 7); diff -Nru opensc-0.17.0/src/libopensc/dir.c opensc-0.19.0/src/libopensc/dir.c --- opensc-0.17.0/src/libopensc/dir.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/dir.c 2018-09-13 11:47:21.000000000 +0000 @@ -214,7 +214,7 @@ size_t rec_size; /* Arbitrary set '16' as maximal number of records to check out: - * to avoid endless loop because of some uncomplete cards/drivers */ + * to avoid endless loop because of some incomplete cards/drivers */ for (rec_nr = 1; rec_nr < 16; rec_nr++) { r = sc_read_record(card, rec_nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR); if (r == SC_ERROR_RECORD_NOT_FOUND) @@ -259,10 +259,8 @@ int i; for (i = 0; i < card->app_count; i++) { - if (card->app[i]->label) - free(card->app[i]->label); - if (card->app[i]->ddo.value) - free(card->app[i]->ddo.value); + free(card->app[i]->label); + free(card->app[i]->ddo.value); free(card->app[i]); } card->app_count = -1; diff -Nru opensc-0.17.0/src/libopensc/ef-gdo.c opensc-0.19.0/src/libopensc/ef-gdo.c --- opensc-0.17.0/src/libopensc/ef-gdo.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/libopensc/ef-gdo.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * ef-atr.c: Stuff for handling EF(GDO) + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "asn1.h" +#include "internal.h" +#include +#include + +static int +sc_parse_ef_gdo_content(const unsigned char *gdo, size_t gdo_len, + unsigned char *iccsn, size_t *iccsn_len, + unsigned char *chn, size_t *chn_len) +{ + int r = SC_SUCCESS, iccsn_found = 0, chn_found = 0; + const unsigned char *p = gdo; + size_t left = gdo_len; + + while (left >= 2) { + unsigned int cla, tag; + size_t tag_len; + + r = sc_asn1_read_tag(&p, left, &cla, &tag, &tag_len); + if (r != SC_SUCCESS) { + if (r == SC_ERROR_ASN1_END_OF_CONTENTS) { + /* not enough data */ + r = SC_SUCCESS; + } + break; + } + if (p == NULL) { + /* done parsing */ + break; + } + + if (cla == SC_ASN1_TAG_APPLICATION) { + switch (tag) { + case 0x1A: + iccsn_found = 1; + if (iccsn && iccsn_len) { + memcpy(iccsn, p, MIN(tag_len, *iccsn_len)); + *iccsn_len = MIN(tag_len, *iccsn_len); + } + break; + case 0x1F20: + chn_found = 1; + if (chn && chn_len) { + memcpy(chn, p, MIN(tag_len, *chn_len)); + *chn_len = MIN(tag_len, *chn_len); + } + break; + } + } + + p += tag_len; + left = gdo_len - (p - gdo); + } + + if (!iccsn_found && iccsn_len) + *iccsn_len = 0; + if (!chn_found && chn_len) + *chn_len = 0; + + return r; +} + + + +int +sc_parse_ef_gdo(struct sc_card *card, + unsigned char *iccsn, size_t *iccsn_len, + unsigned char *chn, size_t *chn_len) +{ + struct sc_context *ctx; + struct sc_path path; + struct sc_file *file; + unsigned char *gdo = NULL; + size_t gdo_len = 0; + int r; + + if (!card) + return SC_ERROR_INVALID_ARGUMENTS; + + ctx = card->ctx; + + LOG_FUNC_CALLED(ctx); + + sc_format_path("3F002F02", &path); + r = sc_select_file(card, &path, &file); + LOG_TEST_GOTO_ERR(ctx, r, "Cannot select EF(GDO) file"); + + if (file->size) { + gdo_len = file->size; + } else { + gdo_len = 64; + } + gdo = malloc(gdo_len); + if (!gdo) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + + r = sc_read_binary(card, 0, gdo, gdo_len, 0); + LOG_TEST_GOTO_ERR(ctx, r, "Cannot read EF(GDO) file"); + + r = sc_parse_ef_gdo_content(gdo, r, iccsn, iccsn_len, chn, chn_len); + +err: + sc_file_free(file); + free(gdo); + + LOG_FUNC_RETURN(ctx, r); +} diff -Nru opensc-0.17.0/src/libopensc/errors.c opensc-0.19.0/src/libopensc/errors.c --- opensc-0.17.0/src/libopensc/errors.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/errors.c 2018-09-13 11:47:21.000000000 +0000 @@ -103,7 +103,9 @@ "Unsupported card", "Unable to load external module", "EF offset too large", - "Not implemented" + "Not implemented", + "Invalid Simple TLV object", + "Premature end of Simple TLV stream", }; const int int_base = -SC_ERROR_INTERNAL; diff -Nru opensc-0.17.0/src/libopensc/errors.h opensc-0.19.0/src/libopensc/errors.h --- opensc-0.17.0/src/libopensc/errors.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/errors.h 2018-09-13 11:47:21.000000000 +0000 @@ -95,6 +95,8 @@ #define SC_ERROR_CANNOT_LOAD_MODULE -1414 #define SC_ERROR_OFFSET_TOO_LARGE -1415 #define SC_ERROR_NOT_IMPLEMENTED -1416 +#define SC_ERROR_INVALID_TLV_OBJECT -1417 +#define SC_ERROR_TLV_END_OF_CONTENTS -1418 /* Relating to PKCS #15 init stuff */ #define SC_ERROR_PKCS15INIT -1500 diff -Nru opensc-0.17.0/src/libopensc/gp.c opensc-0.19.0/src/libopensc/gp.c --- opensc-0.17.0/src/libopensc/gp.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/libopensc/gp.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * gp.c: Global Platform Related functions + * + * Copyright (C) 2018 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" + +/* The AID of the Card Manager defined by Open Platform 2.0.1 specification */ +static const struct sc_aid gp_card_manager = { + {0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00}, 7 +}; + +/* The AID of the Issuer Security Domain defined by GlobalPlatform 2.3.1 specification. */ +static const struct sc_aid gp_isd_rid = { + {0xA0, 0x00, 0x00, 0x01, 0x51, 0x00, 0x00}, 7 +}; + + +/* Select AID */ +int +gp_select_aid(struct sc_card *card, const struct sc_aid *aid) +{ + struct sc_apdu apdu; + int rv; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C); + apdu.lc = aid->len; + apdu.data = aid->value; + apdu.datalen = aid->len; + + rv = sc_transmit_apdu(card, &apdu); + + if (rv < 0) + return rv; + + rv = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (rv < 0) + return rv; + + return apdu.resplen; +} + +/* Select the Open Platform Card Manager */ +int +gp_select_card_manager(struct sc_card *card) +{ + int rv; + + LOG_FUNC_CALLED(card->ctx); + rv = gp_select_aid(card, &gp_card_manager); + LOG_FUNC_RETURN(card->ctx, rv); +} + +/* Select Global Platform Card Manager */ +int +gp_select_isd_rid(struct sc_card *card) +{ + int rv; + + LOG_FUNC_CALLED(card->ctx); + rv = gp_select_aid(card, &gp_isd_rid); + LOG_FUNC_RETURN(card->ctx, rv); +} diff -Nru opensc-0.17.0/src/libopensc/gp.h opensc-0.19.0/src/libopensc/gp.h --- opensc-0.17.0/src/libopensc/gp.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/libopensc/gp.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * gp.h: Global Platform Related functions + * + * Copyright (C) 2018 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LIBOPENSC_GP_H +#define _LIBOPENSC_GP_H + +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int gp_select_aid(struct sc_card *card, const struct sc_aid *aid); +int gp_select_card_manager(struct sc_card *card); +int gp_select_isd_rid(struct sc_card *card); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru opensc-0.17.0/src/libopensc/iasecc-sdo.c opensc-0.19.0/src/libopensc/iasecc-sdo.c --- opensc-0.17.0/src/libopensc/iasecc-sdo.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/iasecc-sdo.c 2018-09-13 11:47:21.000000000 +0000 @@ -83,7 +83,7 @@ {SC_AC_OP_READ, IASECC_ACL_GET_DATA}, {0x00, 0x00} }; - unsigned char mask = 0x80, op_mask; + unsigned char mask = 0x80, op_mask = 0; int ii; LOG_FUNC_CALLED(ctx); @@ -94,10 +94,10 @@ break; } } - if (ops[ii].mask == 0) + if (op_mask == 0) LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); - sc_log(ctx, "OP:%i, mask:0x%X", op, ops[ii].mask); + sc_log(ctx, "OP:%i, mask:0x%X", op, op_mask); sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS)); sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size)); @@ -344,7 +344,7 @@ LOG_TEST_RET(ctx, size_size, "parse error: invalid SDO SE data size"); if (data_len != size + size_size + 3) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalide SDO SE data size"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO SE data size"); data += 3 + size_size; data_len = size; @@ -364,7 +364,7 @@ LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); if (data_len != size + size_size + 1) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalide SE data size"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SE data size"); offs = 1 + size_size; for (; offs < data_len;) { @@ -375,7 +375,7 @@ } if (offs != data_len) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totaly parsed"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -583,7 +583,7 @@ LOG_TEST_RET(ctx, rv, "iasecc_parse_get_tlv() get and parse TLV error"); sc_log(ctx, - "iasecc_parse_docp() parse_get_tlv retuned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", + "iasecc_parse_docp() parse_get_tlv returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", rv, tlv.tag, tlv.size); if (tlv.tag == IASECC_DOCP_TAG_ACLS) { @@ -606,7 +606,7 @@ else if (tlv.tag == IASECC_DOCP_TAG_ISSUER_DATA) { sdo->docp.issuer_data = tlv; } - else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDATION) { + else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION) { sdo->docp.non_repudiation = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { @@ -655,7 +655,7 @@ free(tlv.value); LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP"); } - else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDATION) { + else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION) { sdo->docp.non_repudiation = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { @@ -745,7 +745,7 @@ LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); if (data_len != size + size_size + 3) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalide SDO data size"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size"); sc_log(ctx, "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %"SC_FORMAT_LEN_SIZE_T"u", @@ -760,7 +760,7 @@ } if (offs != data_len) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totaly parsed"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); sc_log(ctx, "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u, docp.size.size %"SC_FORMAT_LEN_SIZE_T"u", @@ -803,7 +803,7 @@ LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); if (data_len != size + size_size + 3) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalide SDO data size"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size"); sc_log(ctx, "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %"SC_FORMAT_LEN_SIZE_T"u", @@ -818,7 +818,7 @@ } if (offs != data_len) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totaly parsed"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); sc_log(ctx, "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u; docp.size.size %"SC_FORMAT_LEN_SIZE_T"u", @@ -922,7 +922,7 @@ LOG_TEST_RET(ctx, rv, "ECC: cannot add USAGE REMAINING to blob"); rv = iasecc_update_blob(ctx, &docp->non_repudiation, &tmp_blob, &blob_size); - LOG_TEST_RET(ctx, rv, "ECC: cannot add NON REPUDATION to blob"); + LOG_TEST_RET(ctx, rv, "ECC: cannot add NON REPUDIATION to blob"); rv = iasecc_update_blob(ctx, &docp->size, &tmp_blob, &blob_size); LOG_TEST_RET(ctx, rv, "ECC: cannot add SIZE to blob"); @@ -1212,7 +1212,7 @@ if (*(data + offs) == IASECC_CARD_ANSWER_TAG_DATA ) { if (size > sizeof(out->data)) - LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "iasecc_sm_decode_answer() unbelivable !!!"); + LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "iasecc_sm_decode_answer() unbelievable !!!"); memcpy(out->data, data + offs + size_size + 1, size); out->data_len = size; diff -Nru opensc-0.17.0/src/libopensc/iasecc-sdo.h opensc-0.19.0/src/libopensc/iasecc-sdo.h --- opensc-0.17.0/src/libopensc/iasecc-sdo.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/iasecc-sdo.h 2018-09-13 11:47:21.000000000 +0000 @@ -34,7 +34,7 @@ #define IASECC_DOCP_TAG_TRIES_REMAINING 0x9B #define IASECC_DOCP_TAG_USAGE_MAXIMUM 0x9C #define IASECC_DOCP_TAG_USAGE_REMAINING 0x9D -#define IASECC_DOCP_TAG_NON_REPUDATION 0x9E +#define IASECC_DOCP_TAG_NON_REPUDIATION 0x9E #define IASECC_DOCP_TAG_SIZE 0x80 #define IASECC_DOCP_TAG_ACLS 0xA1 #define IASECC_DOCP_TAG_ACLS_CONTACT 0x8C diff -Nru opensc-0.17.0/src/libopensc/iasecc-sm.c opensc-0.19.0/src/libopensc/iasecc-sm.c --- opensc-0.17.0/src/libopensc/iasecc-sm.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/iasecc-sm.c 2018-09-13 11:47:21.000000000 +0000 @@ -260,31 +260,6 @@ LOG_FUNC_RETURN(ctx, rv); } - - -static int -iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len) -{ - struct sc_context *ctx = card->ctx; - struct sc_apdu apdu; - unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE]; - int rv; - - sc_log(ctx, "SM get challenge: length %"SC_FORMAT_LEN_SIZE_T"u", len); - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0); - apdu.le = len; - apdu.resplen = len; - apdu.resp = rbuf; - - rv = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(ctx, rv, "APDU transmit failed"); - rv = sc_check_sw(card, apdu.sw1, apdu.sw2); - LOG_TEST_RET(ctx, rv, "Command failed"); - - memcpy(out, rbuf, apdu.resplen); - - LOG_FUNC_RETURN(ctx, apdu.resplen); -} #endif @@ -309,7 +284,7 @@ rv = iasecc_sm_se_mutual_authentication(card, se_num); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() MUTUAL AUTHENTICATION failed"); - rv = iasecc_sm_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN); + rv = sc_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() GET CHALLENGE failed"); sc_remote_data_init(&rdata); @@ -335,7 +310,7 @@ rv = iasecc_sm_transmit_apdus (card, &rdata, cwa_session->mdata, &cwa_session->mdata_len); if (rv == SC_ERROR_PIN_CODE_INCORRECT) sc_log(ctx, "SM initialization failed, %i tries left", (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F); - LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() trasmit APDUs failed"); + LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() transmit APDUs failed"); rdata.free(&rdata); diff -Nru opensc-0.17.0/src/libopensc/internal.h opensc-0.19.0/src/libopensc/internal.h --- opensc-0.17.0/src/libopensc/internal.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/internal.h 2018-09-13 11:47:21.000000000 +0000 @@ -125,7 +125,7 @@ /* Returns an index number if a match was found, -1 otherwise. table has to * be null terminated. */ -int _sc_match_atr(struct sc_card *card, struct sc_atr_table *table, int *type_out); +int _sc_match_atr(struct sc_card *card, const struct sc_atr_table *table, int *type_out); int _sc_card_add_algorithm(struct sc_card *card, const struct sc_algorithm_info *info); int _sc_card_add_symmetric_alg(sc_card_t *card, unsigned int algorithm, diff -Nru opensc-0.17.0/src/libopensc/internal-winscard.h opensc-0.19.0/src/libopensc/internal-winscard.h --- opensc-0.17.0/src/libopensc/internal-winscard.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/internal-winscard.h 2018-09-13 11:47:21.000000000 +0000 @@ -237,7 +237,7 @@ /* structures used (but not defined) in PCSC Part 10: * "IFDs with Secure Pin Entry Capabilities" */ -/* Set structure elements aligment on bytes +/* Set structure elements alignment on bytes * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ #if defined(__APPLE__) || defined(sun) #pragma pack(1) diff -Nru opensc-0.17.0/src/libopensc/iso7816.c opensc-0.19.0/src/libopensc/iso7816.c --- opensc-0.17.0/src/libopensc/iso7816.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/iso7816.c 2018-09-13 11:47:21.000000000 +0000 @@ -57,10 +57,15 @@ { 0x6282, SC_ERROR_FILE_END_REACHED, "End of file/record reached before reading Le bytes" }, { 0x6283, SC_ERROR_CARD_CMD_FAILED, "Selected file invalidated" }, { 0x6284, SC_ERROR_CARD_CMD_FAILED, "FCI not formatted according to ISO 7816-4" }, + { 0x6285, SC_ERROR_CARD_CMD_FAILED, "Selected file in termination state" }, + { 0x6286, SC_ERROR_CARD_CMD_FAILED, "No input data available from a sensor on the card" }, { 0x6300, SC_ERROR_CARD_CMD_FAILED, "Warning: no information given, non-volatile memory has changed" }, { 0x6381, SC_ERROR_CARD_CMD_FAILED, "Warning: file filled up by last write" }, + { 0x6400, SC_ERROR_CARD_CMD_FAILED, "Execution error" }, + { 0x6401, SC_ERROR_CARD_CMD_FAILED, "Immediate response required by the card" }, + { 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure" }, { 0x6700, SC_ERROR_WRONG_LENGTH, "Wrong length" }, @@ -68,37 +73,36 @@ { 0x6800, SC_ERROR_NO_CARD_SUPPORT, "Functions in CLA not supported" }, { 0x6881, SC_ERROR_NO_CARD_SUPPORT, "Logical channel not supported" }, { 0x6882, SC_ERROR_NO_CARD_SUPPORT, "Secure messaging not supported" }, + { 0x6883, SC_ERROR_CARD_CMD_FAILED, "Last command of the chain expected" }, + { 0x6884, SC_ERROR_NO_CARD_SUPPORT, "Command chaining not supported" }, { 0x6900, SC_ERROR_NOT_ALLOWED, "Command not allowed" }, { 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" }, - { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" }, + { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED,"Security status not satisfied" }, { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" }, { 0x6984, SC_ERROR_REF_DATA_NOT_USABLE, "Referenced data not usable" }, { 0x6985, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied" }, { 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" }, { 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" }, - { 0x6988, SC_ERROR_INCORRECT_PARAMETERS,"SM data objects incorrect" }, + { 0x6988, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect SM data objects" }, { 0x6A00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" }, { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters in the data field" }, { 0x6A81, SC_ERROR_NO_CARD_SUPPORT, "Function not supported" }, - { 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File not found" }, + { 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File or application not found" }, { 0x6A83, SC_ERROR_RECORD_NOT_FOUND, "Record not found" }, { 0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory space in the file" }, { 0x6A85, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with TLV structure" }, { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters P1-P2" }, { 0x6A87, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with P1-P2" }, { 0x6A88, SC_ERROR_DATA_OBJECT_NOT_FOUND,"Referenced data not found" }, - { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File already exists"}, - { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS, "DF name already exists"}, + { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File already exists"}, + { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS, "DF name already exists"}, { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" }, { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Instruction code not supported or invalid" }, { 0x6E00, SC_ERROR_CLASS_NOT_SUPPORTED, "Class not supported" }, { 0x6F00, SC_ERROR_CARD_CMD_FAILED, "No precise diagnosis" }, - - - }; @@ -116,7 +120,7 @@ if (sw1 == 0x90) return SC_SUCCESS; if (sw1 == 0x63U && (sw2 & ~0x0fU) == 0xc0U ) { - sc_log(card->ctx, "Verification failed (remaining tries: %d)", (sw2 & 0x0f)); + sc_log(card->ctx, "PIN not verified (remaining tries: %d)", (sw2 & 0x0f)); return SC_ERROR_PIN_CODE_INCORRECT; } for (i = 0; i < err_count; i++) { @@ -334,115 +338,127 @@ const unsigned char *buf, size_t buflen) { struct sc_context *ctx = card->ctx; - size_t taglen, len = buflen; - int i; - const unsigned char *tag = NULL, *p = buf; + const unsigned char *p, *end; + unsigned int cla = 0, tag = 0; + size_t length; + int size; + + for (p = buf, length = buflen, end = buf + buflen; + p < end; + p += length, length = end - p) { - sc_log(ctx, "processing FCI bytes"); - tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); - if (tag != NULL && taglen == 2) { - file->id = (tag[0] << 8) | tag[1]; - sc_log(ctx, " file identifier: 0x%02X%02X", tag[0], tag[1]); - } - - /* determine the file size */ - /* try the tag 0x80 then the tag 0x81 */ - file->size = 0; - for (i = 0x80; i <= 0x81; i++) { - int size = 0; - len = buflen; - tag = sc_asn1_find_tag(ctx, p, len, i, &taglen); - if (tag == NULL) - continue; - if (taglen == 0) - continue; - if (sc_asn1_decode_integer(tag, taglen, &size) < 0) - continue; - if (size <0) - continue; - - file->size = size; - sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", - file->size); - break; - } - - tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); - if (tag != NULL) { - if (taglen > 0) { - unsigned char byte = tag[0]; - const char *type; - - file->shareable = byte & 0x40 ? 1 : 0; - sc_log(ctx, " shareable: %s", (byte & 0x40) ? "yes" : "no"); - file->ef_structure = byte & 0x07; - switch ((byte >> 3) & 7) { - case 0: - type = "working EF"; - file->type = SC_FILE_TYPE_WORKING_EF; + if (SC_SUCCESS != sc_asn1_read_tag(&p, length, &cla, &tag, &length) + || p == NULL) { + break; + } + switch (cla | tag) { + case 0x81: + if (file->size != 0) { + /* don't overwrite existing file size excluding structural information */ + break; + } + /* fall through */ + case 0x80: + /* determine the file size */ + if (sc_asn1_decode_integer(p, length, &size) == 0 && size >= 0) { + file->size = size; + sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", + file->size); + } break; - case 1: - type = "internal EF"; - file->type = SC_FILE_TYPE_INTERNAL_EF; + + case 0x82: + if (length > 0) { + unsigned char byte = p[0]; + const char *type; + + file->shareable = byte & 0x40 ? 1 : 0; + sc_log(ctx, " shareable: %s", (byte & 0x40) ? "yes" : "no"); + file->ef_structure = byte & 0x07; + switch ((byte >> 3) & 7) { + case 0: + type = "working EF"; + file->type = SC_FILE_TYPE_WORKING_EF; + break; + case 1: + type = "internal EF"; + file->type = SC_FILE_TYPE_INTERNAL_EF; + break; + case 7: + type = "DF"; + file->type = SC_FILE_TYPE_DF; + break; + default: + type = "unknown"; + break; + } + sc_log(ctx, " type: %s", type); + sc_log(ctx, " EF structure: %d", byte & 0x07); + sc_log(ctx, " tag 0x82: 0x%02x", byte); + if (SC_SUCCESS != sc_file_set_type_attr(file, &byte, 1)) + sc_log(ctx, "Warning: Could not set file attributes"); + } break; - case 7: - type = "DF"; - file->type = SC_FILE_TYPE_DF; + + case 0x83: + if (length == 2) { + file->id = (p[0] << 8) | p[1]; + sc_log(ctx, " file identifier: 0x%02X%02X", p[0], p[1]); + } break; - default: - type = "unknown"; + + case 0x84: + if (length > 0 && length <= 16) { + memcpy(file->name, p, length); + file->namelen = length; + + sc_debug_hex(ctx, SC_LOG_DEBUG_NORMAL, " File name:", file->name, file->namelen); + if (!file->type) + file->type = SC_FILE_TYPE_DF; + } break; - } - sc_log(ctx, " type: %s", type); - sc_log(ctx, " EF structure: %d", byte & 0x07); - sc_log(ctx, " tag 0x82: 0x%02x", byte); - if (SC_SUCCESS != sc_file_set_type_attr(file, &byte, 1)) - sc_log(ctx, "Warning: Could not set file attributes"); - } - } - tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); - if (tag != NULL && taglen > 0 && taglen <= 16) { - char tbuf[128]; + case 0x85: + case 0xA5: + if (SC_SUCCESS != sc_file_set_prop_attr(file, p, length)) { + sc_log(ctx, "Warning: Could not set proprietary file properties"); + } + break; - memcpy(file->name, tag, taglen); - file->namelen = taglen; + case 0x86: + if (SC_SUCCESS != sc_file_set_sec_attr(file, p, length)) { + sc_log(ctx, "Warning: Could not set file security properties"); + } + break; - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, file->name, file->namelen, tbuf, sizeof(tbuf)); - sc_log(ctx, " File name: %s", tbuf); - if (!file->type) - file->type = SC_FILE_TYPE_DF; - } + case 0x88: + if (length == 1) { + file->sid = *p; + sc_log(ctx, " short file identifier: 0x%02X", *p); + } + break; - tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen); - if (tag != NULL && taglen) - sc_file_set_prop_attr(file, tag, taglen); - else - file->prop_attr_len = 0; + case 0x8A: + if (length == 1) { + if (p[0] == 0x01) + file->status = SC_FILE_STATUS_CREATION; + else if (p[0] == 0x07 || p[0] == 0x05) + file->status = SC_FILE_STATUS_ACTIVATED; + else if (p[0] == 0x06 || p[0] == 0x04) + file->status = SC_FILE_STATUS_INVALIDATED; + } + break; - tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen); - if (tag != NULL && taglen) - sc_file_set_prop_attr(file, tag, taglen); - - tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen); - if (tag != NULL && taglen) - sc_file_set_sec_attr(file, tag, taglen); - - tag = sc_asn1_find_tag(ctx, p, len, 0x88, &taglen); - if (tag != NULL && taglen == 1) - file->sid = *tag; - - tag = sc_asn1_find_tag(ctx, p, len, 0x8A, &taglen); - if (tag != NULL && taglen==1) { - if (tag[0] == 0x01) - file->status = SC_FILE_STATUS_CREATION; - else if (tag[0] == 0x07 || tag[0] == 0x05) - file->status = SC_FILE_STATUS_ACTIVATED; - else if (tag[0] == 0x06 || tag[0] == 0x04) - file->status = SC_FILE_STATUS_INVALIDATED; + case 0x62: + case 0x64: + case 0x6F: + /* allow nested FCP/FMD/FCI templates */ + iso7816_process_fci(card, file, p, length); + } } file->magic = SC_FILE_MAGIC; + return SC_SUCCESS; } @@ -608,28 +624,23 @@ { int r; struct sc_apdu apdu; - u8 buf[10]; - if (!rnd && len) - return SC_ERROR_INVALID_ARGUMENTS; + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00); + apdu.le = len; + apdu.resp = rnd; + apdu.resplen = len; - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); - apdu.le = 8; - apdu.resp = buf; - apdu.resplen = 8; /* include SW's */ + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - while (len > 0) { - size_t n = len > 8 ? 8 : len; + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed"); - r = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - if (apdu.resplen != 8) - return sc_check_sw(card, apdu.sw1, apdu.sw2); - memcpy(rnd, apdu.resp, n); - len -= n; - rnd += n; + if (len < apdu.resplen) { + return (int) len; } - return 0; + + return (int) apdu.resplen; } @@ -828,18 +839,22 @@ *p++ = env->algorithm_ref & 0xFF; } if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) { + if (env->file_ref.len > 0xFF) + return SC_ERROR_INVALID_ARGUMENTS; *p++ = 0x81; - *p++ = env->file_ref.len; + *p++ = (u8) env->file_ref.len; assert(sizeof(sbuf) - (p - sbuf) >= env->file_ref.len); memcpy(p, env->file_ref.value, env->file_ref.len); p += env->file_ref.len; } if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { - if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) *p++ = 0x83; else *p++ = 0x84; - *p++ = env->key_ref_len; + if (env->key_ref_len > 0xFF) + return SC_ERROR_INVALID_ARGUMENTS; + *p++ = env->key_ref_len & 0xFF; assert(sizeof(sbuf) - (p - sbuf) >= env->key_ref_len); memcpy(p, env->key_ref, env->key_ref_len); p += env->key_ref_len; @@ -1001,6 +1016,7 @@ case SC_AC_CHV: /* fall through */ case SC_AC_SESSION: + case SC_AC_CONTEXT_SPECIFIC: break; default: return SC_ERROR_INVALID_ARGUMENTS; @@ -1302,9 +1318,13 @@ apdu.le = read; r = sc_transmit_apdu(card, &apdu); + if (r < 0) + goto err; + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r < 0 && r != SC_ERROR_FILE_END_REACHED) + goto err; /* emulate the behaviour of sc_read_binary */ - if (r >= 0) - r = apdu.resplen; + r = apdu.resplen; while(1) { if (r >= 0 && ((size_t) r) != read) { @@ -1401,3 +1421,19 @@ err: return r; } + +int iso7816_logout(sc_card_t *card, unsigned char pin_reference) +{ + int r; + sc_apdu_t apdu; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0xFF, pin_reference); + + r = sc_transmit_apdu(card, &apdu); + if (r < 0) + return r; + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + + return r; +} diff -Nru opensc-0.17.0/src/libopensc/libopensc.exports opensc-0.19.0/src/libopensc/libopensc.exports --- opensc-0.17.0/src/libopensc/libopensc.exports 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/libopensc.exports 2018-09-13 11:47:21.000000000 +0000 @@ -130,7 +130,6 @@ sc_lock sc_logout sc_make_cache_dir -sc_mem_alloc_secure sc_mem_clear sc_mem_reverse sc_match_atr_block @@ -323,6 +322,7 @@ sc_pkcs15init_sanity_check sc_pkcs15init_finalize_profile sc_card_find_rsa_alg +sc_card_find_ec_alg sc_check_apdu sc_print_cache sc_find_app @@ -349,17 +349,22 @@ _sc_card_add_rsa_alg _sc_match_atr _sc_log -npa_secret_name +eac_secret_name get_pace_capabilities perform_pace perform_terminal_authentication perform_chip_authentication -npa_default_flags +eac_default_flags +eac_pace_get_tries_left npa_reset_retry_counter -npa_pace_get_tries_left escape_pace_input_to_buf escape_buf_to_pace_input escape_pace_output_to_buf escape_buf_to_pace_output escape_pace_capabilities_to_buf escape_buf_to_pace_capabilities +ui_get_str +sc_notify_init +sc_notify_close +sc_notify +sc_notify_id diff -Nru opensc-0.17.0/src/libopensc/log.c opensc-0.19.0/src/libopensc/log.c --- opensc-0.17.0/src/libopensc/log.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/log.c 2018-09-13 11:47:21.000000000 +0000 @@ -84,7 +84,9 @@ #ifdef _WIN32 GetLocalTime(&st); r = snprintf(p, left, - "%i-%02i-%02i %02i:%02i:%02i.%03i ", + "P:%lu; T:%lu %i-%02i-%02i %02i:%02i:%02i.%03i ", + (unsigned long)GetCurrentProcessId(), + (unsigned long)GetCurrentThreadId(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); #else @@ -112,11 +114,14 @@ if (r < 0) return; - if (ctx->reopen_log_file) { - r = sc_ctx_log_to_file(ctx, ctx->debug_filename); - if (r < 0) - return; - } +#ifdef _WIN32 + /* In Windows, file handles can not be shared between DLL-s, each DLL has a + * separate file handle table. Make sure we always have a valid file + * descriptor. */ + r = sc_ctx_log_to_file(ctx, ctx->debug_filename); + if (r < 0) + return; +#endif outf = ctx->debug_file; if (outf == NULL) @@ -128,11 +133,11 @@ fprintf(outf, "\n"); fflush(outf); - if (ctx->reopen_log_file) { - if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) - fclose(ctx->debug_file); - ctx->debug_file = NULL; - } +#ifdef _WIN32 + if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) + fclose(ctx->debug_file); + ctx->debug_file = NULL; +#endif return; } @@ -163,29 +168,25 @@ if (buf == NULL) return; - sc_hex_dump(ctx, type, data, len, buf, blen); + sc_hex_dump(data, len, buf, blen); if (label) sc_do_log(ctx, type, file, line, func, - "\n%s (%u byte%s):\n%s", - label, (unsigned int) len, len==1?"":"s", buf); + "\n%s (%"SC_FORMAT_LEN_SIZE_T"u byte%s):\n%s", + label, len, len==1?"":"s", buf); else sc_do_log(ctx, type, file, line, func, - "%u byte%s:\n%s", - (unsigned int) len, len==1?"":"s", buf); + "%"SC_FORMAT_LEN_SIZE_T"u byte%s:\n%s", + len, len==1?"":"s", buf); free(buf); } -/* Although not used, we need this for consistent exports */ -void sc_hex_dump(struct sc_context *ctx, int level, const u8 * in, size_t count, char *buf, size_t len) +void sc_hex_dump(const u8 * in, size_t count, char *buf, size_t len) { char *p = buf; int lines = 0; - if (!ctx || ctx->debug < level) - return; - if (buf == NULL || (in == NULL && count != 0)) { return; } @@ -219,7 +220,7 @@ } } -char * +const char * sc_dump_hex(const u8 * in, size_t count) { static char dump_buf[0x1000]; @@ -252,7 +253,7 @@ return dump_buf; } -char * +const char * sc_dump_oid(const struct sc_object_id *oid) { static char dump_buf[SC_MAX_OBJECT_ID_OCTETS * 20]; diff -Nru opensc-0.17.0/src/libopensc/log.h opensc-0.19.0/src/libopensc/log.h --- opensc-0.17.0/src/libopensc/log.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/log.h 2018-09-13 11:47:21.000000000 +0000 @@ -87,6 +87,8 @@ */ #define sc_debug_hex(ctx, level, label, data, len) \ _sc_debug_hex(ctx, level, __FILE__, __LINE__, __FUNCTION__, label, data, len) +#define sc_log_hex(ctx, label, data, len) \ + sc_debug_hex(ctx, SC_LOG_DEBUG_NORMAL, label, data, len) /** * @brief Log binary data * @@ -102,9 +104,9 @@ void _sc_debug_hex(struct sc_context *ctx, int level, const char *file, int line, const char *func, const char *label, const u8 *data, size_t len); -void sc_hex_dump(struct sc_context *ctx, int level, const u8 * buf, size_t len, char *out, size_t outlen); -char * sc_dump_hex(const u8 * in, size_t count); -char * sc_dump_oid(const struct sc_object_id *oid); +void sc_hex_dump(const u8 *buf, size_t len, char *out, size_t outlen); +const char * sc_dump_hex(const u8 * in, size_t count); +const char * sc_dump_oid(const struct sc_object_id *oid); #define SC_FUNC_CALLED(ctx, level) do { \ sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, "called\n"); \ } while (0) diff -Nru opensc-0.17.0/src/libopensc/Makefile.am opensc-0.19.0/src/libopensc/Makefile.am --- opensc-0.17.0/src/libopensc/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -2,19 +2,21 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -EXTRA_DIST = Makefile.mak +EXTRA_DIST = Makefile.mak opensc.dll.manifest lib_LTLIBRARIES = libopensc.la noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.h \ internal-winscard.h p15card-helper.h pkcs15-syn.h \ - opensc.h pkcs15.h \ + opensc.h pkcs15.h gp.h \ cardctl.h asn1.h log.h simpletlv.h \ errors.h types.h compression.h itacns.h iso7816.h \ authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \ pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h \ jpki.h sc-ossl-compat.h card-npa.h ccid-types.h reader-tr03119.h -AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\" \ +AM_CPPFLAGS = -D'OPENSC_CONF_PATH="$(sysconfdir)/opensc.conf"' \ + -D'DEFAULT_SM_MODULE_PATH="$(DEFAULT_SM_MODULE_PATH)"' \ + -D'DEFAULT_SM_MODULE="$(DEFAULT_SM_MODULE)"' \ -I$(top_srcdir)/src AM_CFLAGS = $(OPENPACE_CFLAGS) $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_OPENCT_CFLAGS) \ $(OPTIONAL_PCSC_CFLAGS) $(OPTIONAL_ZLIB_CFLAGS) @@ -22,8 +24,8 @@ libopensc_la_SOURCES_BASE = \ sc.c ctx.c log.c errors.c \ - asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c padding.c apdu.c \ - simpletlv.c \ + asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c \ + ef-gdo.c padding.c apdu.c simpletlv.c gp.c \ \ pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \ @@ -52,7 +54,7 @@ pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \ pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \ pkcs15-oberthur.c pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \ - pkcs15-coolkey.c \ + pkcs15-coolkey.c pkcs15-din-66291.c \ pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c \ compression.c p15card-helper.c sm.c \ aux-data.c @@ -78,6 +80,8 @@ $(top_builddir)/src/pkcs15init/libpkcs15init.la \ $(top_builddir)/src/scconf/libscconf.la \ $(top_builddir)/src/common/libscdl.la \ + $(top_builddir)/src/ui/libnotify.la \ + $(top_builddir)/src/ui/libstrings.la \ $(top_builddir)/src/sm/libsmeac.la \ $(top_builddir)/src/common/libcompat.la if WIN32 diff -Nru opensc-0.17.0/src/libopensc/Makefile.mak opensc-0.19.0/src/libopensc/Makefile.mak --- opensc-0.17.0/src/libopensc/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -4,7 +4,7 @@ OBJECTS = \ sc.obj ctx.obj log.obj errors.obj \ asn1.obj base64.obj sec.obj card.obj iso7816.obj dir.obj ef-atr.obj \ - padding.obj apdu.obj simpletlv.obj \ + ef-gdo.obj padding.obj apdu.obj simpletlv.obj gp.obj \ \ pkcs15.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \ pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-skey.obj \ @@ -32,7 +32,7 @@ pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \ pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \ pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \ - pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj \ + pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \ pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \ pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \ compression.obj p15card-helper.obj sm.obj \ @@ -41,6 +41,8 @@ LIBS = $(TOPDIR)\src\scconf\scconf.lib \ $(TOPDIR)\src\common\common.lib \ $(TOPDIR)\src\common\libscdl.lib \ + $(TOPDIR)\src\ui\strings.lib \ + $(TOPDIR)\src\ui\notify.lib \ $(TOPDIR)\src\sm\libsmiso.lib \ $(TOPDIR)\src\sm\libsmeac.lib \ $(TOPDIR)\src\pkcs15init\pkcs15init.lib @@ -53,8 +55,8 @@ echo LIBRARY $* > $*.def echo EXPORTS >> $*.def type lib$*.exports >> $*.def - link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:opensc.dll $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib advapi32.lib ws2_32.lib + link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:opensc.dll $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib if EXIST opensc.dll.manifest mt -manifest opensc.dll.manifest -outputresource:opensc.dll;2 -opensc_a.lib: $(OBJECTS) $(LIBS) - lib $(LIBFLAGS) /out:opensc_a.lib $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) user32.lib advapi32.lib ws2_32.lib +opensc_a.lib: $(OBJECTS) + lib $(LIBFLAGS) /out:opensc_a.lib $(OBJECTS) diff -Nru opensc-0.17.0/src/libopensc/muscle.c opensc-0.19.0/src/libopensc/muscle.c --- opensc-0.17.0/src/libopensc/muscle.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/muscle.c 2018-09-13 11:47:21.000000000 +0000 @@ -617,6 +617,8 @@ if(!*modulus) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); memcpy(*modulus, buffer, *modLength); *expLength = (buffer[*modLength] << 8) | buffer[*modLength + 1]; + if (*expLength > sizeof buffer) + return SC_ERROR_OUT_OF_MEMORY; r = msc_read_object(card, inputId, fileLocation, buffer, *expLength); if(r < 0) { free(*modulus); *modulus = NULL; @@ -788,10 +790,11 @@ SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { r = msc_read_object(card, inputId, 2, outputData, dataLength); - *outputDataLength = dataLength; + if (r >= 0) + *outputDataLength = r; msc_delete_object(card, outputId, 0); msc_delete_object(card, inputId, 0); - return 0; + return r; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) { diff -Nru opensc-0.17.0/src/libopensc/muscle-filesystem.c opensc-0.19.0/src/libopensc/muscle-filesystem.c --- opensc-0.17.0/src/libopensc/muscle-filesystem.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/muscle-filesystem.c 2018-09-13 11:47:21.000000000 +0000 @@ -53,6 +53,7 @@ void mscfs_free(mscfs_t *fs) { mscfs_clear_cache(fs); + free(fs); } void mscfs_clear_cache(mscfs_t* fs) { @@ -142,7 +143,7 @@ int mscfs_lookup_path(mscfs_t* fs, const u8 *path, int pathlen, msc_id* objectId, int isDirectory) { u8* oid = objectId->id; - if ((pathlen & 1) != 0) /* not divisble by 2 */ + if ((pathlen & 1) != 0) /* not divisible by 2 */ return MSCFS_INVALID_ARGS; if(isDirectory) { /* Directory must be right next to root */ @@ -224,7 +225,7 @@ } *file_data = NULL; } - if(*file_data == NULL && (0 == memcmp("\x3F\x00\x00\x00", fullPath.id, 4) || 0 == memcmp("\x3F\x00\x3F\x00", fullPath.id, 4 ))) { + if(*file_data == NULL && (0 == memcmp("\x3F\x00\x00\x00", fullPath.id, 4) || 0 == memcmp("\x3F\x00\x50\x15", fullPath.id, 4 ) || 0 == memcmp("\x3F\x00\x3F\x00", fullPath.id, 4))) { static mscfs_file_t ROOT_FILE; ROOT_FILE.ef = 0; ROOT_FILE.size = 0; diff -Nru opensc-0.17.0/src/libopensc/opensc.dll.manifest opensc-0.19.0/src/libopensc/opensc.dll.manifest --- opensc-0.17.0/src/libopensc/opensc.dll.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/libopensc/opensc.dll.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/libopensc/opensc.h opensc-0.19.0/src/libopensc/opensc.h --- opensc-0.17.0/src/libopensc/opensc.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/opensc.h 2018-09-13 11:47:21.000000000 +0000 @@ -62,8 +62,7 @@ #define SC_SEC_ENV_ALG_REF_PRESENT 0x0001 #define SC_SEC_ENV_FILE_REF_PRESENT 0x0002 #define SC_SEC_ENV_KEY_REF_PRESENT 0x0004 -/* FIXME: the flag below is misleading */ -#define SC_SEC_ENV_KEY_REF_ASYMMETRIC 0x0008 +#define SC_SEC_ENV_KEY_REF_SYMMETRIC 0x0008 #define SC_SEC_ENV_ALG_PRESENT 0x0010 /* PK algorithms */ @@ -86,40 +85,41 @@ /* Key derivation algorithms */ #define SC_ALGORITHM_PBKDF2 192 -/* Key encryption algoprithms */ +/* Key encryption algorithms */ #define SC_ALGORITHM_PBES2 256 #define SC_ALGORITHM_ONBOARD_KEY_GEN 0x80000000 /* need usage = either sign or decrypt. keys with both? decrypt, emulate sign */ #define SC_ALGORITHM_NEED_USAGE 0x40000000 -#define SC_ALGORITHM_SPECIFIC_FLAGS 0x0001FFFF +#define SC_ALGORITHM_SPECIFIC_FLAGS 0x001FFFFF #define SC_ALGORITHM_RSA_RAW 0x00000001 /* If the card is willing to produce a cryptogram padded with the following * methods, set these flags accordingly. */ -#define SC_ALGORITHM_RSA_PADS 0x0000000E +#define SC_ALGORITHM_RSA_PADS 0x0000001E #define SC_ALGORITHM_RSA_PAD_NONE 0x00000000 #define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 #define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004 #define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008 +#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* If the card is willing to produce a cryptogram with the following * hash values, set these flags accordingly. */ -#define SC_ALGORITHM_RSA_HASH_NONE 0x00000010 -#define SC_ALGORITHM_RSA_HASH_SHA1 0x00000020 -#define SC_ALGORITHM_RSA_HASH_MD5 0x00000040 -#define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000080 -#define SC_ALGORITHM_RSA_HASH_RIPEMD160 0x00000100 -#define SC_ALGORITHM_RSA_HASH_SHA256 0x00000200 -#define SC_ALGORITHM_RSA_HASH_SHA384 0x00000400 -#define SC_ALGORITHM_RSA_HASH_SHA512 0x00000800 -#define SC_ALGORITHM_RSA_HASH_SHA224 0x00001000 -#define SC_ALGORITHM_RSA_HASHES 0x00001FE0 - -#define SC_ALGORITHM_GOSTR3410_RAW 0x00002000 -#define SC_ALGORITHM_GOSTR3410_HASH_NONE 0x00004000 -#define SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411 0x00008000 -#define SC_ALGORITHM_GOSTR3410_HASHES 0x00008000 +#define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 +#define SC_ALGORITHM_RSA_HASH_SHA1 0x00000200 +#define SC_ALGORITHM_RSA_HASH_MD5 0x00000400 +#define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000800 +#define SC_ALGORITHM_RSA_HASH_RIPEMD160 0x00001000 +#define SC_ALGORITHM_RSA_HASH_SHA256 0x00002000 +#define SC_ALGORITHM_RSA_HASH_SHA384 0x00004000 +#define SC_ALGORITHM_RSA_HASH_SHA512 0x00008000 +#define SC_ALGORITHM_RSA_HASH_SHA224 0x00010000 +#define SC_ALGORITHM_RSA_HASHES 0x0001FE00 + +#define SC_ALGORITHM_GOSTR3410_RAW 0x00020000 +#define SC_ALGORITHM_GOSTR3410_HASH_NONE 0x00040000 +#define SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411 0x00080000 +#define SC_ALGORITHM_GOSTR3410_HASHES 0x00080000 /*TODO: -DEE Should the above be 0x0000E000 */ /* Or should the HASH_NONE be 0x00000010 and HASHES be 0x00008010 */ @@ -127,8 +127,8 @@ /* TODO: -DEE Will overload RSA_HASHES with EC_HASHES */ /* Not clear if these need their own bits or not */ /* The PIV card does not support and hashes */ -#define SC_ALGORITHM_ECDSA_RAW 0x00010000 -#define SC_ALGORITHM_ECDH_CDH_RAW 0x00020000 +#define SC_ALGORITHM_ECDSA_RAW 0x00100000 +#define SC_ALGORITHM_ECDH_CDH_RAW 0x00200000 #define SC_ALGORITHM_ECDSA_HASH_NONE SC_ALGORITHM_RSA_HASH_NONE #define SC_ALGORITHM_ECDSA_HASH_SHA1 SC_ALGORITHM_RSA_HASH_SHA1 #define SC_ALGORITHM_ECDSA_HASH_SHA224 SC_ALGORITHM_RSA_HASH_SHA224 @@ -144,7 +144,7 @@ /* define mask of all algorithms that can do raw */ #define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ECDSA_RAW) -/* extened algorithm bits for selected mechs */ +/* extended algorithm bits for selected mechs */ #define SC_ALGORITHM_EXT_EC_F_P 0x00000001 #define SC_ALGORITHM_EXT_EC_F_2M 0x00000002 #define SC_ALGORITHM_EXT_EC_ECPARAMETERS 0x00000004 @@ -163,6 +163,7 @@ struct sc_supported_algo_info { unsigned int reference; unsigned int mechanism; + struct sc_object_id *parameters; /* OID for ECC, NULL for RSA */ unsigned int operations; struct sc_object_id algo_id; unsigned int algo_ref; @@ -361,7 +362,7 @@ struct sc_pin_cmd_pin { const char *prompt; /* Prompt to display */ - const unsigned char *data; /* PIN, if given by the appliction */ + const unsigned char *data; /* PIN, if given by the application */ int len; /* set to -1 to get pin from pin pad */ size_t min_length; /* min length of PIN */ @@ -452,6 +453,7 @@ /* Hint SC_CARD_CAP_RNG */ #define SC_CARD_FLAG_RNG 0x00000002 +#define SC_CARD_FLAG_KEEP_ALIVE 0x00000004 /* * Card capabilities @@ -600,7 +602,7 @@ int (*decipher)(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen); - /* compute_signature: Generates a digital signature on the card. Similiar + /* compute_signature: Generates a digital signature on the card. Similar * to the function decipher. */ int (*compute_signature)(struct sc_card *card, const u8 * data, size_t data_len, u8 * out, size_t outlen); @@ -678,7 +680,7 @@ unsigned long (*thread_id)(void); } sc_thread_context_t; -/** Stop modifing or using external resources +/** Stop modifying or using external resources * * Currently this is used to avoid freeing duplicated external resources for a * process that has been forked. For example, a child process may want to leave @@ -687,6 +689,7 @@ * calling sc_disconnect_card. */ #define SC_CTX_FLAG_TERMINATE 0x00000001 +/** removed in 0.18.0 and later */ #define SC_CTX_FLAG_PARANOID_MEMORY 0x00000002 #define SC_CTX_FLAG_DEBUG_MEMORY 0x00000004 #define SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER 0x00000008 @@ -697,7 +700,6 @@ scconf_block *conf_blocks[3]; char *app_name; int debug; - int reopen_log_file; unsigned long flags; FILE *debug_file; @@ -723,7 +725,7 @@ /** Sends a APDU to the card * @param card struct sc_card object to which the APDU should be send * @param apdu sc_apdu_t object of the APDU to be send - * @return SC_SUCCESS on succcess and an error code otherwise + * @return SC_SUCCESS on success and an error code otherwise */ int sc_transmit_apdu(struct sc_card *, struct sc_apdu *); @@ -745,6 +747,24 @@ */ int sc_bytes2apdu(sc_context_t *ctx, const u8 *buf, size_t len, sc_apdu_t *apdu); +/** Encodes a APDU as an octet string + * @param ctx sc_context_t object (used for logging) + * @param apdu APDU to be encoded as an octet string + * @param proto protocol version to be used + * @param out output buffer of size outlen. + * @param outlen size of hte output buffer + * @return SC_SUCCESS on success and an error code otherwise + */ +int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu, + unsigned int proto, u8 *out, size_t outlen); + +/** Calculates the length of the encoded APDU in octets. + * @param apdu the APDU + * @param proto the desired protocol + * @return length of the encoded APDU + */ +size_t sc_apdu_get_length(const sc_apdu_t *apdu, unsigned int proto); + int sc_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2); /********************************************************************/ @@ -769,7 +789,7 @@ /** version number of this structure (0 for this version) */ unsigned int ver; /** name of the application (used for finding application - * dependend configuration data). If NULL the name "default" + * dependent configuration data). If NULL the name "default" * will be used. */ const char *app_name; /** context flags */ @@ -818,8 +838,9 @@ * @param key path of register key * @return SC_SUCCESS on success and an error code otherwise. */ -int sc_ctx_win32_get_config_value(char *env, char *reg, char *key, char *out, - size_t *out_size); +int sc_ctx_win32_get_config_value(const char *env, + const char *reg, const char *key, + void *out, size_t *out_size); /** * Returns a pointer to the specified sc_reader_t object @@ -900,7 +921,7 @@ /** * Checks if a card is present in a reader * @param reader Reader structure - * @retval If an error occured, the return value is a (negative) + * @retval If an error occurred, the return value is a (negative) * OpenSC error code. If no card is present, 0 is returned. * Otherwise, a positive value is returned, which is a * combination of flags. The flag SC_READER_CARD_PRESENT is @@ -923,9 +944,9 @@ * @param event (OUT) the events that occurred. This is also ORed * from the SC_EVENT_CARD_* constants listed above. * @param timeout Amount of millisecs to wait; -1 means forever - * @retval < 0 if an error occured + * @retval < 0 if an error occurred * @retval = 0 if a an event happened - * @retval = 1 if the timeout occured + * @retval = 1 if the timeout occurred */ int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, @@ -1026,7 +1047,7 @@ * @param buf buffer with the data * @param count number of bytes to write * @param flags flags for the WRITE BINARY command (currently not used) - * @return number of bytes writen or an error code + * @return number of bytes written or an error code */ int sc_write_binary(struct sc_card *card, unsigned int idx, const u8 * buf, size_t count, unsigned long flags); @@ -1037,7 +1058,7 @@ * @param buf buffer with the new data * @param count number of bytes to update * @param flags flags for the UPDATE BINARY command (currently not used) - * @return number of bytes writen or an error code + * @return number of bytes written or an error code */ int sc_update_binary(struct sc_card *card, unsigned int idx, const u8 * buf, size_t count, unsigned long flags); @@ -1048,7 +1069,7 @@ * @param idx index within the file for the data to be erased * @param count number of bytes to erase * @param flags flags for the ERASE BINARY command (currently not used) - * @return number of bytes writen or an error code + * @return number of bytes written or an error code */ int sc_erase_binary(struct sc_card *card, unsigned int idx, size_t count, unsigned long flags); @@ -1077,10 +1098,10 @@ * Writes data to a record from the current (i.e. selected) file. * @param card struct sc_card object on which to issue the command * @param rec_nr SC_READ_RECORD_CURRENT or a record number starting from 1 - * @param buf buffer with to the data to be writen + * @param buf buffer with to the data to be written * @param count number of bytes to write * @param flags flags (may contain a short file id of a file to select) - * @retval number of bytes writen or an error value + * @retval number of bytes written or an error value */ int sc_write_record(struct sc_card *card, unsigned int rec_nr, const u8 * buf, size_t count, unsigned long flags); @@ -1090,7 +1111,7 @@ * @param buf buffer with to the data for the new record * @param count length of the data * @param flags flags (may contain a short file id of a file to select) - * @retval number of bytes writen or an error value + * @retval number of bytes written or an error value */ int sc_append_record(struct sc_card *card, const u8 * buf, size_t count, unsigned long flags); @@ -1098,10 +1119,10 @@ * Updates the data of a record from the current (i.e. selected) file. * @param card struct sc_card object on which to issue the command * @param rec_nr SC_READ_RECORD_CURRENT or a record number starting from 1 - * @param buf buffer with to the new data to be writen + * @param buf buffer with to the new data to be written * @param count number of bytes to update * @param flags flags (may contain a short file id of a file to select) - * @retval number of bytes writen or an error value + * @retval number of bytes written or an error value */ int sc_update_record(struct sc_card *card, unsigned int rec_nr, const u8 * buf, size_t count, unsigned long flags); @@ -1305,7 +1326,6 @@ * @param len length of the memory buffer */ void sc_mem_clear(void *ptr, size_t len); -void *sc_mem_alloc_secure(sc_context_t *ctx, size_t len); int sc_mem_reverse(unsigned char *buf, size_t len); int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize); @@ -1316,8 +1336,12 @@ void sc_free_apps(struct sc_card *card); int sc_parse_ef_atr(struct sc_card *card); void sc_free_ef_atr(struct sc_card *card); +int sc_parse_ef_gdo(struct sc_card *card, + unsigned char *iccsn, size_t *iccsn_len, + unsigned char *chn, size_t *chn_len); int sc_update_dir(struct sc_card *card, sc_app_info_t *app); +void sc_invalidate_cache(struct sc_card *card); void sc_print_cache(struct sc_card *card); struct sc_algorithm_info * sc_card_find_rsa_alg(struct sc_card *card, @@ -1333,7 +1357,19 @@ * @param value pointer to data used for CRC calculation * @param len length of data used for CRC calculation */ -unsigned sc_crc32(unsigned char *value, size_t len); +unsigned sc_crc32(const unsigned char *value, size_t len); + +/** + * Find a given tag in a compact TLV structure + * @param[in] buf input buffer holding the compact TLV structure + * @param[in] len length of the input buffer @buf in bytes + * @param[in] tag compact tag to search for - high nibble: plain tag, low nibble: length. + * If length is 0, only the plain tag is used for searching, + * in any other case, the length must also match. + * @param[out] outlen pointer where the size of the buffer returned is to be stored + * @return pointer to the tag value found within @buf, or NULL if not found/on error + */ +const u8 *sc_compacttlv_find_tag(const u8 *buf, size_t len, u8 tag, size_t *outlen); /** * Used to initialize the @c sc_remote_data structure -- @@ -1396,6 +1432,16 @@ int iso7816_write_binary_sfid(sc_card_t *card, unsigned char sfid, u8 *ef, size_t ef_len); +/** + * @brief Set verification status of a specific PIN to “not verified” + * + * @param[in] card + * @param[in] pin_reference PIN reference written to P2 + * + * @note The appropriate directory must be selected before calling this function. + * */ +int iso7816_logout(sc_card_t *card, unsigned char pin_reference); + #ifdef __cplusplus } #endif diff -Nru opensc-0.17.0/src/libopensc/padding.c opensc-0.19.0/src/libopensc/padding.c --- opensc-0.17.0/src/libopensc/padding.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/padding.c 2018-09-13 11:47:21.000000000 +0000 @@ -310,6 +310,11 @@ *sflags |= (caps & SC_ALGORITHM_RAW_MASK); /* adds in the one raw type */ *pflags = 0; + } else if (iflags & SC_ALGORITHM_RSA_PAD_PSS) { + if (caps & SC_ALGORITHM_RSA_PAD_PSS) + *sflags |= SC_ALGORITHM_RSA_PAD_PSS; + else + *pflags |= SC_ALGORITHM_RSA_PAD_PSS; } else { LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported algorithm"); } diff -Nru opensc-0.17.0/src/libopensc/pkcs15.c opensc-0.19.0/src/libopensc/pkcs15.c --- opensc-0.17.0/src/libopensc/pkcs15.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15.c 2018-09-13 11:47:21.000000000 +0000 @@ -50,13 +50,19 @@ static const struct sc_asn1_entry c_asn1_algorithm_info[7] = { { "reference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, { "algorithmPKCS#11", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, - { "parameters", SC_ASN1_NULL, SC_ASN1_TAG_NULL, 0, NULL, NULL }, + { "parameters", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, { "supportedOperations",SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, { "objId", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_OPTIONAL, NULL, NULL }, { "algRef", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; +static const struct sc_asn1_entry c_asn1_algorithm_info_parameters[3] = { + { "PKCS15RSAParameters",SC_ASN1_NULL, SC_ASN1_TAG_NULL, 0, NULL, NULL }, + { "PKCS15ECParameters", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + /* * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 */ @@ -134,9 +140,11 @@ u8 preferred_language[3]; size_t lang_length = sizeof(preferred_language); struct sc_asn1_entry asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1], - asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; + asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7], + asn1_algo_infos_parameters[SC_MAX_SUPPORTED_ALGORITHMS][3]; size_t reference_len = sizeof(ti->supported_algos[0].reference); size_t mechanism_len = sizeof(ti->supported_algos[0].mechanism); + size_t parameter_len = sizeof(ti->supported_algos[0].parameters); size_t operations_len = sizeof(ti->supported_algos[0].operations); size_t algo_ref_len = sizeof(ti->supported_algos[0].algo_ref); @@ -152,14 +160,22 @@ sc_format_asn1_entry(asn1_twlabel, label, &label_len, 0); sc_copy_asn1_entry(c_asn1_profile_indication, asn1_profile_indication); - for (ii=0; iisupported_algos[ii].reference, &reference_len, 0); sc_format_asn1_entry(asn1_algo_infos[ii] + 1, &ti->supported_algos[ii].mechanism, &mechanism_len, 0); - sc_format_asn1_entry(asn1_algo_infos[ii] + 2, NULL, NULL, 0); + sc_format_asn1_entry(asn1_algo_infos[ii] + 2, + asn1_algo_infos_parameters[ii], NULL, 0); + sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 0, + NULL, NULL, 0); + sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 1, + &ti->supported_algos[ii].parameters, ¶meter_len, 0); sc_format_asn1_entry(asn1_algo_infos[ii] + 3, &ti->supported_algos[ii].operations, &operations_len, 0); sc_format_asn1_entry(asn1_algo_infos[ii] + 4, &ti->supported_algos[ii].algo_id, NULL, 1); sc_format_asn1_entry(asn1_algo_infos[ii] + 5, &ti->supported_algos[ii].algo_ref, &algo_ref_len, 0); @@ -191,7 +207,7 @@ r = sc_asn1_decode(ctx, asn1_tokeninfo, buf, blen, NULL, NULL); LOG_TEST_RET(ctx, r, "ASN.1 parsing of EF(TokenInfo) failed"); - if (asn1_toki_attrs[1].flags & SC_ASN1_PRESENT) { + if (asn1_toki_attrs[1].flags & SC_ASN1_PRESENT && serial_len > 0) { ti->serial_number = malloc(serial_len * 2 + 1); if (ti->serial_number == NULL) return SC_ERROR_OUT_OF_MEMORY; @@ -270,9 +286,11 @@ struct sc_asn1_entry asn1_toki_attrs[C_ASN1_TOKI_ATTRS_SIZE]; struct sc_asn1_entry asn1_tokeninfo[2]; struct sc_asn1_entry asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1], - asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; + asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7], + asn1_algo_infos_parameters[SC_MAX_SUPPORTED_ALGORITHMS][3]; size_t reference_len = sizeof(ti->supported_algos[0].reference); size_t mechanism_len = sizeof(ti->supported_algos[0].mechanism); + size_t parameter_len = sizeof(ti->supported_algos[0].parameters); size_t operations_len = sizeof(ti->supported_algos[0].operations); size_t algo_ref_len = sizeof(ti->supported_algos[0].algo_ref); struct sc_asn1_entry asn1_last_update[C_ASN1_LAST_UPDATE_SIZE]; @@ -283,14 +301,22 @@ sc_copy_asn1_entry(c_asn1_last_update, asn1_last_update); sc_copy_asn1_entry(c_asn1_profile_indication, asn1_profile_indication); - for (ii=0; iisupported_algos[ii].reference; ii++) + for (ii=0; iisupported_algos[ii].reference; ii++) { sc_copy_asn1_entry(c_asn1_algorithm_info, asn1_algo_infos[ii]); + sc_copy_asn1_entry(c_asn1_algorithm_info_parameters, + asn1_algo_infos_parameters[ii]); + } sc_copy_asn1_entry(c_asn1_supported_algorithms, asn1_supported_algorithms); for (ii=0; iisupported_algos[ii].reference; ii++) { sc_format_asn1_entry(asn1_algo_infos[ii] + 0, &ti->supported_algos[ii].reference, &reference_len, 1); sc_format_asn1_entry(asn1_algo_infos[ii] + 1, &ti->supported_algos[ii].mechanism, &mechanism_len, 1); - sc_format_asn1_entry(asn1_algo_infos[ii] + 2, NULL, NULL, 0); + sc_format_asn1_entry(asn1_algo_infos[ii] + 2, + asn1_algo_infos_parameters[ii], NULL, 0); + sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 0, + NULL, NULL, 0); + sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 1, + &ti->supported_algos[ii].parameters, ¶meter_len, 0); sc_format_asn1_entry(asn1_algo_infos[ii] + 3, &ti->supported_algos[ii].operations, &operations_len, 1); sc_format_asn1_entry(asn1_algo_infos[ii] + 4, &ti->supported_algos[ii].algo_id, NULL, 1); sc_format_asn1_entry(asn1_algo_infos[ii] + 5, &ti->supported_algos[ii].algo_ref, &algo_ref_len, 1); @@ -413,52 +439,6 @@ } } - -static void -fix_starcos_pkcs15_card(struct sc_pkcs15_card *p15card) -{ - struct sc_context *ctx = p15card->card->ctx; - - /* set special flags based on card meta data */ - if (strcmp(p15card->card->driver->short_name,"cardos") == 0 - && p15card->tokeninfo && p15card->tokeninfo->label) { - - /* D-Trust cards (D-TRUST, D-SIGN) */ - if (strstr(p15card->tokeninfo->label,"D-TRUST") != NULL - || strstr(p15card->tokeninfo->label,"D-SIGN") != NULL) { - - /* D-TRUST Card 2.0 2cc (standard cards, which always add - * SHA1 prefix itself */ - if (strstr(p15card->tokeninfo->label, "2cc") != NULL) { - p15card->card->caps |= SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED; - sc_log(ctx, "D-TRUST 2cc card detected, only SHA1 works with this card"); - /* XXX: add detection when other hash than SHA1 is used with - * such a card, as this produces invalid signatures. - */ - } - - /* D-SIGN multicard 2.0 2ca (cards working with all types of hashes - * and no addition of prefix) */ - else if (strstr(p15card->tokeninfo->label, "2ca") != NULL) { - p15card->card->caps |= SC_CARD_CAP_ONLY_RAW_HASH; - sc_log(ctx, "D-TRUST 2ca card detected"); - } - - /* D-TRUST card 2.4 2ce (cards working with all types of hashes - * and no addition of prefix) */ - else if (strstr(p15card->tokeninfo->label, "2ce") != NULL) { - p15card->card->caps |= SC_CARD_CAP_ONLY_RAW_HASH; - sc_log(ctx, "D-TRUST 2ce card detected"); - } - - /* XXX: probably there are more D-Trust card in the wild, - * which also need these flags to produce valid signatures - */ - } - } -} - - static int parse_ddo(struct sc_pkcs15_card *p15card, const u8 * buf, size_t buflen) { @@ -712,55 +692,64 @@ return NULL; } - sc_init_oid(&p15card->tokeninfo->profile_indication.oid); - p15card->magic = SC_PKCS15_CARD_MAGIC; return p15card; } +struct sc_pkcs15_tokeninfo * +sc_pkcs15_tokeninfo_new(void) +{ + struct sc_pkcs15_tokeninfo *tokeninfo; + + tokeninfo = calloc(1, sizeof(struct sc_pkcs15_tokeninfo)); + if (tokeninfo == NULL) { + return NULL; + } + + sc_init_oid(&tokeninfo->profile_indication.oid); + + return tokeninfo; +} + + void -sc_pkcs15_free_tokeninfo(struct sc_pkcs15_card *p15card) +sc_pkcs15_free_tokeninfo(struct sc_pkcs15_tokeninfo *tokeninfo) { - if (!p15card || !p15card->tokeninfo) + if (!tokeninfo) return; - if (p15card->tokeninfo->label != NULL) - free(p15card->tokeninfo->label); - if (p15card->tokeninfo->serial_number != NULL) - free(p15card->tokeninfo->serial_number); - if (p15card->tokeninfo->manufacturer_id != NULL) - free(p15card->tokeninfo->manufacturer_id); - if (p15card->tokeninfo->last_update.gtime != NULL) - free(p15card->tokeninfo->last_update.gtime); - if (p15card->tokeninfo->preferred_language != NULL) - free(p15card->tokeninfo->preferred_language); - if (p15card->tokeninfo->profile_indication.name != NULL) - free(p15card->tokeninfo->profile_indication.name); - if (p15card->tokeninfo->seInfo != NULL) { + if (tokeninfo->label != NULL) + free(tokeninfo->label); + if (tokeninfo->serial_number != NULL) + free(tokeninfo->serial_number); + if (tokeninfo->manufacturer_id != NULL) + free(tokeninfo->manufacturer_id); + if (tokeninfo->last_update.gtime != NULL) + free(tokeninfo->last_update.gtime); + if (tokeninfo->preferred_language != NULL) + free(tokeninfo->preferred_language); + if (tokeninfo->profile_indication.name != NULL) + free(tokeninfo->profile_indication.name); + if (tokeninfo->seInfo != NULL) { unsigned i; - for (i = 0; i < p15card->tokeninfo->num_seInfo; i++) - free(p15card->tokeninfo->seInfo[i]); - free(p15card->tokeninfo->seInfo); + for (i = 0; i < tokeninfo->num_seInfo; i++) + free(tokeninfo->seInfo[i]); + free(tokeninfo->seInfo); } - free(p15card->tokeninfo); - - p15card->tokeninfo = NULL; + free(tokeninfo); } void sc_pkcs15_free_app(struct sc_pkcs15_card *p15card) { - if (!p15card || !p15card->app) - return; - - if (p15card->app->label) + if (p15card && p15card->app) { free(p15card->app->label); - if (p15card->app->ddo.value) free(p15card->app->ddo.value); - free(p15card->app); - p15card->app = NULL; + free(p15card->app); + p15card->app = NULL; + } } @@ -789,7 +778,7 @@ sc_file_free(p15card->file_unusedspace); p15card->magic = 0; - sc_pkcs15_free_tokeninfo(p15card); + sc_pkcs15_free_tokeninfo(p15card->tokeninfo); sc_pkcs15_free_app(p15card); free(p15card); } @@ -1059,15 +1048,17 @@ } if (err < 0) { err = sc_read_binary(card, 0, buf, len, 0); - if (err < 0) { - sc_log(ctx, "read EF(ODF) file error: %s", sc_strerror(err)); - goto end; - } - else if (err < 2) { - err = SC_ERROR_PKCS15_APP_NOT_FOUND; - sc_log(ctx, "Invalid content of EF(ODF): %s", sc_strerror(err)); + if (err < 2) { + if (err < 0) { + sc_log(ctx, "read EF(ODF) file error: %s", sc_strerror(err)); + } else { + err = SC_ERROR_PKCS15_APP_NOT_FOUND; + sc_log(ctx, "Invalid content of EF(ODF): %s", sc_strerror(err)); + } goto end; } + /* sc_read_binary may return less than requested */ + len = err; if (p15card->opts.use_file_cache) { sc_pkcs15_cache_file(p15card, &tmppath, buf, len); @@ -1125,20 +1116,21 @@ } if (err < 0) { err = sc_read_binary(card, 0, buf, len, 0); - if (err < 0) { - sc_log(ctx, "read EF(TokenInfo) file error: %s", sc_strerror(err)); - goto end; - } if (err <= 2) { - err = SC_ERROR_PKCS15_APP_NOT_FOUND; - sc_log(ctx, "Invalid content of EF(TokenInfo): %s", sc_strerror(err)); + if (err < 0) { + sc_log(ctx, "read EF(TokenInfo) file error: %s", sc_strerror(err)); + } else { + err = SC_ERROR_PKCS15_APP_NOT_FOUND; + sc_log(ctx, "Invalid content of EF(TokenInfo): %s", sc_strerror(err)); + } goto end; } + /* sc_read_binary may return less than requested */ + len = err; if (p15card->opts.use_file_cache) { sc_pkcs15_cache_file(p15card, &tmppath, buf, len); } - err = len; } memset(&tokeninfo, 0, sizeof(tokeninfo)); @@ -1150,6 +1142,10 @@ *(p15card->tokeninfo) = tokeninfo; + if (!p15card->tokeninfo->serial_number && 0 == card->serialnr.len) { + sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &card->serialnr); + } + if (!p15card->tokeninfo->serial_number && card->serialnr.len) { char *serial = calloc(1, card->serialnr.len*2 + 1); size_t ii; @@ -1251,8 +1247,6 @@ goto error; } done: - fix_starcos_pkcs15_card(p15card); - *p15card_out = p15card; sc_unlock(card); LOG_FUNC_RETURN(ctx, SC_SUCCESS); @@ -2321,7 +2315,8 @@ if (r) { r = sc_lock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_lock() failed"); + if (r) + goto fail; r = sc_select_file(p15card->card, in_path, &file); if (r) goto fail_unlock; @@ -2392,7 +2387,7 @@ sc_file_free(file); - if (p15card->opts.use_file_cache) { + if (len && p15card->opts.use_file_cache) { sc_pkcs15_cache_file(p15card, in_path, data, len); } } @@ -2401,9 +2396,10 @@ LOG_FUNC_RETURN(ctx, SC_SUCCESS); fail_unlock: + sc_unlock(p15card->card); +fail: free(data); sc_file_free(file); - sc_unlock(p15card->card); LOG_FUNC_RETURN(ctx, r); } @@ -2525,7 +2521,7 @@ /* Need to pass by temporary variable, * because 'value' and 'content.value' pointers can be the sames. */ - tmp_buf = (unsigned char *)sc_mem_alloc_secure(ctx, len); + tmp_buf = calloc(sizeof *tmp_buf, len); if (!tmp_buf) return SC_ERROR_OUT_OF_MEMORY; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-cac.c opensc-0.19.0/src/libopensc/pkcs15-cac.c --- opensc-0.17.0/src/libopensc/pkcs15-cac.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-cac.c 2018-09-13 11:47:21.000000000 +0000 @@ -139,7 +139,7 @@ /* map a cert usage and algorithm to public and private key usages */ static int -cac_map_usage(unsigned long long cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation) +cac_map_usage(unsigned int cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation) { unsigned int pub_usage = 0, pr_usage = 0; unsigned int alg_flags = cac_alg_flags_from_algorithm(algorithm); @@ -173,7 +173,7 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card) { static const pindata pins[] = { - { "1", NULL, "", 0x00, + { "1", "PIN", "", 0x00, SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 8, 4, 8, SC_PKCS15_PIN_FLAG_NEEDS_PADDING | @@ -184,7 +184,7 @@ }; /* oid for key usage */ static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }}; - unsigned long long usage; + unsigned int usage; /* @@ -224,6 +224,9 @@ } /* set pins */ + /* TODO we should not create PIN objects if it is not initialized + * (opensc-tool -s 0020000000 returns 0x6A 0x88) + */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "CAC adding pins..."); for (i = 0; pins[i].id; i++) { struct sc_pkcs15_auth_info pin_info; @@ -245,11 +248,17 @@ sc_format_path(pins[i].path, &pin_info.path); pin_info.tries_left = -1; - label = pins[i].label? pins[i].label : cac_get_name(card->type); + label = pins[i].label; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "CAC Adding pin %d label=%s",i, label); strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1); pin_obj.flags = pins[i].obj_flags; + /* get the ACA path in case it needs to be selected before PIN verify */ + r = sc_card_ctl(card, SC_CARDCTL_CAC_GET_ACA_PATH, &pin_info.path); + if (r < 0) { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + } + r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if (r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); @@ -257,6 +266,8 @@ /* set other objects */ r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not initiate generic objects."); + for (i = 0; i < count; i++) { struct sc_pkcs15_data_info obj_info; struct sc_pkcs15_object obj_obj; @@ -273,6 +284,7 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_GENERIC_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not finalize generic objects."); /* * certs, pubkeys and priv keys are related and we assume @@ -282,6 +294,8 @@ */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "CAC adding certs, pub and priv keys..."); r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects."); + for (i = 0; i < count; i++) { struct sc_pkcs15_data_info obj_info; struct sc_pkcs15_cert_info cert_info; @@ -294,6 +308,7 @@ sc_pkcs15_cert_t *cert_out = NULL; r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_CERT_OBJECT, &obj_info); + LOG_TEST_RET(card->ctx, r, "Can not get next object"); memset(&cert_info, 0, sizeof(cert_info)); memset(&pubkey_info, 0, sizeof(pubkey_info)); @@ -317,8 +332,8 @@ prkey_info.path.len += 2; } pubkey_info.native = 1; - pubkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 || obj_info.id.value[1]; - prkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 || obj_info.id.value[1]; + pubkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1]; + prkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1]; prkey_info.native = 1; memcpy(cert_obj.label, obj_info.app_label, sizeof(obj_info.app_label)); @@ -395,7 +410,7 @@ usage = 0xd9ULL; /* basic default usage */ } cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cert %s: cert_usage=0x%llx, pub_usage=0x%x priv_usage=0x%x\n", + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n", sc_dump_hex(cert_info.id.value, cert_info.id.len), usage, pubkey_info.usage, prkey_info.usage); if (cert_out->key->algorithm != SC_ALGORITHM_RSA) { @@ -421,6 +436,7 @@ } r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects."); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-cert.c opensc-0.19.0/src/libopensc/pkcs15-cert.c --- opensc-0.17.0/src/libopensc/pkcs15-cert.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-cert.c 2018-09-13 11:47:21.000000000 +0000 @@ -98,38 +98,40 @@ cert->data.len = data_len; r = sc_asn1_decode(ctx, asn1_cert, obj, objlen, NULL, NULL); - LOG_TEST_RET(ctx, r, "ASN.1 parsing of certificate failed"); - + cert->key = pubkey; cert->version++; + LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 parsing of certificate failed"); + if (!pubkey) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Unable to decode subjectPublicKeyInfo from cert"); - cert->key = pubkey; + LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Unable to decode subjectPublicKeyInfo from cert"); sc_asn1_clear_algorithm_id(&sig_alg); if (serial && serial_len) { sc_format_asn1_entry(asn1_serial_number + 0, serial, &serial_len, 1); r = sc_asn1_encode(ctx, asn1_serial_number, &cert->serial, &cert->serial_len); - free(serial); - LOG_TEST_RET(ctx, r, "ASN.1 encoding of serial failed"); + LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of serial failed"); } if (subject && subject_len) { sc_format_asn1_entry(asn1_subject + 0, subject, &subject_len, 1); r = sc_asn1_encode(ctx, asn1_subject, &cert->subject, &cert->subject_len); - free(subject); - LOG_TEST_RET(ctx, r, "ASN.1 encoding of subject"); + LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of subject"); } if (issuer && issuer_len) { sc_format_asn1_entry(asn1_issuer + 0, issuer, &issuer_len, 1); r = sc_asn1_encode(ctx, asn1_issuer, &cert->issuer, &cert->issuer_len); - free(issuer); - LOG_TEST_RET(ctx, r, "ASN.1 encoding of issuer"); + LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of issuer"); } - return SC_SUCCESS; +err: + free(serial); + free(subject); + free(issuer); + + return r; } @@ -159,7 +161,7 @@ rdn = sc_asn1_skip_tag(ctx, &dn, &dn_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &rdn_len); if (rdn == NULL) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of Distiguished Name"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of Distinguished Name"); for (next_ava = rdn, next_ava_len = rdn_len; next_ava_len; ) { const u8 *ava, *dummy, *oidp; @@ -220,7 +222,7 @@ * The extension is identified by it's oid value. * NOTE: extensions can occur in any number or any order, which is why we * can't parse them with a single pass of the asn1 decoder. - * If is_critical is supplied, then it is set to 1 if the extention is critical + * If is_critical is supplied, then it is set to 1 if the extension is critical * and 0 if it is not. * The data in the extension is extension specific. * The following are common extension values: @@ -310,13 +312,13 @@ int sc_pkcs15_get_bitstring_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, const struct sc_object_id *type, - unsigned long long *value, int *is_critical) + unsigned int *value, int *is_critical) { int r; u8 *bit_string = NULL; size_t bit_string_len=0, val_len = sizeof(*value); struct sc_asn1_entry asn1_bit_string[] = { - { "bitString", SC_ASN1_BIT_STRING, SC_ASN1_TAG_BIT_STRING, 0, value, &val_len }, + { "bitString", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, value, &val_len }, { NULL, 0, 0, 0, NULL, NULL } }; @@ -539,8 +541,7 @@ return; } - if (cert->key) - sc_pkcs15_free_pubkey(cert->key); + sc_pkcs15_free_pubkey(cert->key); free(cert->subject); free(cert->issuer); free(cert->serial); @@ -555,7 +556,6 @@ { if (!cert) return; - if (cert->value.value) - free(cert->value.value); + free(cert->value.value); free(cert); } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-coolkey.c opensc-0.19.0/src/libopensc/pkcs15-coolkey.c --- opensc-0.17.0/src/libopensc/pkcs15-coolkey.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-coolkey.c 2018-09-13 11:47:21.000000000 +0000 @@ -484,7 +484,7 @@ sc_card_t *card = p15card->card; sc_serial_number_t serial; int count; - + struct sc_pkcs15_object *obj; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); @@ -539,6 +539,8 @@ /* set other objects */ r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_INIT_GET_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not initiate objects."); + for (i = 0; i < count; i++) { struct sc_cardctl_coolkey_object coolkey_obj; struct sc_pkcs15_object obj_obj; @@ -558,6 +560,8 @@ memset(&obj_obj, 0, sizeof(obj_obj)); + /* coolkey applets have label only on the certificates, + * but we should copy it also to the keys matching the same ID */ coolkey_get_attribute_bytes(card, &coolkey_obj, CKA_LABEL, (u8 *)obj_obj.label, &len, sizeof(obj_obj.label)); coolkey_get_flags(card, &coolkey_obj, &obj_obj.flags); if (obj_obj.flags & SC_PKCS15_CO_FLAG_PRIVATE) { @@ -676,6 +680,36 @@ } r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_FINAL_GET_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not finalize objects."); + + /* Iterate over all the created objects and fill missing labels */ + for (obj = p15card->obj_list; obj != NULL; obj = obj->next) { + struct sc_pkcs15_id *id = NULL; + struct sc_pkcs15_object *cert_object; + + /* label non-empty -- do not overwrite */ + if (obj->label[0] != '\0') + continue; + + switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) { + case SC_PKCS15_TYPE_PUBKEY: + id = &((struct sc_pkcs15_pubkey_info *)obj->data)->id; + break; + case SC_PKCS15_TYPE_PRKEY: + id = &((struct sc_pkcs15_prkey_info *)obj->data)->id; + break; + default: + /* We do not care about other objects */ + continue; + } + r = sc_pkcs15_find_cert_by_id(p15card, id, &cert_object); + if (r != 0) + continue; + + sc_log(card->ctx, "Copy label \"%s\" from cert to key object", + cert_object->label); + memcpy(obj->label, cert_object->label, SC_PKCS15_MAX_LABEL_SIZE); + } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-din-66291.c opensc-0.19.0/src/libopensc/pkcs15-din-66291.c --- opensc-0.17.0/src/libopensc/pkcs15-din-66291.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-din-66291.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,277 @@ +/* + * PKCS15 emulation layer for DIN 66291–4 profile. + * + * Copyright (C) 2017, Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "common/compat_strlcpy.h" +#include "log.h" +#include "pkcs15.h" +#include +#include + +static const unsigned char aid_CIA[] = {0xE8, 0x28, 0xBD, 0x08, 0x0F, + 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E}; +static const unsigned char aid_ESIGN[] = {0xA0, 0x00, 0x00, 0x01, 0x67, + 0x45, 0x53, 0x49, 0x47, 0x4E}; + +int din_66291_match_p15card(sc_pkcs15_card_t *p15card, struct sc_aid *aid) +{ + int ok = 0, r; + sc_path_t path; + unsigned char *tokeninfo_content = NULL; + struct sc_file *file_tokeninfo = NULL; + struct sc_pkcs15_tokeninfo *tokeninfo = sc_pkcs15_tokeninfo_new(); + + if (!p15card || !tokeninfo + || (aid && (aid->len != sizeof aid_CIA + || 0 != memcmp(aid->value, aid_CIA, sizeof aid_CIA)))) + goto err; + + if (p15card->tokeninfo + && p15card->tokeninfo->profile_indication.name + && 0 == strcmp("DIN V 66291", + p15card->tokeninfo->profile_indication.name)) { + ok = 1; + goto err; + } + + /* it is possible that p15card->tokeninfo has not been touched yet */ + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_CIA, sizeof aid_CIA, 0, 0); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) + goto err; + + sc_format_path("5032", &path); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, &file_tokeninfo)) + goto err; + + tokeninfo_content = malloc(file_tokeninfo->size); + if (!tokeninfo_content) + goto err; + r = sc_read_binary(p15card->card, 0, tokeninfo_content, file_tokeninfo->size, 0); + if (r < 0) + goto err; + r = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, tokeninfo, tokeninfo_content, r); + if (r != SC_SUCCESS) + goto err; + + if (tokeninfo->profile_indication.name + && 0 == strcmp("DIN V 66291", + tokeninfo->profile_indication.name)) { + ok = 1; + /* save tokeninfo and file_tokeninfo */ + sc_pkcs15_free_tokeninfo(p15card->tokeninfo); + sc_file_free(p15card->file_tokeninfo); + p15card->tokeninfo = tokeninfo; + p15card->file_tokeninfo = file_tokeninfo; + tokeninfo = NULL; + file_tokeninfo = NULL; + } + +err: + sc_pkcs15_free_tokeninfo(tokeninfo); + sc_file_free(file_tokeninfo); + free(tokeninfo_content); + + return ok; +} + + static int +sc_pkcs15emu_din_66291_init(sc_pkcs15_card_t *p15card) +{ + /* EF.C.CH.AUT + * fileIdentifier ´C5 00´ + * shortFileIdentifier ´01´= 1 + * PrK.CH.AUT + * keyIdentifier ´02´ = 2 + * privateKey …, Moduluslänge 2048 Bit + * + * EF.C.CH.ENC + * fileIdentifier ´C2 00´ + * shortFileIdentifier ´02´= 2 + * PrK.CH.ENC + * keyIdentifier ´03´ = 3 + * privateKey …, Moduluslänge 2048 Bit + */ + sc_path_t path; + size_t i; + struct sc_pin_cmd_data data; + const unsigned char user_pin_ref = 0x02; + sc_serial_number_t serial; + + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_ESIGN, sizeof aid_ESIGN, 0, 0); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) + return SC_ERROR_WRONG_CARD; + + memset(&data, 0, sizeof(data)); + data.cmd = SC_PIN_CMD_GET_INFO; + data.pin_type = SC_AC_CHV; + data.pin_reference = user_pin_ref; + + if (SC_SUCCESS == sc_pin_cmd(p15card->card, &data, NULL)) { + const unsigned char user_pin_id = 1; + + for (i = 0; i < 2; i++) { + const char *pin_names[3] = { "PIN", "PUK" }; + const int pin_min[] = {6, 10}; + const int pin_max[] = {8, 8}; + const unsigned char user_puk_id = 2; + const int pin_id[] = {user_pin_id, user_puk_id}; + const int pin_flags[] = {SC_PKCS15_PIN_FLAG_INITIALIZED, + SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED}; + const int max_tries[] = {3, 10}; + struct sc_pkcs15_auth_info pin_info; + struct sc_pkcs15_object pin_obj; + + memset(&pin_info, 0, sizeof(pin_info)); + memset(&pin_obj, 0, sizeof(pin_obj)); + + pin_info.auth_id.value[0] = pin_id[i]; + pin_info.auth_id.len = 1; + pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; + pin_info.attrs.pin.flags = pin_flags[i]; + pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; + pin_info.attrs.pin.min_length = pin_min[i]; + pin_info.attrs.pin.stored_length = pin_max[i]; + pin_info.attrs.pin.max_length = pin_max[i]; + pin_info.max_tries = max_tries[i]; + + strlcpy(pin_obj.label, pin_names[i], sizeof(pin_obj.label)); + + /* catch the differences between PIN and PUK */ + if (pin_flags[i] & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { + pin_info.tries_left = max_tries[i]; + } else { + pin_info.attrs.pin.reference = user_pin_ref; + pin_info.tries_left = data.pin1.tries_left; + pin_info.logged_in = data.pin1.logged_in; + pin_obj.auth_id.value[0] = user_puk_id; + pin_obj.auth_id.len = 1; + } + + if (0 > sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info)) + return SC_ERROR_INTERNAL; + } + + for (i = 0; i < 2; i++) { + struct sc_aid aid; + const char *din_66291_cert_fids[] = { "C500", "C200"}; + const char prk_id[] = { 0x10, 0x11,}; + struct sc_pkcs15_cert_info cert_info; + struct sc_pkcs15_object cert_obj; + struct sc_pkcs15_prkey_info prkey_info; + struct sc_pkcs15_object prkey_obj; + const int prk_usage[2] = { + SC_PKCS15_PRKEY_USAGE_ENCRYPT + | SC_PKCS15_PRKEY_USAGE_DECRYPT + | SC_PKCS15_PRKEY_USAGE_SIGN, + SC_PKCS15_PRKEY_USAGE_NONREPUDIATION}; + + memcpy(aid.value, aid_CIA, sizeof aid_CIA); + aid.len = sizeof aid_CIA; + + memset(&prkey_info, 0, sizeof(prkey_info)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + memset(&cert_info, 0, sizeof(cert_info)); + memset(&cert_obj, 0, sizeof(cert_obj)); + + + sc_format_path(din_66291_cert_fids[i], &cert_info.path); + if (SC_SUCCESS != sc_select_file(p15card->card, &cert_info.path, NULL)) + continue; + cert_info.path.aid = aid; + + cert_info.id.value[0] = prk_id[i]; + cert_info.id.len = 1; + + if (0 > sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info)) + continue; + + if (i == 0) { + sc_pkcs15_cert_t *cert; + if (SC_SUCCESS == sc_pkcs15_read_certificate(p15card, &cert_info, &cert)) { + static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; + u8 *cn_name = NULL; + size_t cn_len = 0; + sc_pkcs15_get_name_from_dn(p15card->card->ctx, cert->subject, + cert->subject_len, &cn_oid, &cn_name, &cn_len); + if (cn_len > 0) { + char *token_name = malloc(cn_len+1); + if (token_name) { + memcpy(token_name, cn_name, cn_len); + token_name[cn_len] = '\0'; + free(p15card->tokeninfo->label); + p15card->tokeninfo->label = token_name; + } + } + free(cn_name); + sc_pkcs15_free_certificate(cert); + } + } + + memset(&prkey_info, 0, sizeof(prkey_info)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + + prkey_info.id.value[0] = prk_id[i]; + prkey_info.id.len = 1; + prkey_info.usage = prk_usage[i]; + prkey_info.native = 1; + prkey_info.key_reference = prk_id[i]; + prkey_info.modulus_length = 2048; + prkey_obj.auth_id.value[0] = user_pin_id; + prkey_obj.auth_id.len = 1; + prkey_obj.user_consent = 0; + prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; + + if (0 > sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info)) + continue; + } + } + + /* get the card serial number */ + if (!p15card->tokeninfo->serial_number + && SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serial)) { + char serial_hex[SC_MAX_SERIALNR*2+2]; + sc_bin_to_hex(serial.value, serial.len , serial_hex, sizeof serial_hex - 1, 0); + p15card->tokeninfo->serial_number = strdup(serial_hex); + } + + return SC_SUCCESS; +} + +int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid, + sc_pkcs15emu_opt_t *opts) +{ + if (!p15card || ! p15card->card) + return SC_ERROR_INVALID_ARGUMENTS; + + SC_FUNC_CALLED(p15card->card->ctx, 1); + + /* Check card */ + if (!(opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) { + if (!din_66291_match_p15card(p15card, aid)) + return SC_ERROR_WRONG_CARD; + } + + /* Init card */ + return sc_pkcs15emu_din_66291_init(p15card); +} diff -Nru opensc-0.17.0/src/libopensc/pkcs15-esinit.c opensc-0.19.0/src/libopensc/pkcs15-esinit.c --- opensc-0.17.0/src/libopensc/pkcs15-esinit.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-esinit.c 2018-09-13 11:47:21.000000000 +0000 @@ -55,6 +55,8 @@ /* get serial number */ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); + if (r != SC_SUCCESS) + return SC_ERROR_INTERNAL; r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); if (r != SC_SUCCESS) return SC_ERROR_INTERNAL; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-esteid.c opensc-0.19.0/src/libopensc/pkcs15-esteid.c --- opensc-0.17.0/src/libopensc/pkcs15-esteid.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-esteid.c 2018-09-13 11:47:21.000000000 +0000 @@ -33,6 +33,7 @@ #include "common/compat_strlcat.h" #include "internal.h" +#include "opensc.h" #include "pkcs15.h" #include "esteid.h" @@ -64,6 +65,7 @@ sc_card_t *card = p15card->card; unsigned char buff[128]; int r, i; + size_t field_length = 0, modulus_length = 0; sc_path_t tmppath; set_string (&p15card->tokeninfo->label, "ID-kaart"); @@ -74,10 +76,10 @@ r = sc_select_file (card, &tmppath, NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "select esteid PD failed"); - /* read the serial (document number) */ + /* read the serial (document number) */ r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "read document number failed"); - buff[r] = '\0'; + buff[MIN((size_t) r, (sizeof buff)-1)] = '\0'; set_string (&p15card->tokeninfo->serial_number, (const char *) buff); p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION @@ -93,10 +95,10 @@ "3f00eeeeaace", "3f00eeeeddce"}; static int esteid_cert_ids[2] = {1, 2}; - + struct sc_pkcs15_cert_info cert_info; struct sc_pkcs15_object cert_obj; - + memset(&cert_info, 0, sizeof(cert_info)); memset(&cert_obj, 0, sizeof(cert_obj)); @@ -108,8 +110,14 @@ if (r < 0) return SC_ERROR_INTERNAL; if (i == 0) { - sc_pkcs15_cert_t *cert; + sc_pkcs15_cert_t *cert = NULL; r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert); + if (r < 0) + return SC_ERROR_INTERNAL; + if (cert->key->algorithm == SC_ALGORITHM_EC) + field_length = cert->key->u.ec.params.field_length; + else + modulus_length = cert->key->u.rsa.modulus.len * 8; if (r == SC_SUCCESS) { static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; u8 *cn_name = NULL; @@ -155,16 +163,16 @@ memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); - + /* read the number of tries left for the PIN */ r = sc_read_record (card, i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR); if (r < 0) return SC_ERROR_INTERNAL; tries_left = buff[5]; - + pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = esteid_pin_authid[i]; - pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; + pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = esteid_pin_ref[i]; pin_info.attrs.pin.flags = esteid_pin_flags[i]; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; @@ -188,16 +196,11 @@ if (r < 0) return SC_ERROR_INTERNAL; } - + /* add private keys */ for (i = 0; i < 2; i++) { static int prkey_pin[2] = {1, 2}; - static int prkey_usage[2] = { - SC_PKCS15_PRKEY_USAGE_ENCRYPT - | SC_PKCS15_PRKEY_USAGE_DECRYPT - | SC_PKCS15_PRKEY_USAGE_SIGN, - SC_PKCS15_PRKEY_USAGE_NONREPUDIATION}; - + static const char *prkey_name[2] = { "Isikutuvastus", "Allkirjastamine"}; @@ -207,16 +210,19 @@ memset(&prkey_info, 0, sizeof(prkey_info)); memset(&prkey_obj, 0, sizeof(prkey_obj)); - + prkey_info.id.len = 1; prkey_info.id.value[0] = prkey_pin[i]; - prkey_info.usage = prkey_usage[i]; prkey_info.native = 1; prkey_info.key_reference = i + 1; - if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30) - prkey_info.modulus_length = 2048; + prkey_info.field_length = field_length; + prkey_info.modulus_length = modulus_length; + if (i == 1) + prkey_info.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + else if(field_length > 0) // ECC has sign and derive usage + prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DERIVE; else - prkey_info.modulus_length = 1024; + prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT; strlcpy(prkey_obj.label, prkey_name[i], sizeof(prkey_obj.label)); prkey_obj.auth_id.len = 1; @@ -224,7 +230,10 @@ prkey_obj.user_consent = 0; prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; - r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); + if(field_length > 0) + r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); + else + r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); if (r < 0) return SC_ERROR_INTERNAL; } @@ -236,7 +245,7 @@ { if (is_esteid_card(p15card->card)) return SC_SUCCESS; - else + else return SC_ERROR_WRONG_CARD; } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-gemsafeGPK.c opensc-0.19.0/src/libopensc/pkcs15-gemsafeGPK.c --- opensc-0.17.0/src/libopensc/pkcs15-gemsafeGPK.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-gemsafeGPK.c 2018-09-13 11:47:21.000000000 +0000 @@ -225,9 +225,11 @@ p15card->tokeninfo->manufacturer_id = strdup(MANU_ID); /* get serial number */ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); + if (r != SC_SUCCESS) + return SC_ERROR_INTERNAL; r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); - if (r != SC_SUCCESS) - return SC_ERROR_INTERNAL; + if (r != SC_SUCCESS) + return SC_ERROR_INTERNAL; p15card->tokeninfo->serial_number = strdup(buf); /* test if we have a gemsafe app df */ @@ -291,7 +293,7 @@ if (r < 0) continue; - /* need to reverse the modulus skiping the tag */ + /* need to reverse the modulus skipping the tag */ j = kinfo[num_keyinfo].modulus_len; cp = kinfo[num_keyinfo].modulus; while (j--) @@ -326,7 +328,7 @@ if (!gsdata) return SC_ERROR_OUT_OF_MEMORY; - /* set indcies of data in gsdata */ + /* set indices of data in gsdata */ idx1 = 0; /* start point */ idx2 = 0; /* index of last data read so far */ @@ -479,7 +481,7 @@ prkey_info.modulus_length= prkeys[i].modulus_len; sc_format_path(prkeys[i].path, &prkey_info.path); - /*DEE need to look for them by reading and checking mudulus vs cert */ + /*DEE need to look for them by reading and checking modulus vs cert */ /* will use the default path, unless we found a key with */ /* the same modulus as the cert(s) we already added */ diff -Nru opensc-0.17.0/src/libopensc/pkcs15-gemsafeV1.c opensc-0.19.0/src/libopensc/pkcs15-gemsafeV1.c --- opensc-0.17.0/src/libopensc/pkcs15-gemsafeV1.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-gemsafeV1.c 2018-09-13 11:47:21.000000000 +0000 @@ -208,7 +208,7 @@ * the private key. */ ind = 2; /* skip length */ - while (ibuf[ind] == 0x01) { + while (ibuf[ind] == 0x01 && i < gemsafe_cert_max) { if (ibuf[ind+1] == 0xFE) { gemsafe_prkeys[i].ref = ibuf[ind+4]; sc_log(card->ctx, "Key container %d is allocated and uses key_ref %d", @@ -225,7 +225,7 @@ } /* Delete additional key containers from the data structures if - * this card can't accomodate them. + * this card can't accommodate them. */ for (; i < gemsafe_cert_max; i++) { gemsafe_prkeys[i].label = NULL; @@ -325,7 +325,7 @@ apdu.cla = 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); - /* Manual says Le=0x05, but should be 0x08 to return full version numer */ + /* Manual says Le=0x05, but should be 0x08 to return full version number */ apdu.le = 0x08; apdu.lc = 0; apdu.datalen = 0; diff -Nru opensc-0.17.0/src/libopensc/pkcs15.h opensc-0.19.0/src/libopensc/pkcs15.h --- opensc-0.17.0/src/libopensc/pkcs15.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15.h 2018-09-13 11:47:21.000000000 +0000 @@ -611,7 +611,7 @@ /* flags suitable for struct sc_pkcs15_card */ #define SC_PKCS15_CARD_FLAG_EMULATED 0x02000000 -/* X509 bits for certificate usage extansion */ +/* X509 bits for certificate usage extension */ #define SC_X509_DIGITAL_SIGNATURE 0x0001UL #define SC_X509_NON_REPUDIATION 0x0002UL #define SC_X509_KEY_ENCIPHERMENT 0x0004UL @@ -647,6 +647,8 @@ struct sc_pkcs15_card * sc_pkcs15_card_new(void); void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card); void sc_pkcs15_card_clear(struct sc_pkcs15_card *p15card); +struct sc_pkcs15_tokeninfo * sc_pkcs15_tokeninfo_new(void); +void sc_pkcs15_free_tokeninfo(struct sc_pkcs15_tokeninfo *tokeninfo); int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *prkey_obj, @@ -738,7 +740,7 @@ int sc_pkcs15_get_bitstring_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, const struct sc_object_id *type, - unsigned long long *value, + unsigned int *value, int *is_critical); /* sc_pkcs15_create_cdf: Creates a new certificate DF on a card pointed * by . Information about the file, such as the file ID, is read @@ -883,7 +885,7 @@ struct sc_pkcs15_card *p15card, u8 **buf, size_t *buflen); -/* Deduce private key attributes from cerresponding certificate */ +/* Deduce private key attributes from corresponding certificate */ int sc_pkcs15_prkey_attrs_from_cert(struct sc_pkcs15_card *, struct sc_pkcs15_object *, struct sc_pkcs15_object **); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-iasecc.c opensc-0.19.0/src/libopensc/pkcs15-iasecc.c --- opensc-0.17.0/src/libopensc/pkcs15-iasecc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-iasecc.c 2018-09-13 11:47:21.000000000 +0000 @@ -37,7 +37,7 @@ #include "iasecc.h" #include "aux-data.h" -#define IASECC_GEMALTO_MD_APPLICAITON_NAME "CSP" +#define IASECC_GEMALTO_MD_APPLICATION_NAME "CSP" #define IASECC_GEMALTO_MD_DEFAULT_CONT_LABEL "Default Key Container" static int @@ -60,7 +60,6 @@ LOG_TEST_RET(ctx, rv, "Failed to read container DATA object data"); offs = 0; - rv = SC_ERROR_INVALID_DATA; if (*(ddata->data + offs++) != 0x01) { sc_pkcs15_free_data_object(ddata); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); @@ -138,7 +137,7 @@ for(ii=0; iidata; - if (strcmp(dinfo->app_label, IASECC_GEMALTO_MD_APPLICAITON_NAME)) + if (strcmp(dinfo->app_label, IASECC_GEMALTO_MD_APPLICATION_NAME)) continue; if (!strcmp(dobjs[ii]->label, IASECC_GEMALTO_MD_DEFAULT_CONT_LABEL)) { @@ -152,7 +151,7 @@ struct sc_pkcs15_data_info *dinfo = (struct sc_pkcs15_data_info *)dobjs[ii]->data; int default_cont = 0; - if (strcmp(dinfo->app_label, IASECC_GEMALTO_MD_APPLICAITON_NAME)) + if (strcmp(dinfo->app_label, IASECC_GEMALTO_MD_APPLICATION_NAME)) continue; if (!strcmp(dobjs[ii]->label, IASECC_GEMALTO_MD_DEFAULT_CONT_LABEL)) diff -Nru opensc-0.17.0/src/libopensc/pkcs15-infocamere.c opensc-0.19.0/src/libopensc/pkcs15-infocamere.c --- opensc-0.17.0/src/libopensc/pkcs15-infocamere.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-infocamere.c 2018-09-13 11:47:21.000000000 +0000 @@ -166,10 +166,7 @@ sc_card_t *card = p15card->card; sc_path_t path; - sc_file_t *file; sc_pkcs15_id_t id, auth_id; - unsigned char buffer[256]; - unsigned char ef_gdo[256]; char serial[256]; unsigned char certlen[2]; int authority, change_sign = 0; @@ -235,64 +232,34 @@ SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_NEEDS_PADDING; - int r, len_iccsn, len_chn; - - sc_format_path("3F002F02", &path); - - r = sc_select_file(card, &path, &file); - - if (r != SC_SUCCESS || file->size > 255) { - /* Not EF.GDO */ - sc_file_free(file); - return SC_ERROR_WRONG_CARD; - } - - sc_read_binary(card, 0, ef_gdo, file->size, 0); - - if (ef_gdo[0] != 0x5A || file->size < 3) { - /* Not EF.GDO */ - sc_file_free(file); - return SC_ERROR_WRONG_CARD; - } - - len_iccsn = ef_gdo[1]; + int r; - memcpy(buffer, ef_gdo + 2, len_iccsn); + unsigned char chn[8]; + size_t chn_len = sizeof chn; + sc_serial_number_t iccsn; + iccsn.len = sizeof iccsn.value; - sc_bin_to_hex(buffer, len_iccsn, serial, sizeof(serial), 0); - if (file->size < (size_t) (len_iccsn + 5)) { - /* Not CHN */ - sc_file_free(file); - return SC_ERROR_WRONG_CARD; - } - sc_file_free(file); + r = sc_parse_ef_gdo(card, iccsn.value, &iccsn.len, chn, &chn_len); + if (r < 0) + return r; - if (! - (ef_gdo[len_iccsn + 2] == 0x5F - && ef_gdo[len_iccsn + 3] == 0x20)) { - /* Not CHN */ + if (!iccsn.len || chn_len < 2 || chn_len > 8) { return SC_ERROR_WRONG_CARD; } - len_chn = ef_gdo[len_iccsn + 4]; - - if (len_chn < 2 || len_chn > 8) { - /* Length CHN incorrect */ - return SC_ERROR_WRONG_CARD; - } + sc_bin_to_hex(iccsn.value, iccsn.len, serial, sizeof(serial), 0); if (! - (ef_gdo[len_iccsn + 5] == 0x12 - && (ef_gdo[len_iccsn + 6] == 0x02 - || ef_gdo[len_iccsn + 6] == 0x03))) { + (chn[0] == 0x12 + && (chn[1] == 0x02 || chn[1] == 0x03))) { /* Not Infocamere Card */ return SC_ERROR_WRONG_CARD; } set_string(&p15card->tokeninfo->serial_number, serial); - if (ef_gdo[len_iccsn + 6] == 0x02) + if (chn[1] == 0x02) set_string(&p15card->tokeninfo->label, "Infocamere 1202 Card"); else { set_string(&p15card->tokeninfo->label, "Infocamere 1203 Card"); @@ -305,7 +272,7 @@ /* Get the authentication certificate length */ - sc_format_path(infocamere_auth_certpath[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_auth_certpath[chn[1]-2], &path); r = sc_select_file(card, &path, NULL); @@ -336,11 +303,11 @@ if (!change_sign) { /* add authentication PIN */ - sc_format_path(infocamere_auth_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_auth_path[chn[1]-2], &path); sc_pkcs15_format_id("01", &id); sc_pkcs15emu_add_pin(p15card, &id, - authPIN, &path, infocamere_idpin_auth_obj[ef_gdo[len_iccsn+6]-2], + authPIN, &path, infocamere_idpin_auth_obj[chn[1]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); @@ -354,7 +321,7 @@ authPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, authprkey_usage, - &path, infocamere_idprkey_auth_obj[ef_gdo[len_iccsn+6]-2], + &path, infocamere_idprkey_auth_obj[chn[1]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); } @@ -362,7 +329,7 @@ /* Get the non-repudiation certificate length */ - sc_format_path(infocamere_cert_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_cert_path[chn[1]-2], &path); if (sc_select_file(card, &path, NULL) < 0) { return SC_ERROR_INTERNAL; @@ -392,7 +359,7 @@ authority = 1; - sc_format_path(infocamere_cacert_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_cacert_path[chn[1]-2], &path); r = sc_select_file(card, &path, NULL); @@ -425,11 +392,11 @@ /* add non repudiation PIN */ - sc_format_path(infocamere_nrepud_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_nrepud_path[chn[1]-2], &path); sc_pkcs15_format_id("02", &id); sc_pkcs15emu_add_pin(p15card, &id, - nonrepPIN, &path, infocamere_idpin_nrepud_obj[ef_gdo[len_iccsn+6]-2], + nonrepPIN, &path, infocamere_idpin_nrepud_obj[chn[1]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); @@ -442,7 +409,7 @@ sc_pkcs15emu_add_prkey(p15card, &id, nonrepPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, prkey_usage, - &path, infocamere_idprkey_nrepud_obj[ef_gdo[len_iccsn+6]-2], + &path, infocamere_idprkey_nrepud_obj[chn[1]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); @@ -810,7 +777,7 @@ /* return to MF */ sc_format_path("3F00", &path); - r = sc_select_file(card, &path, NULL); + sc_select_file(card, &path, NULL); return SC_SUCCESS; } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-itacns.c opensc-0.19.0/src/libopensc/pkcs15-itacns.c --- opensc-0.17.0/src/libopensc/pkcs15-itacns.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-itacns.c 2018-09-13 11:47:21.000000000 +0000 @@ -401,7 +401,7 @@ { /* * Bytes 0-5 contain the ASCII encoding of the following TLV - * strcture's total size, in base 16. + * structure's total size, in base 16. */ const unsigned int EF_personaldata_maxlen = 400; @@ -473,8 +473,10 @@ if (fields[f_first_name].len + fields[f_last_name].len + 1 >= name_len) return -1; - snprintf(name, name_len, "%s %s", - fields[f_first_name].value, fields[f_last_name].value); + /* the lengths are already checked that they will fit in buffer */ + snprintf(name, name_len, "%.*s %.*s", + fields[f_first_name].len, fields[f_first_name].value, + fields[f_last_name].len, fields[f_last_name].value); return 0; } @@ -548,6 +550,7 @@ sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Could not read EF_DatiPersonali: " "keeping generic card name"); + return SC_SUCCESS; } { @@ -651,7 +654,7 @@ sc_path_t path; sc_pkcs15_id_t cert_id; int ext_info_ok; - int ku, xku; + int ku = 0, xku = 0; int pubkey_usage_flags = 0, prkey_usage_flags = 0; cert_id.len = 1; @@ -687,7 +690,7 @@ "Could not read certificate file"); path.index = cert_offset; path.count = (certlen[1] << 8) + certlen[2]; - /* If those bytes are 00, then we are probably dealign with an + /* If those bytes are 00, then we are probably dealing with an * empty file. */ if (path.count == 0) return 0; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-jpki.c opensc-0.19.0/src/libopensc/pkcs15-jpki.c --- opensc-0.17.0/src/libopensc/pkcs15-jpki.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-jpki.c 2018-09-13 11:47:21.000000000 +0000 @@ -164,7 +164,7 @@ "User Authentication Key", "Digital Signature Key" }; - + static int prkey_user_consent[2] = { 0, 1 }; struct sc_pkcs15_prkey_info prkey_info; struct sc_pkcs15_object prkey_obj; @@ -181,13 +181,44 @@ strlcpy(prkey_obj.label, prkey_name[i], sizeof (prkey_obj.label)); prkey_obj.auth_id.len = 1; prkey_obj.auth_id.value[0] = prkey_pin[i]; - prkey_obj.user_consent = 0; + prkey_obj.user_consent = prkey_user_consent[i]; prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; rc = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); if (rc < 0) LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); } + + /* add public keys */ + for (i = 0; i < 2; i++) { + static int pubkey_id[2] = { 1, 2 }; + static const char *jpki_pubkey_names[2] = { + "User Authentication Public Key", + "Digital Signature Public Key" + }; + struct sc_pkcs15_pubkey_info pubkey_info; + struct sc_pkcs15_object pubkey_obj; + static char const *jpki_pubkey_paths[2] = { + "000A", + "0001" + }; + + memset(&pubkey_info, 0, sizeof (pubkey_info)); + memset(&pubkey_obj, 0, sizeof (pubkey_obj)); + + strlcpy(pubkey_obj.label, jpki_pubkey_names[i], sizeof (pubkey_obj.label)); + pubkey_info.id.len = 1; + pubkey_info.id.value[0] = pubkey_id[i]; + pubkey_info.native = 1; + pubkey_info.key_reference = i + 1; + + sc_format_path(jpki_pubkey_paths[i], &pubkey_info.path); + pubkey_info.path.type = SC_PATH_TYPE_FILE_ID; + + rc = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); + if (rc < 0) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-oberthur.c opensc-0.19.0/src/libopensc/pkcs15-oberthur.c --- opensc-0.17.0/src/libopensc/pkcs15-oberthur.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-oberthur.c 2018-09-13 11:47:21.000000000 +0000 @@ -29,6 +29,7 @@ #include #include #include +#include "../common/compat_strlcpy.h" #include "pkcs15.h" #include "log.h" @@ -593,7 +594,7 @@ LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'ID'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (!len || len > sizeof(key_info.id.value)) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalie 'ID' length"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalid 'ID' length"); memcpy(key_info.id.value, info_blob + offs + 2, len); key_info.id.len = len; @@ -663,7 +664,7 @@ LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'ID'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len > sizeof(cinfo.id.value)) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add certificate: invalie 'ID' length"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add certificate: invalid 'ID' length"); memcpy(cinfo.id.value, info_blob + offs + 2, len); cinfo.id.len = len; @@ -738,7 +739,7 @@ unsigned int id = path.value[path.len - 2] * 0x100 + path.value[path.len - 1]; if (id == ccont.id_cert) { - strncpy(kobj.label, objs[ii]->label, sizeof(kobj.label) - 1); + strlcpy(kobj.label, objs[ii]->label, sizeof(kobj.label)); break; } } @@ -1081,7 +1082,7 @@ LOG_FUNC_RETURN(ctx, SC_SUCCESS); rv = sc_oberthur_read_file(p15card, AWP_OBJECTS_LIST_PRV, &buf, &buf_len, 1); - LOG_TEST_RET(ctx, rv, "Parse DF: read pribate objects info failed"); + LOG_TEST_RET(ctx, rv, "Parse DF: read private objects info failed"); rv = sc_oberthur_parse_privateinfo(p15card, buf, buf_len, 0); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-openpgp.c opensc-0.19.0/src/libopensc/pkcs15-openpgp.c --- opensc-0.17.0/src/libopensc/pkcs15-openpgp.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-openpgp.c 2018-09-13 11:47:21.000000000 +0000 @@ -106,18 +106,25 @@ } pgp_manuf_map_t; static const pgp_manuf_map_t manuf_map[] = { - { 0x0001, "PPC Card Systems" }, - { 0x0002, "Prism" }, - { 0x0003, "OpenFortress" }, - { 0x0004, "Wewid AB" }, - { 0x0005, "ZeitControl" }, - { 0x0006, "Yubico" }, - { 0x0007, "OpenKMS" }, - { 0x0008, "LogoEmail" }, - { 0x002A, "Magrathea" }, - { 0xF517, "FSIJ" }, - { 0x0000, "test card" }, - { 0xffff, "test card" }, + { 0x0001, "PPC Card Systems" }, + { 0x0002, "Prism" }, + { 0x0003, "OpenFortress" }, + { 0x0004, "Wewid AB" }, + { 0x0005, "ZeitControl" }, + { 0x0006, "Yubico" }, + { 0x0007, "OpenKMS" }, + { 0x0008, "LogoEmail" }, + { 0x0009, "Fidesmo" }, + { 0x000A, "Dangerous Things" }, + { 0x002A, "Magrathea" }, + { 0x0042, "GnuPG e.V." }, + { 0x1337, "Warsaw Hackerspace" }, + { 0x2342, "warpzone" }, + { 0x63AF, "Trustica" }, + { 0xBD0E, "Paranoidlabs" }, + { 0xF517, "FSIJ" }, + { 0x0000, "test card" }, + { 0xffff, "test card" }, { 0, NULL } }; @@ -147,6 +154,9 @@ if (file->size < len) len = file->size; + + sc_file_free(file); + return sc_read_binary(card, 0, (u8 *) buf, len, 0); } @@ -159,10 +169,10 @@ u8 c4data[10]; u8 c5data[70]; int r, i; - const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? pin_cfg_v2 : pin_cfg_v1; + const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V1) + ? pin_cfg_v1 : pin_cfg_v2; sc_path_t path; - sc_file_t *file; + sc_file_t *file = NULL; set_string(&p15card->tokeninfo->label, "OpenPGP card"); set_string(&p15card->tokeninfo->manufacturer_id, "OpenPGP project"); @@ -368,13 +378,19 @@ goto failed; } - /* PKCS#15 DATA object from OpenPGP private DOs */ - r = sc_pkcs15emu_openpgp_add_data(p15card); + /* Add PKCS#15 DATA objects from other OpenPGP card DOs. The return + * value is ignored, so this will not cause initialization to fail. + */ + sc_pkcs15emu_openpgp_add_data(p15card); - return 0; +failed: + if (r < 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Failed to initialize OpenPGP emulation: %s\n", + sc_strerror(r)); + } + sc_file_free(file); -failed: sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP emulation: %s\n", - sc_strerror(r)); return r; } @@ -385,7 +401,7 @@ int i, r; LOG_FUNC_CALLED(ctx); - /* There is 4 private DO from 0101 to 0104 */ + /* Optional private use DOs 0101 to 0104 */ for (i = 1; i <= PGP_NUM_PRIVDO; i++) { sc_pkcs15_data_info_t dat_info; sc_pkcs15_object_t dat_obj; @@ -398,8 +414,8 @@ snprintf(name, 8, "PrivDO%d", i); snprintf(path, 9, "3F00010%d", i); - /* Check if the DO can be read. - * We won't expose pkcs15 DATA object if DO is empty. + /* Check if the DO can be read and is not empty. Otherwise we + * won't expose a PKCS#15 DATA object. */ r = read_file(p15card->card, path, content, sizeof(content)); if (r <= 0 ) { @@ -421,14 +437,18 @@ sc_log(ctx, "Add %s data object", name); r = sc_pkcs15emu_add_data_object(p15card, &dat_obj, &dat_info); + LOG_TEST_RET(ctx, r, "Could not add data object to framework"); } - LOG_FUNC_RETURN(ctx, r); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } static int openpgp_detect_card(sc_pkcs15_card_t *p15card) { - if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2 - || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK) + if (p15card->card->type == SC_CARD_TYPE_OPENPGP_BASE + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2 + || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V3) return SC_SUCCESS; else return SC_ERROR_WRONG_CARD; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-pin.c opensc-0.19.0/src/libopensc/pkcs15-pin.c --- opensc-0.17.0/src/libopensc/pkcs15-pin.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-pin.c 2018-09-13 11:47:21.000000000 +0000 @@ -30,6 +30,7 @@ #include "internal.h" #include "asn1.h" #include "pkcs15.h" +#include "ui/notify.h" int _sc_pkcs15_verify_pin(struct sc_pkcs15_card *, struct sc_pkcs15_object *, const unsigned char *, size_t); @@ -358,11 +359,13 @@ "PIN(type:%X; method:%X; value(%p:%"SC_FORMAT_LEN_SIZE_T"u)", auth_info->auth_type, auth_info->auth_method, pincode, pinlen); + card = p15card->card; - if (pinlen > SC_MAX_PIN_SIZE) + if (pinlen > SC_MAX_PIN_SIZE) { + sc_notify_id(card->ctx, &card->reader->atr, p15card, + NOTIFY_PIN_BAD); LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_LENGTH, "Invalid PIN size"); - - card = p15card->card; + } /* Initialize arguments */ memset(&data, 0, sizeof(data)); @@ -408,10 +411,10 @@ data.pin_reference = skey_info->key_reference; } - 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 ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { + if (!pincode && !pinlen) + 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"; @@ -446,14 +449,23 @@ sc_log(ctx, "PIN cmd result %i", r); if (r == SC_SUCCESS) { sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen); - if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN) { + if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN && sessionpinlen) { *sessionpinlen = data.pin2.len; } } else { - if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN) { + sc_notify_id(card->ctx, &card->reader->atr, p15card, + NOTIFY_PIN_BAD); + if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN && sessionpinlen) { *sessionpinlen = 0; } } + + if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_PIN + && auth_info->auth_method != SC_AC_SESSION) { + sc_notify_id(card->ctx, &card->reader->atr, p15card, + r == SC_SUCCESS ? NOTIFY_PIN_GOOD : NOTIFY_PIN_BAD); + } + out: sc_unlock(card); LOG_FUNC_RETURN(ctx, r); @@ -688,7 +700,7 @@ /* Try to update PIN info from card */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_GET_INFO; - data.pin_type = SC_AC_CHV; + data.pin_type = pin_info->auth_method; data.pin_reference = pin_info->attrs.pin.reference; r = sc_pin_cmd(card, &data, NULL); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-piv.c opensc-0.19.0/src/libopensc/pkcs15-piv.c --- opensc-0.17.0/src/libopensc/pkcs15-piv.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-piv.c 2018-09-13 11:47:21.000000000 +0000 @@ -104,7 +104,7 @@ int pubkey_from_file; int key_alg; unsigned int pubkey_len; - unsigned long long cert_keyUsage; /* x509 key usage as defined in certificate */ + unsigned int cert_keyUsage; /* x509 key usage as defined in certificate */ int cert_keyUsage_present; /* 1 if keyUsage found in certificate */ int pub_usage; int priv_usage; @@ -119,7 +119,7 @@ * We need to return a GUID like value for each object * But this needs to be some what unique. * So we will use two different methods, depending - * on the size of the sereal number. + * on the size of the serial number. * If it is 25 bytes, then it was from a FASCN. If 16 bytes * its from a GUID. * If neither, we will uase the default method. @@ -153,12 +153,12 @@ if (id.len == 1 && serialnr.len == 25) { /* It is from a FASCN, and we need to shorten it but keep - * as much uniquness as possible. + * as much uniqueness as possible. * FASC-N is stored like a ISO 7811 Magnetic Strip Card * Using the ANSI/ISO BCD Data Format * 4 data bit + 1 parity bit (odd) least significant bit first. * It starts with the Start Sentinel 0x0b ";" - * Fields are seperated by 0x0d "=" + * Fields are separated by 0x0d "=" * Ends with End Sentinel 0x0f "?" * Its 39 characters + the LRC * http://www.dataip.co.uk/Reference/MagneticCardBCD.php @@ -323,7 +323,7 @@ }; /* * NIST 800-73-1 lifted the restriction on - * requering pin protected certs. Thus the default is to + * requiring pin protected certs. Thus the default is to * not require this. */ /* certs will be pulled out from the cert objects */ @@ -359,7 +359,7 @@ }; static const pindata pins[] = { - { "01", "PIV Card Holder pin", "", 0x80, + { "01", "PIN", "", 0x80, /* label, flag and ref will change if using global pin */ SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 8, 4, 8, @@ -386,7 +386,7 @@ * but can be derived from the certificates. * the cert, pubkey and privkey are a set. * Key usages bits taken from pkcs15v1_1 Table 2 - * RSA and EC hav differents set of usage + * RSA and EC have different sets of usage */ static const pubdata pubkeys[PIV_NUM_CERTS_AND_KEYS] = { @@ -528,83 +528,83 @@ { "05", "Retired KEY MAN 1", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x82, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x82, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "06", "Retired KEY MAN 2", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x83, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x83, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "07", "Retired KEY MAN 3", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x84, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x84, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "08", "Retired KEY MAN 4", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x85, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x85, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "09", "Retired KEY MAN 5", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x86, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x86, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "10", "Retired KEY MAN 6", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x87, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x87, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "11", "Retired KEY MAN 7", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x88, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x88, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "12", "Retired KEY MAN 8", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x89, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x89, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "13", "Retired KEY MAN 9", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8A, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8A, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "14", "Retired KEY MAN 10", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8B, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8B, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "15", "Retired KEY MAN 11", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8C, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8C, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "16", "Retired KEY MAN 12", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8D, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8D, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "17", "Retired KEY MAN 13", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8E, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8E, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "18", "Retired KEY MAN 14", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x8F, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x8F, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "19", "Retired KEY MAN 15", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x90, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x90, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "20", "Retired KEY MAN 16", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x91, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x91, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "21", "Retired KEY MAN 17", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x92, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x92, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "22", "Retired KEY MAN 18", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x93, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x93, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "23", "Retired KEY MAN 19", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x94, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, + "", 0x94, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, { "24", "Retired KEY MAN 20", /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, - "", 0x95, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1} + "", 0x95, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0} }; int r, i; @@ -613,7 +613,7 @@ char buf[SC_MAX_SERIALNR * 2 + 1]; common_key_info ckis[PIV_NUM_CERTS_AND_KEYS]; int follows_nist_fascn = 0; - + char *token_name = NULL; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); @@ -658,7 +658,7 @@ sc_format_path(objects[i].path, &obj_info.path); /* See if the object can not be present on the card */ - r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path); + r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path); if (r == 1) continue; /* Not on card, do not define the object */ @@ -699,7 +699,7 @@ * they are in order * We need to read the cert, get modulus and keylen * We use those for the pubkey, and priv key objects. - * If no cert, then see if pubkey (i.e. we are initilizing, + * If no cert, then see if pubkey (i.e. we are initializing, * and the pubkey is in a file,) then add pubkey and privkey * If no cert and no pubkey, skip adding them. @@ -734,7 +734,7 @@ cert_obj.flags = certs[i].obj_flags; /* See if the cert might be present or not. */ - r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path); + r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path); if (r == 1) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cert can not be present,i=%d", i); continue; @@ -765,6 +765,30 @@ sc_pkcs15_free_certificate(cert_out); continue; } + + /* set the token name to the name of the CN of the first certificate */ + if (!token_name) { + u8 * cn_name = NULL; + size_t cn_len = 0; + static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; + r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject, + cert_out->subject_len, &cn_oid, &cn_name, &cn_len); + if (r == SC_SUCCESS) { + token_name = malloc (cn_len+1); + if (!token_name) { + sc_pkcs15_free_certificate(cert_out); + free(cn_name); + SC_FUNC_RETURN(card->ctx, + SC_ERROR_OUT_OF_MEMORY, r); + } + memcpy(token_name, cn_name, cn_len); + free(cn_name); + token_name[cn_len] = 0; + free(p15card->tokeninfo->label); + p15card->tokeninfo->label = token_name; + } + } + /* * get keyUsage if present save in ckis[i] * Will only use it if this in a non FED issued card @@ -773,13 +797,11 @@ if (follows_nist_fascn == 0) { struct sc_object_id keyUsage_oid={{2,5,29,15,-1}}; - unsigned long long *value; int r = 0; - value = &ckis[i].cert_keyUsage; r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &keyUsage_oid, - value, NULL); + &ckis[i].cert_keyUsage, NULL); if ( r >= 0) ckis[i].cert_keyUsage_present = 1; /* TODO if no key usage, we could set all uses */ @@ -887,7 +909,7 @@ break; default: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key.algorithm %d", cert_out->key->algorithm); ckis[i].pubkey_len = 0; /* set some value for now */ } ckis[i].pubkey_from_cert = cert_out->key; @@ -926,13 +948,13 @@ label = pins[i].label; if (i == 0 && - (card->ops->card_ctl)(card, SC_CARDCTL_PIV_PIN_PREFERENCE, + sc_card_ctl(card, SC_CARDCTL_PIV_PIN_PREFERENCE, &pin_ref) == 0 && pin_ref == 0x00) { /* must be 80 for PIV pin, or 00 for Global PIN */ pin_info.attrs.pin.reference = pin_ref; pin_info.attrs.pin.flags &= ~SC_PKCS15_PIN_FLAG_LOCAL; label = "Global PIN"; - } + } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label); strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1); pin_obj.flags = pins[i].obj_flags; @@ -953,9 +975,9 @@ /* set public keys */ - /* We may only need this during initialzation when genkey + /* We may only need this during initialization when genkey * gets the pubkey, but it can not be read from the card - * at a later time. The piv-tool can stach pubkey in file + * at a later time. The piv-tool can stash pubkey in file */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pub keys..."); for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) { @@ -981,7 +1003,7 @@ if (pubkeys[i].auth_id) sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id); - /* If no cert found, piv-tool may have stached the pubkey + /* If no cert found, piv-tool may have stashed the pubkey * so we can use it when generating a certificate request * The file is a OpenSSL DER EVP_KEY, which looks like * a certificate subjectPublicKeyInfo. @@ -1120,18 +1142,18 @@ strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); prkey_obj.flags = prkeys[i].obj_flags; - prkey_obj.user_consent = prkeys[i].user_consent; + prkey_obj.user_consent = prkeys[i].user_consent; /* only Sign key */ if (prkeys[i].auth_id) sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id); /* * When no cert is present and a pubkey in a file was found, - * means the caller is initilaizeing a card. A sign operation + * means the caller is initializing a card. A sign operation * will be required to sign a certificate request even if * normal usage would not allow it. Set SC_PKCS15_PRKEY_USAGE_SIGN - * TODO if code is added to allow key generation and reqest - * sign in the same session, similiar code will be needed. + * TODO if code is added to allow key generation and request + * sign in the same session, similar code will be needed. */ if (ckis[i].pubkey_from_file == 1) { @@ -1143,6 +1165,10 @@ case SC_ALGORITHM_RSA: if(ckis[i].cert_keyUsage_present) { prkey_info.usage |= ckis[i].priv_usage; + /* If retired key and non gov cert has NONREPUDIATION, treat as user_consent */ + if (i >= 4 && (ckis[i].priv_usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) { + prkey_obj.user_consent = 1; + } } else { prkey_info.usage |= prkeys[i].usage_rsa; } @@ -1152,6 +1178,10 @@ case SC_ALGORITHM_EC: if (ckis[i].cert_keyUsage_present) { prkey_info.usage |= ckis[i].priv_usage; + /* If retired key and non gov cert has NONREPUDIATION, treat as user_consent */ + if (i >= 4 && (ckis[i].priv_usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) { + prkey_obj.user_consent = 1; + } } else { prkey_info.usage |= prkeys[i].usage_ec; } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-pubkey.c opensc-0.19.0/src/libopensc/pkcs15-pubkey.c --- opensc-0.17.0/src/libopensc/pkcs15-pubkey.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-pubkey.c 2018-09-13 11:47:21.000000000 +0000 @@ -200,7 +200,7 @@ LOG_TEST_RET(ctx, rv, "Failed to decode 'SPKI' direct value"); rv = sc_pkcs15_encode_pubkey(ctx, pubkey, &info->direct.raw.value, &info->direct.raw.len); - LOG_TEST_RET(ctx, rv, "Failed to endode 'RAW' direct value"); + LOG_TEST_RET(ctx, rv, "Failed to encode 'RAW' direct value"); sc_pkcs15_free_pubkey(pubkey); } @@ -939,7 +939,6 @@ pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); if (pubkey == NULL) { - free(data); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } pubkey->algorithm = algorithm; @@ -990,10 +989,11 @@ } err: - if (r) + if (r) { sc_pkcs15_free_pubkey(pubkey); - else + } else *out = pubkey; + free(data); LOG_FUNC_RETURN(ctx, r); } @@ -1098,8 +1098,10 @@ rv = sc_asn1_encode_algorithm_id(ctx, &alg, &alglen,key->alg_id, 0); if (rv == SC_SUCCESS) { pubkey->alg_id = (struct sc_algorithm_id *)calloc(1, sizeof(struct sc_algorithm_id)); - if (pubkey->alg_id == NULL) + if (pubkey->alg_id == NULL) { + free(pubkey); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + } rv = sc_asn1_decode_algorithm_id(ctx, alg, alglen, pubkey->alg_id, 0); free(alg); } @@ -1234,7 +1236,7 @@ int r; int f = -1; size_t len, offs; - u8 tagbuf[1024]; /* enough to read in the tag and length */ + u8 tagbuf[16]; /* enough to read in the tag and length */ u8 * rbuf = NULL; size_t rbuflen = 0; const u8 * body = NULL; @@ -1264,10 +1266,10 @@ body = tagbuf; r = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen); - if (r != SC_SUCCESS) + if (r != SC_SUCCESS && r != SC_ERROR_ASN1_END_OF_CONTENTS) goto out; - if (tag_out == SC_ASN1_TAG_EOC || body == NULL) { + if (body == NULL) { r = SC_SUCCESS; goto out; } @@ -1389,8 +1391,10 @@ } pubkey->u.ec.ecpointQ.value = malloc(pk.len); - if (pubkey->u.ec.ecpointQ.value == NULL) - LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + if (pubkey->u.ec.ecpointQ.value == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + LOG_TEST_GOTO_ERR(ctx, r, "failed to malloc() memory"); + } memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len); pubkey->u.ec.ecpointQ.len = pk.len; } @@ -1486,6 +1490,8 @@ {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224}, {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256}, {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320}, + {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384}, + {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512}, {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192}, {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256}, diff -Nru opensc-0.17.0/src/libopensc/pkcs15-sc-hsm.c opensc-0.19.0/src/libopensc/pkcs15-sc-hsm.c --- opensc-0.17.0/src/libopensc/pkcs15-sc-hsm.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-sc-hsm.c 2018-09-13 11:47:21.000000000 +0000 @@ -62,6 +62,15 @@ { (unsigned char *) "\x01", 1} }, { + { (unsigned char *) "\x2B\x81\x04\x00\x23", 5}, // secp521r1 + { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, + { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC", 66}, + { (unsigned char *) "\x00\x51\x95\x3E\xB9\x61\x8E\x1C\x9A\x1F\x92\x9A\x21\xA0\xB6\x85\x40\xEE\xA2\xDA\x72\x5B\x99\xB3\x15\xF3\xB8\xB4\x89\x91\x8E\xF1\x09\xE1\x56\x19\x39\x51\xEC\x7E\x93\x7B\x16\x52\xC0\xBD\x3B\xB1\xBF\x07\x35\x73\xDF\x88\x3D\x2C\x34\xF1\xEF\x45\x1F\xD4\x6B\x50\x3F\x00", 66}, + { (unsigned char *) "\x04\x00\xC6\x85\x8E\x06\xB7\x04\x04\xE9\xCD\x9E\x3E\xCB\x66\x23\x95\xB4\x42\x9C\x64\x81\x39\x05\x3F\xB5\x21\xF8\x28\xAF\x60\x6B\x4D\x3D\xBA\xA1\x4B\x5E\x77\xEF\xE7\x59\x28\xFE\x1D\xC1\x27\xA2\xFF\xA8\xDE\x33\x48\xB3\xC1\x85\x6A\x42\x9B\xF9\x7E\x7E\x31\xC2\xE5\xBD\x66\x01\x18\x39\x29\x6A\x78\x9A\x3B\xC0\x04\x5C\x8A\x5F\xB4\x2C\x7D\x1B\xD9\x98\xF5\x44\x49\x57\x9B\x44\x68\x17\xAF\xBD\x17\x27\x3E\x66\x2C\x97\xEE\x72\x99\x5E\xF4\x26\x40\xC5\x50\xB9\x01\x3F\xAD\x07\x61\x35\x3C\x70\x86\xA2\x72\xC2\x40\x88\xBE\x94\x76\x9F\xD1\x66\x50", 133}, + { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFA\x51\x86\x87\x83\xBF\x2F\x96\x6B\x7F\xCC\x01\x48\xF7\x09\xA5\xD0\x3B\xB5\xC9\xB8\x89\x9C\x47\xAE\xBB\x6F\xB7\x1E\x91\x38\x64\x09", 66}, + { (unsigned char *) "\x01", 1} + }, + { { (unsigned char *) "\x2B\x24\x03\x03\x02\x08\x01\x01\x03", 9}, // brainpoolP192r1 { (unsigned char *) "\xC3\x02\xF4\x1D\x93\x2A\x36\xCD\xA7\xA3\x46\x30\x93\xD1\x8D\xB7\x8F\xCE\x47\x6D\xE1\xA8\x62\x97", 24}, { (unsigned char *) "\x6A\x91\x17\x40\x76\xB1\xE0\xE1\x9C\x39\xC0\x31\xFE\x86\x85\xC1\xCA\xE0\x40\xE5\xC6\x9A\x28\xEF", 24}, @@ -98,6 +107,24 @@ { (unsigned char *) "\x01", 1} }, { + { (unsigned char *) "\x2B\x24\x03\x03\x02\x08\x01\x01\x0B", 9}, // brainpoolP384r1 + { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, + { (unsigned char *) "\x7B\xC3\x82\xC6\x3D\x8C\x15\x0C\x3C\x72\x08\x0A\xCE\x05\xAF\xA0\xC2\xBE\xA2\x8E\x4F\xB2\x27\x87\x13\x91\x65\xEF\xBA\x91\xF9\x0F\x8A\xA5\x81\x4A\x50\x3A\xD4\xEB\x04\xA8\xC7\xDD\x22\xCE\x28\x26", 48}, + { (unsigned char *) "\x04\xA8\xC7\xDD\x22\xCE\x28\x26\x8B\x39\xB5\x54\x16\xF0\x44\x7C\x2F\xB7\x7D\xE1\x07\xDC\xD2\xA6\x2E\x88\x0E\xA5\x3E\xEB\x62\xD5\x7C\xB4\x39\x02\x95\xDB\xC9\x94\x3A\xB7\x86\x96\xFA\x50\x4C\x11", 48}, + { (unsigned char *) "\x04\x1D\x1C\x64\xF0\x68\xCF\x45\xFF\xA2\xA6\x3A\x81\xB7\xC1\x3F\x6B\x88\x47\xA3\xE7\x7E\xF1\x4F\xE3\xDB\x7F\xCA\xFE\x0C\xBD\x10\xE8\xE8\x26\xE0\x34\x36\xD6\x46\xAA\xEF\x87\xB2\xE2\x47\xD4\xAF\x1E\x8A\xBE\x1D\x75\x20\xF9\xC2\xA4\x5C\xB1\xEB\x8E\x95\xCF\xD5\x52\x62\xB7\x0B\x29\xFE\xEC\x58\x64\xE1\x9C\x05\x4F\xF9\x91\x29\x28\x0E\x46\x46\x21\x77\x91\x81\x11\x42\x82\x03\x41\x26\x3C\x53\x15", 97}, + { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB3\x1F\x16\x6E\x6C\xAC\x04\x25\xA7\xCF\x3A\xB6\xAF\x6B\x7F\xC3\x10\x3B\x88\x32\x02\xE9\x04\x65\x65", 48}, + { (unsigned char *) "\x01", 1} + }, + { + { (unsigned char *) "\x2B\x24\x03\x03\x02\x08\x01\x01\x0D", 9}, // brainpoolP512r1 + { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, + { (unsigned char *) "\x78\x30\xA3\x31\x8B\x60\x3B\x89\xE2\x32\x71\x45\xAC\x23\x4C\xC5\x94\xCB\xDD\x8D\x3D\xF9\x16\x10\xA8\x34\x41\xCA\xEA\x98\x63\xBC\x2D\xED\x5D\x5A\xA8\x25\x3A\xA1\x0A\x2E\xF1\xC9\x8B\x9A\xC8\xB5\x7F\x11\x17\xA7\x2B\xF2\xC7\xB9\xE7\xC1\xAC\x4D\x77\xFC\x94\xCA", 64}, + { (unsigned char *) "\x3D\xF9\x16\x10\xA8\x34\x41\xCA\xEA\x98\x63\xBC\x2D\xED\x5D\x5A\xA8\x25\x3A\xA1\x0A\x2E\xF1\xC9\x8B\x9A\xC8\xB5\x7F\x11\x17\xA7\x2B\xF2\xC7\xB9\xE7\xC1\xAC\x4D\x77\xFC\x94\xCA\xDC\x08\x3E\x67\x98\x40\x50\xB7\x5E\xBA\xE5\xDD\x28\x09\xBD\x63\x80\x16\xF7\x23", 64}, + { (unsigned char *) "\x04\x81\xAE\xE4\xBD\xD8\x2E\xD9\x64\x5A\x21\x32\x2E\x9C\x4C\x6A\x93\x85\xED\x9F\x70\xB5\xD9\x16\xC1\xB4\x3B\x62\xEE\xF4\xD0\x09\x8E\xFF\x3B\x1F\x78\xE2\xD0\xD4\x8D\x50\xD1\x68\x7B\x93\xB9\x7D\x5F\x7C\x6D\x50\x47\x40\x6A\x5E\x68\x8B\x35\x22\x09\xBC\xB9\xF8\x22\x7D\xDE\x38\x5D\x56\x63\x32\xEC\xC0\xEA\xBF\xA9\xCF\x78\x22\xFD\xF2\x09\xF7\x00\x24\xA5\x7B\x1A\xA0\x00\xC5\x5B\x88\x1F\x81\x11\xB2\xDC\xDE\x49\x4A\x5F\x48\x5E\x5B\xCA\x4B\xD8\x8A\x27\x63\xAE\xD1\xCA\x2B\x2F\xA8\xF0\x54\x06\x78\xCD\x1E\x0F\x3A\xD8\x08\x92", 129}, + { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x70\x55\x3E\x5C\x41\x4C\xA9\x26\x19\x41\x86\x61\x19\x7F\xAC\x10\x47\x1D\xB1\xD3\x81\x08\x5D\xDA\xDD\xB5\x87\x96\x82\x9C\xA9\x00\x69", 64}, + { (unsigned char *) "\x01", 1} + }, + { { (unsigned char *) "\x2B\x81\x04\x00\x1F", 5}, // secp192k1 { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, { (unsigned char *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 24}, @@ -191,7 +218,7 @@ path.aid = sc_hsm_aid; /* we don't have a pre-known size of the file */ path.count = -1; - if (!p15card->opts.use_file_cache + if (!p15card->opts.use_file_cache || !efbin || SC_SUCCESS != sc_pkcs15_read_cached_file(p15card, &path, &efbin, len)) { /* avoid re-selection of SC-HSM */ path.aid.len = 0; @@ -606,13 +633,13 @@ /* Try to select a related EF containing the PKCS#15 description of the key */ len = sizeof efbin; r = read_file(p15card, fid, efbin, &len, 1); - LOG_TEST_RET(card->ctx, r, "Could not read EF.PRKD"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.PRKD"); ptr = efbin; memset(&prkd, 0, sizeof(prkd)); r = sc_pkcs15_decode_prkdf_entry(p15card, &prkd, (const u8 **)&ptr, &len); - LOG_TEST_RET(card->ctx, r, "Could not decode EF.PRKD"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.PRKD"); /* All keys require user PIN authentication */ prkd.auth_id.len = 1; @@ -642,8 +669,6 @@ 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"); - if (efbin[0] == 0x67) { /* Decode CSR and create public key object */ sc_pkcs15emu_sc_hsm_add_pubkey(p15card, efbin, len, key_info, prkd.label); free(key_info); @@ -702,13 +727,13 @@ /* Try to select a related EF containing the PKCS#15 description of the data */ len = sizeof efbin; r = read_file(p15card, fid, efbin, &len, 1); - LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.DCOD"); ptr = efbin; memset(&data_obj, 0, sizeof(data_obj)); r = sc_pkcs15_decode_dodf_entry(p15card, &data_obj, &ptr, &len); - LOG_TEST_RET(card->ctx, r, "Could not decode EF.DCOD"); + LOG_TEST_RET(card->ctx, r, "Could not decode optional EF.DCOD"); data_info = (sc_pkcs15_data_info_t *)data_obj.data; @@ -741,13 +766,13 @@ /* Try to select a related EF containing the PKCS#15 description of the data */ len = sizeof efbin; r = read_file(p15card, fid, efbin, &len, 1); - LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.DCOD"); ptr = efbin; memset(&obj, 0, sizeof(obj)); r = sc_pkcs15_decode_cdf_entry(p15card, &obj, &ptr, &len); - LOG_TEST_RET(card->ctx, r, "Could not decode EF.CD"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.CDOD"); cert_info = (sc_pkcs15_cert_info_t *)obj.data; @@ -772,10 +797,10 @@ /* Read token info */ len = sizeof efbin; r = read_file(p15card, (u8 *) "\x2F\x03", efbin, &len, 1); - LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.TokenInfo"); r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, len); - LOG_TEST_RET(card->ctx, r, "Could not decode EF.TokenInfo"); + LOG_TEST_RET(card->ctx, r, "Skipping optional EF.TokenInfo"); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -823,8 +848,10 @@ p15card->card->version.hw_major = 24; /* JCOP 2.4.1r3 */ p15card->card->version.hw_minor = 13; - p15card->card->version.fw_major = file->prop_attr[file->prop_attr_len - 2]; - p15card->card->version.fw_minor = file->prop_attr[file->prop_attr_len - 1]; + if (file && file->prop_attr && file->prop_attr_len >= 2) { + p15card->card->version.fw_major = file->prop_attr[file->prop_attr_len - 2]; + p15card->card->version.fw_minor = file->prop_attr[file->prop_attr_len - 1]; + } sc_file_free(file); @@ -835,14 +862,16 @@ } 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"); + LOG_TEST_RET(card->ctx, r, "Skipping optional 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; + if (len > 0) { + /* 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; @@ -855,7 +884,12 @@ sc_pkcs15emu_sc_hsm_read_tokeninfo(p15card); if (p15card->tokeninfo->label == NULL) { - p15card->tokeninfo->label = strdup("SmartCard-HSM"); + if (p15card->card->type == SC_CARD_TYPE_SC_HSM_GOID + || p15card->card->type == SC_CARD_TYPE_SC_HSM_SOC) { + p15card->tokeninfo->label = strdup("GoID"); + } else { + p15card->tokeninfo->label = strdup("SmartCard-HSM"); + } if (p15card->tokeninfo->label == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } @@ -866,7 +900,12 @@ } if (p15card->tokeninfo->manufacturer_id == NULL) { - p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); + if (p15card->card->type == SC_CARD_TYPE_SC_HSM_GOID + || p15card->card->type == SC_CARD_TYPE_SC_HSM_SOC) { + p15card->tokeninfo->manufacturer_id = strdup("Bundesdruckerei GmbH"); + } else { + p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); + } if (p15card->tokeninfo->manufacturer_id == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } @@ -941,7 +980,8 @@ LOG_FUNC_RETURN(card->ctx, r); - if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + if (card->type == SC_CARD_TYPE_SC_HSM_SOC + || card->type == SC_CARD_TYPE_SC_HSM_GOID) { /* SC-HSM of this type always has a PIN-Pad */ r = SC_SUCCESS; } else { @@ -998,7 +1038,8 @@ return sc_pkcs15emu_sc_hsm_init(p15card); } else { if (p15card->card->type != SC_CARD_TYPE_SC_HSM - && p15card->card->type != SC_CARD_TYPE_SC_HSM_SOC) { + && p15card->card->type != SC_CARD_TYPE_SC_HSM_SOC + && p15card->card->type != SC_CARD_TYPE_SC_HSM_GOID) { return SC_ERROR_WRONG_CARD; } return sc_pkcs15emu_sc_hsm_init(p15card); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-sec.c opensc-0.19.0/src/libopensc/pkcs15-sec.c --- opensc-0.17.0/src/libopensc/pkcs15-sec.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-sec.c 2018-09-13 11:47:21.000000000 +0000 @@ -2,7 +2,7 @@ * pkcs15-sec.c: PKCS#15 cryptography functions * * Copyright (C) 2001, 2002 Juha Yrjölä - * Copyrigth (C) 2007 Nils Larsch + * Copyright (C) 2007 Nils Larsch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -49,7 +49,7 @@ /* TODO: Why file_app may be NULL -- at least 3F00 has to be present? * Check validity of the following assumption. */ /* For pkcs15-emulated cards, the file_app may be NULL, - * in that case we allways assume an absolute path */ + * in that case we always assume an absolute path */ if (!prkey->path.len && prkey->path.aid.len) { /* Private key is a SDO allocated in application DF */ path = prkey->path; @@ -420,12 +420,16 @@ /* add the padding bytes (if necessary) */ if (pad_flags != 0) { - size_t tmplen = sizeof(buf); + if (flags & SC_ALGORITHM_RSA_PAD_PSS) { + // TODO PSS padding + } else { + size_t tmplen = sizeof(buf); - r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); + r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); - inlen = tmplen; + inlen = tmplen; + } } else if ( senv.algorithm == SC_ALGORITHM_RSA && (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { @@ -452,6 +456,15 @@ r = use_key(p15card, obj, &senv, sc_compute_signature, tmp, inlen, out, outlen); LOG_TEST_RET(ctx, r, "use_key() failed"); + + /* Some cards may return RSA signature as integer without leading zero bytes */ + /* Already know outlen >= modlen and r >= 0 */ + if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA && (unsigned)r < modlen) { + memmove(out + modlen - r, out, r); + memset(out, 0, modlen - r); + r = modlen; + } + sc_mem_clear(buf, sizeof(buf)); LOG_FUNC_RETURN(ctx, r); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-starcert.c opensc-0.19.0/src/libopensc/pkcs15-starcert.c --- opensc-0.17.0/src/libopensc/pkcs15-starcert.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-starcert.c 2018-09-13 11:47:21.000000000 +0000 @@ -164,6 +164,8 @@ /* get serial number */ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); + if (r != SC_SUCCESS) + return SC_ERROR_INTERNAL; r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); if (r != SC_SUCCESS) return SC_ERROR_INTERNAL; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-syn.c opensc-0.19.0/src/libopensc/pkcs15-syn.c --- opensc-0.17.0/src/libopensc/pkcs15-syn.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-syn.c 2018-09-13 11:47:21.000000000 +0000 @@ -59,6 +59,7 @@ { "iasecc", sc_pkcs15emu_iasecc_init_ex }, { "jpki", sc_pkcs15emu_jpki_init_ex }, { "coolkey", sc_pkcs15emu_coolkey_init_ex }, + { "din66291", sc_pkcs15emu_din_66291_init_ex }, { NULL, NULL } }; @@ -81,6 +82,7 @@ case SC_CARD_TYPE_OPENPGP_V1: case SC_CARD_TYPE_OPENPGP_V2: case SC_CARD_TYPE_OPENPGP_GNUK: + case SC_CARD_TYPE_OPENPGP_V3: case SC_CARD_TYPE_SC_HSM: case SC_CARD_TYPE_SC_HSM_SOC: case SC_CARD_TYPE_DNIE_BASE: @@ -89,6 +91,11 @@ case SC_CARD_TYPE_DNIE_USER: case SC_CARD_TYPE_DNIE_TERMINATED: case SC_CARD_TYPE_IASECC_GEMALTO: + case SC_CARD_TYPE_PIV_II_GENERIC: + case SC_CARD_TYPE_PIV_II_HIST: + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: + return 1; default: return 0; @@ -110,7 +117,7 @@ conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1); if (!conf_block) { - /* no conf file found => try bultin drivers */ + /* no conf file found => try builtin drivers */ sc_log(ctx, "no conf file (or section), trying all builtin emulators"); for (i = 0; builtin_emulators[i].name; i++) { sc_log(ctx, "trying %s", builtin_emulators[i].name); diff -Nru opensc-0.17.0/src/libopensc/pkcs15-syn.h opensc-0.19.0/src/libopensc/pkcs15-syn.h --- opensc-0.17.0/src/libopensc/pkcs15-syn.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-syn.h 2018-09-13 11:47:21.000000000 +0000 @@ -53,6 +53,7 @@ int sc_pkcs15emu_iasecc_init_ex(sc_pkcs15_card_t *, struct sc_aid *, sc_pkcs15emu_opt_t *); int sc_pkcs15emu_jpki_init_ex(sc_pkcs15_card_t *, struct sc_aid *, sc_pkcs15emu_opt_t *); int sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *, sc_pkcs15emu_opt_t *opts); +int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *, sc_pkcs15emu_opt_t *opts); struct sc_pkcs15_emulator_handler { const char *name; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-tccardos.c opensc-0.19.0/src/libopensc/pkcs15-tccardos.c --- opensc-0.17.0/src/libopensc/pkcs15-tccardos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-tccardos.c 2018-09-13 11:47:21.000000000 +0000 @@ -304,10 +304,10 @@ int r; struct sc_path path; struct sc_file *file = NULL; - u8 gdo[MAX_INFO1_SIZE]; char hex_buf[256]; - size_t gdo_len = MAX_INFO1_SIZE; struct sc_card *card = p15card->card; + sc_serial_number_t iccsn; + iccsn.len = sizeof iccsn.value; /* check if we have the correct card OS */ if (strcmp(card->name, "CardOS M4")) @@ -329,10 +329,10 @@ if (p15card->tokeninfo->manufacturer_id == NULL) return SC_ERROR_OUT_OF_MEMORY; /* set the serial number */ - r = read_file(p15card->card, "3F002F02", gdo, &gdo_len); - if (r != SC_SUCCESS) + r = sc_parse_ef_gdo(card, iccsn.value, &iccsn.len, NULL, 0); + if (r != SC_SUCCESS || iccsn.len < 5+8) return SC_ERROR_INTERNAL; - sc_bin_to_hex(gdo + 7, 8, hex_buf, sizeof(hex_buf), 0); + sc_bin_to_hex(iccsn.value + 5, 8, hex_buf, sizeof(hex_buf), 0); p15card->tokeninfo->serial_number = strdup(hex_buf); if (p15card->tokeninfo->serial_number == NULL) return SC_ERROR_OUT_OF_MEMORY; diff -Nru opensc-0.17.0/src/libopensc/pkcs15-tcos.c opensc-0.19.0/src/libopensc/pkcs15-tcos.c --- opensc-0.17.0/src/libopensc/pkcs15-tcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-tcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -157,7 +157,8 @@ if(buf[i]==0xB8) can_crypt++; } } else { - if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS){ + if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS + || !f->prop_attr || f->prop_attr_len < 2){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select(%s) failed\n", sc_print_path(&prkey_info.path)); @@ -245,7 +246,8 @@ return 1; } } else { - if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS){ + if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS + || !f->prop_attr || f->prop_attr_len < 4){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"Select(%s) failed\n", path); return 1; } diff -Nru opensc-0.17.0/src/libopensc/pkcs15-westcos.c opensc-0.19.0/src/libopensc/pkcs15-westcos.c --- opensc-0.17.0/src/libopensc/pkcs15-westcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/pkcs15-westcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -54,6 +54,8 @@ /* get serial number */ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); + if (r) + goto out; r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); if (r) goto out; diff -Nru opensc-0.17.0/src/libopensc/reader-cryptotokenkit.m opensc-0.19.0/src/libopensc/reader-cryptotokenkit.m --- opensc-0.17.0/src/libopensc/reader-cryptotokenkit.m 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-cryptotokenkit.m 2018-09-13 11:47:21.000000000 +0000 @@ -43,6 +43,30 @@ NULL }; +static int convertError(NSError *error) +{ + switch (error.code) { + case TKErrorCodeNotImplemented: + return SC_ERROR_NOT_IMPLEMENTED; + case TKErrorCodeCommunicationError: + return SC_ERROR_TRANSMIT_FAILED; + case TKErrorCodeCorruptedData: + return SC_ERROR_CORRUPTED_DATA; + case TKErrorCodeCanceledByUser: + return SC_ERROR_KEYPAD_CANCELLED; + case TKErrorCodeAuthenticationFailed: + return SC_ERROR_PIN_CODE_INCORRECT; + case TKErrorCodeObjectNotFound: + return SC_ERROR_OBJECT_NOT_FOUND; + case TKErrorCodeTokenNotFound: + return SC_ERROR_CARD_REMOVED; + case TKErrorCodeBadParameter: + return SC_ERROR_INVALID_ARGUMENTS; + default: + return SC_ERROR_UNKNOWN; + } +} + static int cryptotokenkit_init(sc_context_t *ctx) { return SC_SUCCESS; @@ -155,9 +179,13 @@ priv->tksmartcard = [priv->tksmartcardslot makeSmartCard]; } - if (!priv->tksmartcard || ![priv->tksmartcard valid]) + if (!priv->tksmartcard || !priv->tksmartcard.valid) return SC_ERROR_CARD_NOT_PRESENT; + /* if tksmartcard.context is set to nil, we know that the card has been + * reset or acquired by a different session */ + priv->tksmartcard.context = @(YES); + /* attempt to detect protocol in use T0/T1/RAW */ ctk_set_proto(reader); @@ -185,10 +213,15 @@ if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) goto err; + if (priv->tksmartcard.context == nil) { + r = SC_ERROR_CARD_RESET; + priv->tksmartcard.context = @(YES); + goto err; + } + [priv->tksmartcard beginSessionWithReply:^(BOOL success, NSError *error) { if (success != TRUE) { - NSLog(@"Error locking card <%@>", error); - r = SC_ERROR_UNKNOWN; + r = convertError(error); } else { r = SC_SUCCESS; } @@ -240,18 +273,14 @@ if (response) { rsize = [response length]; rbuf = malloc(rsize); - if (!rbuf) + if (!rbuf) { r = SC_ERROR_OUT_OF_MEMORY; - else - memcpy(rbuf, (unsigned char*) [response bytes], rsize); - } - if (r == SC_SUCCESS) { - if (error) { - NSLog(@"Error transmitting to card <%@>", error); - r = SC_ERROR_TRANSMIT_FAILED; } else { + memcpy(rbuf, (unsigned char*) [response bytes], rsize); r = SC_SUCCESS; } + } else { + r = convertError(error); } dispatch_semaphore_signal(sema); }]; @@ -275,6 +304,169 @@ LOG_FUNC_RETURN(reader->ctx, r); } +TKSmartCardPINFormat *getPINFormat(struct sc_pin_cmd_pin *pin) +{ + TKSmartCardPINFormat *format = [[TKSmartCardPINFormat alloc] init]; + switch (pin->encoding) { + case SC_PIN_ENCODING_GLP: + /* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */ + format.PINLengthBitSize = 4; + format.PINBlockByteLength = 8; + /* fall through */ + case SC_PIN_ENCODING_BCD: + format.encoding = TKSmartCardPINEncodingBCD; + break; + case SC_PIN_ENCODING_ASCII: + format.encoding = TKSmartCardPINEncodingASCII; + format.PINBlockByteLength = pin->pad_length; + break; + default: + return nil; + } + format.minPINLength = pin->min_length; + format.maxPINLength = pin->max_length; + if (pin->length_offset > 4) { + format.PINLengthBitOffset = (pin->length_offset-5)*8; + } + + return format; +} + +int cryptotokenkit_perform_verify(struct sc_reader *reader, struct sc_pin_cmd_data *data) +{ + u8 template[SC_MAX_APDU_BUFFER_SIZE]; + __block int r; + __block UInt16 sw; + size_t ssize = 0; + u8 *sbuf = NULL, *rbuf = NULL; + struct cryptotokenkit_private_data *priv = reader->drv_data; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + LOG_FUNC_CALLED(reader->ctx); + + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + + /* The APDU must be provided by the card driver */ + if (!data->apdu) { + return SC_ERROR_NOT_SUPPORTED; + } + + r = sc_apdu_get_octets(reader->ctx, data->apdu, &sbuf, &ssize, reader->active_protocol); + LOG_TEST_GOTO_ERR(reader->ctx, r, "Could not encode APDU template"); + + NSData *apdu = [NSData dataWithBytes:sbuf length:ssize]; + TKSmartCardPINFormat *format; + struct sc_pin_cmd_pin *pin_ref = &data->pin1; + TKSmartCardUserInteractionForPINOperation *interaction; + switch (data->cmd) { + case SC_PIN_CMD_VERIFY: + format = getPINFormat(pin_ref); + NSInteger offset; + if (data->pin1.length_offset != 4) { + offset = data->pin1.offset - 5; + } else { + offset = 0; + } + interaction = [priv->tksmartcard userInteractionForSecurePINVerificationWithPINFormat:format APDU:apdu PINByteOffset:offset]; + break; + case SC_PIN_CMD_CHANGE: + case SC_PIN_CMD_UNBLOCK: + if (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) { + pin_ref = &data->pin2; + } + /* TODO: set confirmation and text */ + format = getPINFormat(pin_ref); + NSInteger oldOffset, newOffset; + if (data->pin1.length_offset != 4) { + oldOffset = data->pin1.offset - 5; + newOffset = data->pin2.offset - 5; + } else { + oldOffset = 0; + newOffset = 0; + } + interaction = [priv->tksmartcard userInteractionForSecurePINChangeWithPINFormat:format APDU:apdu currentPINByteOffset:oldOffset newPINByteOffset:newOffset]; + break; + default: + sc_log(reader->ctx, "Unknown PIN command %d", data->cmd); + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + if (nil == interaction) { + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + + [interaction runWithReply:^(BOOL success, NSError *error) { + if (success) { + NSData *response = interaction.resultData; + if (nil != response) { + data->apdu->resplen = response.length; + memcpy(data->apdu->resp, (unsigned char *) response.bytes, response.length); + } else { + data->apdu->resplen = 0; + } + sw = interaction.resultSW; + r = SC_SUCCESS; + } else { + r = convertError(error); + } + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + if (r != SC_SUCCESS) { + goto err; + } + + data->apdu->sw1 = sw >> 8; + data->apdu->sw2 = sw & 0xFF; + + switch (sw) { + case 0x6400: + /* Input timed out */ + r = SC_ERROR_KEYPAD_TIMEOUT; + break; + case 0x6401: + /* Input cancelled */ + r = SC_ERROR_KEYPAD_CANCELLED; + break; + case 0x6402: + /* PINs don't match */ + r = SC_ERROR_KEYPAD_PIN_MISMATCH; + break; + case 0x6403: + /* Entered PIN is not in length limits */ + r = SC_ERROR_INVALID_PIN_LENGTH; /* XXX: designed to be returned when PIN is in API call */ + break; + case 0x6B80: + /* Wrong data in the buffer, rejected by firmware */ + r = SC_ERROR_READER; + break; + } + +err: + if (sbuf != NULL) { + sc_mem_clear(sbuf, ssize); + free(sbuf); + } + + LOG_FUNC_RETURN(reader->ctx, r); +} + +void cryptotokenkit_detect_reader_features(struct sc_reader *reader, TKSmartCard* tksmartcard) +{ + if (tksmartcard) { + const u8 template[] = {tksmartcard.cla, 0x20, 0x00, 0x80, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + NSData *data = [NSData dataWithBytes:template length:sizeof template]; + TKSmartCardPINFormat *PINFormat = [[TKSmartCardPINFormat alloc] init]; + PINFormat.PINBitOffset = 0; + + if (nil != [tksmartcard userInteractionForSecurePINVerificationWithPINFormat:PINFormat APDU:data PINByteOffset:0]) + reader->capabilities |= SC_READER_CAP_PIN_PAD; + } +} + int cryptotokenkit_use_reader(sc_context_t *ctx, void *pcsc_context_handle, void *pcsc_card_handle) { int r; @@ -329,6 +521,10 @@ /* attempt to detect protocol in use T0/T1/RAW */ ctk_set_proto(reader); + cryptotokenkit_detect_card_presence(reader); + + cryptotokenkit_detect_reader_features(reader, tksmartcard); + r = _sc_add_reader(ctx, reader); err: @@ -347,8 +543,10 @@ static int cryptotokenkit_detect_readers(sc_context_t *ctx) { size_t i; + NSUInteger j; int r; TKSmartCardSlotManager *mngr = [TKSmartCardSlotManager defaultManager]; + NSMutableArray *slotNames; LOG_FUNC_CALLED(ctx); @@ -358,38 +556,37 @@ goto err; } - /* temporarily mark all readers as removed */ - for (i=0; i < sc_ctx_get_reader_count(ctx); i++) { - sc_reader_t *reader = sc_ctx_get_reader(ctx, i); - reader->flags |= SC_READER_REMOVED; - } - sc_log(ctx, "Probing CryptoTokenKit readers"); - for (NSString *slotName in [mngr slotNames]) { - sc_reader_t *old_reader; - int found = 0; - const char *reader_name = [slotName UTF8String]; - dispatch_semaphore_t sema = dispatch_semaphore_create(0); + slotNames = [[mngr slotNames] mutableCopy]; - for (i=0; i < sc_ctx_get_reader_count(ctx) && !found; i++) { - old_reader = sc_ctx_get_reader(ctx, i); - if (old_reader == NULL) { - r = SC_ERROR_INTERNAL; - goto err; - } - if (!strcmp(old_reader->name, reader_name)) { - found = 1; - } + /* check if existing readers were returned in the list */ + for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) { + sc_reader_t *reader = sc_ctx_get_reader(ctx, i); + + if (reader == NULL) { + r = SC_ERROR_INTERNAL; + goto err; } - /* Reader already available, skip */ - if (found) { - old_reader->flags &= ~SC_READER_REMOVED; - continue; + for (j = 0; j < [slotNames count]; j++) { + if (!strcmp(reader->name, [slotNames[j] UTF8String])) + break; } - sc_log(ctx, "Found new CryptoTokenKit reader '%s'", reader_name); + if (j < [slotNames count]) { + /* existing reader found; remove it from the list */ + [slotNames removeObjectAtIndex:j]; + } else { + /* existing reader not found */ + reader->flags |= SC_READER_REMOVED; + } + } + + /* add readers remaining in the list */ + for (NSString *slotName in slotNames) { + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + sc_log(ctx, "Found new CryptoTokenKit reader '%s'", [slotName UTF8String]); [mngr getSlotWithName:slotName reply:^(TKSmartCardSlot *slot) { cryptotokenkit_use_reader(ctx, slot, NULL); dispatch_semaphore_signal(sema); @@ -414,7 +611,7 @@ cryptotokenkit_ops.lock = cryptotokenkit_lock; cryptotokenkit_ops.unlock = cryptotokenkit_unlock; cryptotokenkit_ops.transmit = cryptotokenkit_transmit; - cryptotokenkit_ops.perform_verify = NULL; + cryptotokenkit_ops.perform_verify = cryptotokenkit_perform_verify; cryptotokenkit_ops.perform_pace = NULL; cryptotokenkit_ops.use_reader = cryptotokenkit_use_reader; cryptotokenkit_ops.detect_readers = cryptotokenkit_detect_readers; diff -Nru opensc-0.17.0/src/libopensc/reader-ctapi.c opensc-0.19.0/src/libopensc/reader-ctapi.c --- opensc-0.17.0/src/libopensc/reader-ctapi.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-ctapi.c 2018-09-13 11:47:21.000000000 +0000 @@ -141,7 +141,7 @@ } else { if (rbuf[0] != CTBCS_P2_STATUS_ICC) { /* Should we be more tolerant here? I do not think so... */ - sc_log(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_ICC: 0x%x", rbuf[0]); + sc_log(reader->ctx, "Invalid data object returned on CTBCS_P2_STATUS_ICC: 0x%x", rbuf[0]); return SC_ERROR_TRANSMIT_FAILED; } /* Fixme - should not be reached */ @@ -239,7 +239,6 @@ char rv; u8 cmd[9], rbuf[256], sad, dad; unsigned short lr; - int r; if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) return SC_ERROR_NOT_ALLOWED; @@ -265,7 +264,7 @@ return SC_ERROR_INTERNAL; reader->atr.len = lr; memcpy(reader->atr.value, rbuf, lr); - r = _sc_parse_atr(reader); + _sc_parse_atr(reader); return 0; } @@ -435,11 +434,11 @@ if (rbuf[0] != CTBCS_P2_STATUS_TFU) { /* Number of slots might also detected by using CTBCS_P2_STATUS_ICC. If you think that's important please do it... ;) */ - sc_log(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x", rbuf[0]); + sc_log(reader->ctx, "Invalid data object returned on CTBCS_P2_STATUS_TFU: 0x%x", rbuf[0]); } NumUnits = rbuf[1]; if (NumUnits + 4 > lr) { - sc_log(reader->ctx, "Invalid data returnd: %d functional units, size %d", NumUnits, rv); + sc_log(reader->ctx, "Invalid data returned: %d functional units, size %d", NumUnits, rv); } priv->ctapi_functional_units = 0; for(i = 0; i < NumUnits; i++) { diff -Nru opensc-0.17.0/src/libopensc/reader-openct.c opensc-0.19.0/src/libopensc/reader-openct.c --- opensc-0.17.0/src/libopensc/reader-openct.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-openct.c 2018-09-13 11:47:21.000000000 +0000 @@ -243,7 +243,7 @@ } if (rc == 0) { - sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "openct_reader_connect recved no data\n"); + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "openct_reader_connect received no data\n"); return SC_ERROR_READER; } diff -Nru opensc-0.17.0/src/libopensc/reader-pcsc.c opensc-0.19.0/src/libopensc/reader-pcsc.c --- opensc-0.17.0/src/libopensc/reader-pcsc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-pcsc.c 2018-09-13 11:47:21.000000000 +0000 @@ -82,6 +82,7 @@ SCARDCONTEXT pcsc_ctx; SCARDCONTEXT pcsc_wait_ctx; int enable_pinpad; + int fixed_pinlength; int enable_pace; size_t force_max_recv_size; size_t force_max_send_size; @@ -762,10 +763,11 @@ /* PC/SC Defaults */ gpriv->provider_library = DEFAULT_PCSC_PROVIDER; gpriv->connect_exclusive = 0; - gpriv->disconnect_action = SCARD_RESET_CARD; + gpriv->disconnect_action = SCARD_LEAVE_CARD; gpriv->transaction_end_action = SCARD_LEAVE_CARD; gpriv->reconnect_action = SCARD_LEAVE_CARD; gpriv->enable_pinpad = 1; + gpriv->fixed_pinlength = 0; gpriv->enable_pace = 1; gpriv->pcsc_ctx = -1; gpriv->pcsc_wait_ctx = -1; @@ -781,13 +783,15 @@ gpriv->connect_exclusive = scconf_get_bool(conf_block, "connect_exclusive", gpriv->connect_exclusive); gpriv->disconnect_action = - pcsc_reset_action(scconf_get_str(conf_block, "disconnect_action", "reset")); + pcsc_reset_action(scconf_get_str(conf_block, "disconnect_action", "leave")); gpriv->transaction_end_action = pcsc_reset_action(scconf_get_str(conf_block, "transaction_end_action", "leave")); gpriv->reconnect_action = pcsc_reset_action(scconf_get_str(conf_block, "reconnect_action", "leave")); gpriv->enable_pinpad = scconf_get_bool(conf_block, "enable_pinpad", gpriv->enable_pinpad); + gpriv->fixed_pinlength = scconf_get_bool(conf_block, "fixed_pinlength", + gpriv->fixed_pinlength); gpriv->enable_pace = scconf_get_bool(conf_block, "enable_pace", gpriv->enable_pace); gpriv->force_max_send_size = scconf_get_int(conf_block, @@ -1059,6 +1063,7 @@ PCSC_TLV_STRUCTURE *pcsc_tlv; LONG rv; const char *log_disabled = "but it's disabled in configuration file"; + int id_vendor = 0, id_product = 0; LOG_FUNC_CALLED(ctx); @@ -1128,6 +1133,17 @@ } } + /* Some readers claim to have PinPAD support even if they have not */ + if ((reader->capabilities & SC_READER_CAP_PIN_PAD) && + part10_get_vendor_product(reader, card_handle, &id_vendor, &id_product) == SC_SUCCESS) { + /* HID Global OMNIKEY 3x21/6121 Smart Card Reader, fixed in libccid 1.4.29 (remove when last supported OS is using 1.4.29) */ + if ((id_vendor == 0x076B && id_product == 0x3031) || + (id_vendor == 0x076B && id_product == 0x6632)) { + sc_log(ctx, "%s is not pinpad reader, ignoring", reader->name); + reader->capabilities &= ~SC_READER_CAP_PIN_PAD; + } + } + /* Detect display */ if (priv->pin_properties_ioctl) { rcount = sizeof(rbuf); @@ -1219,11 +1235,10 @@ reader->vendor = strdup((char *) rbuf); } - rcount = sizeof rbuf; + rcount = sizeof i; if(gpriv->SCardGetAttrib(card_handle, SCARD_ATTR_VENDOR_IFD_VERSION, - rbuf, &rcount) == SCARD_S_SUCCESS - && rcount == 4) { - i = *(DWORD *) rbuf; + (u8 *) &i, &rcount) == SCARD_S_SUCCESS + && rcount == sizeof i) { reader->version_major = (i >> 24) & 0xFF; reader->version_minor = (i >> 16) & 0xFF; } @@ -1263,7 +1278,9 @@ ret = _sc_add_reader(ctx, reader); - refresh_attributes(reader); + if (ret == SC_SUCCESS) { + refresh_attributes(reader); + } err1: return ret; @@ -1293,12 +1310,6 @@ goto out; } - /* temporarily mark all readers as removed */ - for (i=0;i < sc_ctx_get_reader_count(ctx);i++) { - sc_reader_t *reader = sc_ctx_get_reader(ctx, i); - reader->flags |= SC_READER_REMOVED; - } - sc_log(ctx, "Probing PC/SC readers"); do { @@ -1354,29 +1365,40 @@ goto out; } - for (reader_name = reader_buf; *reader_name != '\x0'; - reader_name += strlen(reader_name) + 1) { - sc_reader_t *reader = NULL, *old_reader = NULL; - struct pcsc_private_data *priv = NULL; - int found = 0; + /* check if existing readers were returned in the list */ + for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) { + sc_reader_t *reader = sc_ctx_get_reader(ctx, i); - for (i=0;i < sc_ctx_get_reader_count(ctx) && !found;i++) { - old_reader = sc_ctx_get_reader(ctx, i); - if (old_reader == NULL) { - ret = SC_ERROR_INTERNAL; - goto out; - } - if (!strcmp(old_reader->name, reader_name)) { - found = 1; - } + if (!reader) { + ret = SC_ERROR_INTERNAL; + goto out; } - /* Reader already available, skip */ - if (found) { - old_reader->flags &= ~SC_READER_REMOVED; - continue; + for (reader_name = reader_buf; *reader_name != '\x0'; + reader_name += strlen(reader_name) + 1) { + if (!strcmp(reader->name, reader_name)) + break; } + if (*reader_name != '\x0') { + /* existing reader found; remove it from the list */ + char *next_reader_name = reader_name + strlen(reader_name) + 1; + + memmove(reader_name, next_reader_name, + (reader_buf + reader_buf_size) - next_reader_name); + reader_buf_size -= (next_reader_name - reader_name); + } else { + /* existing reader not found */ + reader->flags |= SC_READER_REMOVED; + } + } + + /* add readers remaining in the list */ + for (reader_name = reader_buf; *reader_name != '\x0'; + reader_name += strlen(reader_name) + 1) { + sc_reader_t *reader = NULL; + struct pcsc_private_data *priv = NULL; + ret = pcsc_add_reader(ctx, reader_name, strlen(reader_name), &reader); if (ret != SC_SUCCESS) { _sc_delete_reader(ctx, reader); @@ -1400,7 +1422,7 @@ } if (rv == (LONG)SCARD_E_SHARING_VIOLATION) { /* Assume that there is a card in the reader in shared mode if - * direct communcation failed */ + * direct communication failed */ rv = gpriv->SCardConnect(gpriv->pcsc_ctx, reader->name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, &card_handle, @@ -1459,7 +1481,8 @@ rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; } -#ifndef __APPLE__ /* OS X 10.6.2 does not support PnP notification */ +#ifndef __APPLE__ + /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ if (event_mask & SC_EVENT_READER_ATTACHED) { rgReaderStates[i].szReader = "\\\\?PnP?\\Notification"; rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; @@ -1492,12 +1515,14 @@ goto out; } +#ifdef __APPLE__ if (num_watch == 0) { sc_log(ctx, "No readers available, PnP notification not supported"); *event_reader = NULL; r = SC_ERROR_NO_READERS_FOUND; goto out; } +#endif rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, 0, rgReaderStates, num_watch); if (rv != SCARD_S_SUCCESS) { @@ -1703,17 +1728,12 @@ pin_verify->bTeoPrologue[2] = 0x00; /* APDU itself */ - pin_verify->abData[offset++] = apdu->cla; - pin_verify->abData[offset++] = apdu->ins; - pin_verify->abData[offset++] = apdu->p1; - pin_verify->abData[offset++] = apdu->p2; - - /* Copy data if not Case 1 */ - if (data->pin1.length_offset != 4) { - pin_verify->abData[offset++] = apdu->lc; - memcpy(&pin_verify->abData[offset], apdu->data, apdu->datalen); - offset += apdu->datalen; - } + LOG_TEST_RET(reader->ctx, + sc_apdu2bytes(reader->ctx, apdu, + reader->active_protocol, pin_verify->abData, + SC_MAX_APDU_BUFFER_SIZE), + "Could not encode PIN APDU"); + offset += sc_apdu_get_length(apdu, reader->active_protocol); pin_verify->ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */ @@ -1822,17 +1842,12 @@ pin_modify->bTeoPrologue[2] = 0x00; /* APDU itself */ - pin_modify->abData[offset++] = apdu->cla; - pin_modify->abData[offset++] = apdu->ins; - pin_modify->abData[offset++] = apdu->p1; - pin_modify->abData[offset++] = apdu->p2; - - /* Copy data if not Case 1 */ - if (pin_ref->length_offset != 4) { - pin_modify->abData[offset++] = apdu->lc; - memcpy(&pin_modify->abData[offset], apdu->data, apdu->datalen); - offset += apdu->datalen; - } + LOG_TEST_RET(reader->ctx, + sc_apdu2bytes(reader->ctx, apdu, + reader->active_protocol, pin_modify->abData, + SC_MAX_APDU_BUFFER_SIZE), + "Could not encode PIN APDU"); + offset += sc_apdu_get_length(apdu, reader->active_protocol); pin_modify->ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */ @@ -1895,10 +1910,17 @@ unsigned char buffer[256]; size_t length = sizeof buffer; struct pcsc_private_data *priv = reader->drv_data; + struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) reader->ctx->reader_drv_data; struct sc_pin_cmd_pin *pin_ref = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? &data->pin1 : &data->pin2; + if (gpriv->fixed_pinlength != 0) { + pin_ref->min_length = gpriv->fixed_pinlength; + pin_ref->max_length = gpriv->fixed_pinlength; + return 0; + } + if (!priv->get_tlv_properties) return 0; diff -Nru opensc-0.17.0/src/libopensc/reader-tr03119.c opensc-0.19.0/src/libopensc/reader-tr03119.c --- opensc-0.17.0/src/libopensc/reader-tr03119.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-tr03119.c 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,7 @@ /* * reader-escape.c: implementation related to escape commands with pseudo APDUs * - * Copyright (C) 2013-2015 Frank Morgner + * Copyright (C) 2013-2018 Frank Morgner * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,20 +43,31 @@ #include #endif -static const u8 escape_cla = 0xff; -static const u8 escape_ins = 0x9a; +int get_pace_capabilities(u8 *bitmap) +{ + if (!bitmap) + return SC_ERROR_INVALID_ARGUMENTS; + + /* BitMap */ + *bitmap = EAC_BITMAP_PACE|EAC_BITMAP_EID|EAC_BITMAP_ESIGN; + + return SC_SUCCESS; +} + +const u8 escape_cla = 0xff; +const u8 escape_ins = 0x9a; -static const u8 escape_p1_PIN = 0x04; -static const u8 escape_p2_GetReaderPACECapabilities = 0x01; -static const u8 escape_p2_EstablishPACEChannel = 0x02; -/*static const u8 escape_p2_DestroyPACEChannel = 0x03;*/ -static const u8 escape_p2_PC_to_RDR_Secure = 0x10; - -static const u8 escape_p1_IFD = 0x01; -static const u8 escape_p2_vendor = 0x01; -/*static const u8 escape_p2_product = 0x03;*/ -static const u8 escape_p2_version_firmware = 0x06; -/*static const u8 escape_p2_version_driver = 0x07;*/ +const u8 escape_p1_PIN = 0x04; +const u8 escape_p2_GetReaderPACECapabilities = 0x01; +const u8 escape_p2_EstablishPACEChannel = 0x02; +/*const u8 escape_p2_DestroyPACEChannel = 0x03;*/ +const u8 escape_p2_PC_to_RDR_Secure = 0x10; + +const u8 escape_p1_IFD = 0x01; +const u8 escape_p2_vendor = 0x01; +/*const u8 escape_p2_product = 0x03;*/ +const u8 escape_p2_version_firmware = 0x06; +/*const u8 escape_p2_version_driver = 0x07;*/ struct sc_asn1_entry g_boolean[] = { { "boolean", @@ -79,7 +90,7 @@ { NULL , 0 , 0 , 0 , NULL , NULL } }; -static const struct sc_asn1_entry g_EstablishPACEChannelInput_data[] = { +const struct sc_asn1_entry g_EstablishPACEChannelInput_data[] = { { "passwordID", /* use an OCTET STRING to avoid a conversion to int */ SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL }, @@ -94,7 +105,7 @@ SC_ASN1_STRUCT, SC_ASN1_CTX|0x05|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, { NULL , 0 , 0 , 0 , NULL , NULL } }; -static const struct sc_asn1_entry g_EstablishPACEChannelOutput_data[] = { +const struct sc_asn1_entry g_EstablishPACEChannelOutput_data[] = { { "errorCode", SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL }, { "statusMSESetAT", @@ -109,7 +120,7 @@ SC_ASN1_STRUCT, SC_ASN1_CTX|0x06|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, { NULL , 0 , 0 , 0 , NULL , NULL } }; -static const struct sc_asn1_entry g_EstablishPACEChannel[] = { +const struct sc_asn1_entry g_EstablishPACEChannel[] = { { "EstablishPACEChannel", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE|SC_ASN1_CONS, 0, NULL, NULL }, { NULL , 0 , 0 , 0 , NULL , NULL } @@ -494,7 +505,7 @@ /* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */ bmPINBlockString = 0x40 | 0x08; } else if (pin_ref->encoding == SC_PIN_ENCODING_ASCII && data->flags & SC_PIN_CMD_NEED_PADDING) { - bmPINBlockString = pin_ref->pad_length; + bmPINBlockString = (uint8_t) pin_ref->pad_length; } else { bmPINBlockString = 0x00; } @@ -566,11 +577,11 @@ modify->bmPINLengthFormat = bmPINLengthFormat; if (!(data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) && data->pin1.offset) { - modify->bInsertionOffsetOld = data->pin1.offset - 5; + modify->bInsertionOffsetOld = (uint8_t) data->pin1.offset - 5; } else { modify->bInsertionOffsetOld = 0; } - modify->bInsertionOffsetNew = data->pin2.offset ? data->pin2.offset - 5 : 0; + modify->bInsertionOffsetNew = data->pin2.offset ? (uint8_t) data->pin2.offset - 5 : 0; modify->wPINMaxExtraDigit = wPINMaxExtraDigit; modify->bConfirmPIN = CCID_PIN_CONFIRM_NEW | (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0 : CCID_PIN_INSERT_OLD); @@ -659,8 +670,6 @@ } apdu.lc = apdu.datalen; - r = SC_SUCCESS; - r = reader->ops->transmit(reader, &apdu); if (r < 0) { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, diff -Nru opensc-0.17.0/src/libopensc/reader-tr03119.h opensc-0.19.0/src/libopensc/reader-tr03119.h --- opensc-0.17.0/src/libopensc/reader-tr03119.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/reader-tr03119.h 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,7 @@ /* * reader-tr03119.h: interface related to escape commands with pseudo APDUs * - * Copyright (C) 2013-2015 Frank Morgner + * Copyright (C) 2013-2018 Frank Morgner * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,60 @@ extern "C" { #endif +/** @brief NPA capabilities (TR-03119): PACE */ +#define EAC_BITMAP_PACE 0x40 +/** @brief NPA capabilities (TR-03119): EPA: eID */ +#define EAC_BITMAP_EID 0x20 +/** @brief NPA capabilities (TR-03119): EPA: eSign */ +#define EAC_BITMAP_ESIGN 0x10 + +/** + * @brief Get the PACE capabilities + * + * @param[in,out] bitmap where to store capabilities bitmap + * @note Since this code offers no support for terminal certificate, the bitmap is always \c PACE_BITMAP_PACE|PACE_BITMAP_EID + * + * @return \c SC_SUCCESS or error code if an error occurred + */ +int get_pace_capabilities(u8 *bitmap); + +/** @brief NPA result (TR-03119): Kein Fehler */ +#define EAC_SUCCESS 0x00000000 +/** @brief NPA result (TR-03119): Längen im Input sind inkonsistent */ +#define EAC_ERROR_LENGTH_INCONSISTENT 0xD0000001 +/** @brief NPA result (TR-03119): Unerwartete Daten im Input */ +#define EAC_ERROR_UNEXPECTED_DATA 0xD0000002 +/** @brief NPA result (TR-03119): Unerwartete Kombination von Daten im Input */ +#define EAC_ERROR_UNEXPECTED_DATA_COMBINATION 0xD0000003 +/** @brief NPA result (TR-03119): Die Karte unterstützt das PACE – Verfahren nicht. (Unerwartete Struktur in Antwortdaten der Karte) */ +#define EAC_ERROR_CARD_NOT_SUPPORTED 0xE0000001 +/** @brief NPA result (TR-03119): Der Kartenleser unterstützt den angeforderten bzw. den ermittelten Algorithmus nicht. */ +#define EAC_ERROR_ALGORITH_NOT_SUPPORTED 0xE0000002 +/** @brief NPA result (TR-03119): Der Kartenleser kennt die PIN – ID nicht. */ +#define EAC_ERROR_PINID_NOT_SUPPORTED 0xE0000003 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf Select EF_CardAccess (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_SELECT_EF_CARDACCESS 0xF0000000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf Read Binary (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_READ_BINARY 0xF0010000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf MSE: Set AT (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_MSE_SET_AT 0xF0020000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 1 (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_GENERAL_AUTHENTICATE_1 0xF0030000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 2 (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_GENERAL_AUTHENTICATE_2 0xF0040000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 3 (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_GENERAL_AUTHENTICATE_3 0xF0050000 +/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 4 (needs to be OR-ed with SW1|SW2) */ +#define EAC_ERROR_GENERAL_AUTHENTICATE_4 0xF0060000 +/** @brief NPA result (TR-03119): Kommunikationsabbruch mit Karte. */ +#define EAC_ERROR_COMMUNICATION 0xF0100001 +/** @brief NPA result (TR-03119): Keine Karte im Feld. */ +#define EAC_ERROR_NO_CARD 0xF0100002 +/** @brief NPA result (TR-03119): Benutzerabbruch. */ +#define EAC_ERROR_ABORTED 0xF0200001 +/** @brief NPA result (TR-03119): Benutzer – Timeout */ +#define EAC_ERROR_TIMEOUT 0xF0200002 + void sc_detect_escape_cmds(sc_reader_t *reader); int escape_pace_input_to_buf(sc_context_t *ctx, diff -Nru opensc-0.17.0/src/libopensc/sc.c opensc-0.19.0/src/libopensc/sc.c --- opensc-0.17.0/src/libopensc/sc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/sc.c 2018-09-13 11:47:21.000000000 +0000 @@ -578,9 +578,9 @@ const sc_acl_entry_t *e; unsigned int op; + *dest = NULL; if (!sc_file_valid(src)) return; - *dest = NULL; newf = sc_file_new(); if (newf == NULL) return; @@ -628,7 +628,7 @@ return SC_ERROR_INVALID_ARGUMENTS; } - if (sec_attr == NULL) { + if (sec_attr == NULL || sec_attr_len == 0) { if (file->sec_attr != NULL) free(file->sec_attr); file->sec_attr = NULL; @@ -826,40 +826,8 @@ return SC_SUCCESS; } -void *sc_mem_alloc_secure(sc_context_t *ctx, size_t len) -{ - void *pointer; - int locked = 0; - - pointer = calloc(len, sizeof(unsigned char)); - if (!pointer) - return NULL; -#ifdef HAVE_SYS_MMAN_H - /* TODO mprotect */ - /* Do not swap the memory */ - if (mlock(pointer, len) >= 0) - locked = 1; -#endif -#ifdef _WIN32 - /* Do not swap the memory */ - if (VirtualLock(pointer, len) != 0) - locked = 1; -#endif - if (!locked) { - if (ctx->flags & SC_CTX_FLAG_PARANOID_MEMORY) { - sc_do_log (ctx, 0, NULL, 0, NULL, "cannot lock memory, failing allocation because paranoid set"); - free (pointer); - pointer = NULL; - } else { - sc_do_log (ctx, 0, NULL, 0, NULL, "cannot lock memory, sensitive data may be paged to disk"); - } - } - return pointer; -} - void sc_mem_clear(void *ptr, size_t len) { - /* FIXME: Bug in 1.0.0-beta series crashes with 0 length */ if (len > 0) { #ifdef ENABLE_OPENSSL OPENSSL_cleanse(ptr, len); @@ -949,7 +917,7 @@ static unsigned long sc_CRC_tab32[256]; static int sc_CRC_tab32_initialized = 0; -unsigned sc_crc32(unsigned char *value, size_t len) +unsigned sc_crc32(const unsigned char *value, size_t len) { size_t ii, jj; unsigned long crc; @@ -980,6 +948,26 @@ return crc%0xffff; } +const u8 *sc_compacttlv_find_tag(const u8 *buf, size_t len, u8 tag, size_t *outlen) +{ + if (buf != NULL) { + size_t idx; + u8 plain_tag = tag & 0xF0; + size_t expected_len = tag & 0x0F; + + for (idx = 0; idx < len; idx++) { + if ((buf[idx] & 0xF0) == plain_tag && idx + expected_len < len && + (expected_len == 0 || expected_len == (buf[idx] & 0x0F))) { + if (outlen != NULL) + *outlen = buf[idx] & 0x0F; + return buf + (idx + 1); + } + idx += (buf[idx] & 0x0F); + } + } + return NULL; +} + /**************************** mutex functions ************************/ int sc_mutex_create(const sc_context_t *ctx, void **mutex) diff -Nru opensc-0.17.0/src/libopensc/sc-ossl-compat.h opensc-0.19.0/src/libopensc/sc-ossl-compat.h --- opensc-0.17.0/src/libopensc/sc-ossl-compat.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/sc-ossl-compat.h 2018-09-13 11:47:21.000000000 +0000 @@ -1,5 +1,5 @@ /* - * sc-ossl-compat.h: OpenSC ecompatability for older OpenSSL versions + * sc-ossl-compat.h: OpenSC compatibility for older OpenSSL versions * * Copyright (C) 2016 Douglas E. Engert * @@ -30,7 +30,7 @@ #include #include /* - * Provide backward compatability to older versions of OpenSSL + * Provide backward compatibility to older versions of OpenSSL * while using most of OpenSSL 1.1 API * * LibreSSL is a fork of OpenSSL from 2014 @@ -51,7 +51,7 @@ * * EVP_CIPHER_CTX_new does a EVP_CIPHER_CTX_init * EVP_CIPHER_CTX_free does a EVP_CIPHER_CTX_cleanup - * EVP_CIPHER_CTX_cleanup does equivelent of a EVP_CIPHER_CTX_init + * EVP_CIPHER_CTX_cleanup does equivalent of a EVP_CIPHER_CTX_init * Use EVP_CIPHER_CTX_new, EVP_CIPHER_CTX_free, and EVP_CIPHER_CTX_cleanup between operations */ @@ -90,17 +90,26 @@ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #define RSA_PKCS1_OpenSSL RSA_PKCS1_SSLeay -#define OPENSSL_malloc_init CRYPTO_malloc_init -#define EVP_PKEY_get0_RSA(x) (x->pkey.rsa) -#define EVP_PKEY_get0_DSA(x) (x->pkey.dsa) #define X509_get_extension_flags(x) (x->ex_flags) #define X509_get_key_usage(x) (x->ex_kusage) #define X509_get_extended_key_usage(x) (x->ex_xkusage) -#define EVP_PKEY_up_ref(user_key) CRYPTO_add(&user_key->references, 1, CRYPTO_LOCK_EVP_PKEY) #if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2050300fL #define X509_up_ref(cert) CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509) #endif +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x20700000L +#define OPENSSL_malloc_init CRYPTO_malloc_init +#define EVP_PKEY_get0_RSA(x) (x->pkey.rsa) +#define EVP_PKEY_get0_EC_KEY(x) (x->pkey.ec) +#define EVP_PKEY_get0_DSA(x) (x->pkey.dsa) +#define EVP_PKEY_up_ref(user_key) CRYPTO_add(&user_key->references, 1, CRYPTO_LOCK_EVP_PKEY) +#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +#endif +#endif + +/* workaround unused value warning for a macro that does nothing */ +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L +#define OPENSSL_malloc_init() #endif /* @@ -110,7 +119,7 @@ * If that is not good enough, versions could be added to libopensc */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* based on OpenSSL-1.1.0 e_os2.h */ /* sc_ossl_inline: portable inline definition usable in public headers */ # if !defined(inline) && !defined(__cplusplus) @@ -129,7 +138,7 @@ # endif #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2050300fL) #define RSA_bits(R) (BN_num_bits(R->n)) @@ -140,6 +149,9 @@ #ifndef OPENSSL_NO_DSA #include #endif +#ifndef OPENSSL_NO_EC +#include +#endif #ifndef OPENSSL_NO_RSA static sc_ossl_inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) @@ -239,6 +251,21 @@ /* NOTE: DSA_set0_* functions not defined because they are not currently used in OpenSC */ #endif /* OPENSSL_NO_DSA */ + +#ifndef OPENSSL_NO_EC +static sc_ossl_inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} +#endif /* OPENSSL_NO_EC */ + + #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ #ifdef __cplusplus diff -Nru opensc-0.17.0/src/libopensc/sec.c opensc-0.19.0/src/libopensc/sec.c --- opensc-0.17.0/src/libopensc/sec.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/sec.c 2018-09-13 11:47:21.000000000 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include #endif @@ -220,10 +221,10 @@ * This function will copy a PIN, convert and pad it as required * * Note about the SC_PIN_ENCODING_GLP encoding: - * PIN buffers are allways 16 nibbles (8 bytes) and look like this: + * PIN buffers are always 16 nibbles (8 bytes) and look like this: * 0x2 + len + pin_in_BCD + paddingnibbles * in which the paddingnibble = 0xF - * E.g. if PIN = 12345, then sbuf = {0x24, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF} + * E.g. if PIN = 12345, then sbuf = {0x25, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF} * E.g. if PIN = 123456789012, then sbuf = {0x2C, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0xFF} * Reference: Global Platform - Card Specification - version 2.0.1' - April 7, 2000 */ @@ -243,7 +244,7 @@ if (pin->data[i] < '0' || pin->data[i] > '9') return SC_ERROR_INVALID_ARGUMENTS; } - buf[0] = 0x20 | pin_len; + buf[0] = 0x20 | (u8) pin_len; buf++; buflen--; } @@ -258,6 +259,9 @@ if (pin_len > 2 * buflen) return SC_ERROR_BUFFER_TOO_SMALL; for (i = j = 0; j < pin_len; j++) { + if (!isdigit(pin->data[j])) { + return SC_ERROR_INVALID_DATA; + } buf[i] <<= 4; buf[i] |= pin->data[j] & 0xf; if (j & 1) diff -Nru opensc-0.17.0/src/libopensc/simpletlv.c opensc-0.19.0/src/libopensc/simpletlv.c --- opensc-0.17.0/src/libopensc/simpletlv.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/simpletlv.c 2018-09-13 11:47:21.000000000 +0000 @@ -74,26 +74,38 @@ int sc_simpletlv_read_tag(u8 **buf, size_t buflen, u8 *tag_out, size_t *taglen) { - size_t len; + u8 tag; + size_t left = buflen, len; u8 *p = *buf; - if (buflen < 2) { - *buf = p+buflen; - return SC_ERROR_INVALID_ARGUMENTS; + *buf = NULL; + + if (left < 2) { + return SC_ERROR_INVALID_TLV_OBJECT; } + tag = *p; + p++; + len = *p; + p++; + left -= 2; - *tag_out = *p++; - len = *p++; if (len == 0xff) { /* don't crash on bad data */ - if (buflen < 4) { - *taglen = 0; - return SC_ERROR_INVALID_ARGUMENTS; + if (left < 2) { + return SC_ERROR_INVALID_TLV_OBJECT; } + /* skip two bytes (the size) */ len = lebytes2ushort(p); - p++; + p += 2; + left -= 2; } + + *tag_out = tag; *taglen = len; *buf = p; + + if (len > left) + return SC_ERROR_TLV_END_OF_CONTENTS; + return SC_SUCCESS; } diff -Nru opensc-0.17.0/src/libopensc/sm.c opensc-0.19.0/src/libopensc/sm.c --- opensc-0.17.0/src/libopensc/sm.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/sm.c 2018-09-13 11:47:21.000000000 +0000 @@ -31,6 +31,7 @@ #include "asn1.h" #include "sm.h" +#ifdef ENABLE_SM static const struct sc_asn1_entry c_asn1_sm_response[4] = { { "encryptedData", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 7, SC_ASN1_OPTIONAL, NULL, NULL }, { "statusWord", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x19, 0, NULL, NULL }, @@ -38,7 +39,6 @@ { NULL, 0, 0, 0, NULL, NULL } }; -#ifdef ENABLE_SM int sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len, struct sm_card_response *out) @@ -157,7 +157,7 @@ } /* send APDU flagged as NO_SM */ - sm_apdu->flags |= SC_APDU_FLAGS_NO_SM; + sm_apdu->flags |= SC_APDU_FLAGS_NO_SM | SC_APDU_FLAGS_NO_RETRY_WL; rv = sc_transmit_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); diff -Nru opensc-0.17.0/src/libopensc/sm.h opensc-0.19.0/src/libopensc/sm.h --- opensc-0.17.0/src/libopensc/sm.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/sm.h 2018-09-13 11:47:21.000000000 +0000 @@ -45,8 +45,11 @@ #define SM_TYPE_CWA14890 0x400 #define SM_TYPE_DH_RSA 0x500 +/** don't use SM */ #define SM_MODE_NONE 0x0 +/** let the card driver decide when to use SM, possibly based on the card's ACLs */ #define SM_MODE_ACL 0x100 +/** use SM for all commands */ #define SM_MODE_TRANSMIT 0x200 #define SM_CMD_INITIALIZE 0x10 @@ -300,7 +303,7 @@ /* * @struct sm_module_operations * API to use external SM modules: - * - 'initiliaze' - get APDU(s) to initialize SM session; + * - 'initialize' - get APDU(s) to initialize SM session; * - 'get apdus' - get secured APDUs to execute particular command; * - 'finalize' - get APDU(s) to finalize SM session; * - 'module init' - initialize external module (allocate data, read configuration, ...); @@ -354,7 +357,7 @@ int sc_sm_single_transmit(struct sc_card *, struct sc_apdu *); /** - * @brief Stops SM and frees allocated ressources. + * @brief Stops SM and frees allocated resources. * * Calls \a card->sm_ctx.ops.close() if available and \c card->sm_ctx.sm_mode * is \c SM_MODE_TRANSMIT diff -Nru opensc-0.17.0/src/libopensc/types.h opensc-0.19.0/src/libopensc/types.h --- opensc-0.17.0/src/libopensc/types.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/libopensc/types.h 2018-09-13 11:47:21.000000000 +0000 @@ -149,6 +149,7 @@ #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_CONTEXT_SPECIFIC 0x00000200 /* Context specific login */ #define SC_AC_UNKNOWN 0xFFFFFFFE #define SC_AC_NEVER 0xFFFFFFFF diff -Nru opensc-0.17.0/src/Makefile.am opensc-0.19.0/src/Makefile.am --- opensc-0.17.0/src/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -2,9 +2,13 @@ EXTRA_DIST = Makefile.mak # Order IS important -SUBDIRS = common scconf pkcs15init sm \ - libopensc pkcs11 tools tests minidriver +SUBDIRS = common scconf ui pkcs15init sm \ + libopensc pkcs11 tools minidriver if ENABLE_SM SUBDIRS += smm endif + +if ENABLE_TESTS +SUBDIRS += tests +endif diff -Nru opensc-0.17.0/src/Makefile.mak opensc-0.19.0/src/Makefile.mak --- opensc-0.17.0/src/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,7 @@ TOPDIR = .. -SUBDIRS = common scconf sm pkcs15init \ - libopensc pkcs11 tools tests +SUBDIRS = common scconf ui sm pkcs15init \ + libopensc pkcs11 tools default: all @@ -15,6 +15,10 @@ SUBDIRS = $(SUBDIRS) smm !ENDIF +!IF "$(TESTS_DEF)" == "/DENABLE_TESTS" +SUBDIRS = $(SUBDIRS) tests +!ENDIF + all clean:: @for %i in ( $(SUBDIRS) ) do \ @cmd /c "cd %i && $(MAKE) /nologo /f Makefile.mak $@" diff -Nru opensc-0.17.0/src/minidriver/Makefile.am opensc-0.19.0/src/minidriver/Makefile.am --- opensc-0.17.0/src/minidriver/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,15 +1,15 @@ include $(top_srcdir)/win32/ltrc.inc MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-minidriver.rc -EXTRA_DIST = Makefile.mak versioninfo-minidriver.rc.in +EXTRA_DIST = Makefile.mak versioninfo-minidriver.rc.in opensc-minidriver.dll.manifest if ENABLE_MINIDRIVER lib_LTLIBRARIES = opensc-minidriver@LIBRARY_BITNESS@.la # Do we need this on bin? Why can't we # put it in dedicated directory -dist_sbin_SCRIPTS = opensc-minidriver.inf minidriver-westcos.reg minidriver-sc-hsm.reg minidriver-feitian.reg +dist_sbin_SCRIPTS = opensc-minidriver.inf else -dist_noinst_DATA = opensc-minidriver.inf minidriver-westcos.reg minidriver-sc-hsm.reg minidriver-feitian.reg +dist_noinst_DATA = opensc-minidriver.inf endif AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) diff -Nru opensc-0.17.0/src/minidriver/Makefile.mak opensc-0.19.0/src/minidriver/Makefile.mak --- opensc-0.17.0/src/minidriver/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -3,8 +3,14 @@ TARGET = opensc-minidriver.dll OBJECTS = minidriver.obj versioninfo-minidriver.res LIBS = $(TOPDIR)\src\libopensc\opensc_a.lib \ - $(TOPDIR)\src\pkcs15init\pkcs15init.lib \ - $(TOPDIR)\src\common\libscdl.lib + $(TOPDIR)\src\scconf\scconf.lib \ + $(TOPDIR)\src\common\common.lib \ + $(TOPDIR)\src\common\libscdl.lib \ + $(TOPDIR)\src\ui\strings.lib \ + $(TOPDIR)\src\ui\notify.lib \ + $(TOPDIR)\src\sm\libsmiso.lib \ + $(TOPDIR)\src\sm\libsmeac.lib \ + $(TOPDIR)\src\pkcs15init\pkcs15init.lib all: $(TARGET) @@ -14,5 +20,5 @@ echo LIBRARY $* > $*.def echo EXPORTS >> $*.def type minidriver.exports >> $*.def - 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 + link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib Comctl32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib Shell32.lib Comctl32.lib Winmm.lib /DELAYLOAD:bcrypt.dll if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2 diff -Nru opensc-0.17.0/src/minidriver/minidriver.c opensc-0.19.0/src/minidriver/minidriver.c --- opensc-0.17.0/src/minidriver/minidriver.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/minidriver.c 2018-09-13 11:47:21.000000000 +0000 @@ -32,9 +32,13 @@ #include #include +#include #include #include +#include +#include +#include "cardmod.h" #include "common/compat_strlcpy.h" #include "libopensc/asn1.h" @@ -44,6 +48,9 @@ #include "libopensc/log.h" #include "libopensc/internal.h" #include "libopensc/aux-data.h" +#include "ui/notify.h" +#include "ui/strings.h" +#include "ui/wchar_from_char_str.h" #include "pkcs15init/pkcs15-init.h" #ifdef ENABLE_OPENSSL @@ -71,11 +78,14 @@ #define MD_MAX_KEY_CONTAINERS 12 #define MD_CARDID_SIZE 16 -#define MD_UTC_TIME_LENGTH_MAX 16 -#define MD_CARDCF_LENGTH (sizeof(CARD_CACHE_FILE_FORMAT)) +#define MD_ROLE_USER_SIGN (ROLE_ADMIN + 1) +/* + * must be higher than MD_ROLE_USER_SIGN and + * less than or equal MAX_PINS + */ +#define MD_MAX_PINS MAX_PINS -#define MD_DATA_APPLICAITON_NAME "CSP" -#define MD_DATA_DEFAULT_CONT_LABEL "Default Key Container" +#define MD_CARDCF_LENGTH (sizeof(CARD_CACHE_FILE_FORMAT)) #define MD_KEY_USAGE_KEYEXCHANGE \ SC_PKCS15INIT_X509_KEY_ENCIPHERMENT | \ @@ -111,10 +121,9 @@ #endif /* defined twice: in versioninfo-minidriver.rc.in and in minidriver.c */ -#define IDD_PINPAD 101 -#define IDI_LOGO 102 -#define IDC_PINPAD_TEXT 1001 -#define IDC_PINPAD_ICON 1000 +#define IDI_SMARTCARD 102 + +#define SUBKEY_ENABLE_CANCEL "Software\\OpenSC Project\\OpenSC\\md_pinpad_dlg_enable_cancel" /* magic to determine previous pinpad authentication */ #define MAGIC_SESSION_PIN "opensc-minidriver" @@ -172,7 +181,9 @@ typedef struct _VENDOR_SPECIFIC { - struct sc_pkcs15_object *obj_user_pin, *obj_sopin; + BOOL initialized; + + struct sc_pkcs15_object *pin_objs[MD_MAX_PINS]; struct sc_context *ctx; struct sc_reader *reader; @@ -194,60 +205,17 @@ /* these will be used to store intermediate dh agreements results */ struct md_dh_agreement* dh_agreements; BYTE allocatedAgreements; -}VENDOR_SPECIFIC; - -/* - * Windows (ex. Vista) may access the card from more than one thread. - * The following data type and static data is an attempt to resolve - * some of the encountered multi-thread issues of OpenSC - * on the minidriver side. - * - * TODO: resolve multi-thread issues on the OpenSC side - */ -#define MD_STATIC_FLAG_READ_ONLY 1 -#define MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT 2 -#define MD_STATIC_FLAG_CONTEXT_DELETED 4 -#define MD_STATIC_FLAG_GUID_AS_ID 8 -#define MD_STATIC_FLAG_GUID_AS_LABEL 16 -#define MD_STATIC_FLAG_CREATE_CONTAINER_KEY_IMPORT 32 -#define MD_STATIC_FLAG_CREATE_CONTAINER_KEY_GEN 64 -#define MD_STATIC_FLAG_IGNORE_PIN_LENGTH 128 - -#define MD_STATIC_PROCESS_ATTACHED 0xA11AC4EDL -struct md_opensc_static_data { - unsigned flags, flags_checked; - unsigned long attach_check; -}; -static struct md_opensc_static_data md_static_data; - -#define C_ASN1_MD_CONTAINER_ATTRS_SIZE 7 -static const struct sc_asn1_entry c_asn1_md_container_attrs[C_ASN1_MD_CONTAINER_ATTRS_SIZE] = { - { "index", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, - { "id", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_EMPTY_ALLOWED, NULL, NULL }, - { "guid", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_EMPTY_ALLOWED, NULL, NULL }, - { "flags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, - { "sizeKeyExchange", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, - { "sizeSign", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, - { NULL, 0, 0, 0, NULL, NULL } -}; - -#define C_ASN1_MD_CONTAINER_SIZE 2 -static const struct sc_asn1_entry c_asn1_md_container[C_ASN1_MD_CONTAINER_SIZE] = { - { "mdContainer", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, - { NULL, 0, 0, 0, NULL, NULL } -}; + CRITICAL_SECTION hScard_lock; +} VENDOR_SPECIFIC; static DWORD md_translate_OpenSC_to_Windows_error(int OpenSCerror, DWORD dwDefaulCode); -static int associate_card(PCARD_DATA pCardData); -static int disassociate_card(PCARD_DATA pCardData); +static DWORD associate_card(PCARD_DATA pCardData); +static void disassociate_card(PCARD_DATA pCardData); static DWORD md_pkcs15_delete_object(PCARD_DATA pCardData, struct sc_pkcs15_object *obj); static DWORD md_fs_init(PCARD_DATA pCardData); - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif +static void md_fs_finalize(PCARD_DATA pCardData); #if defined(__GNUC__) static void logprintf(PCARD_DATA pCardData, int level, const char* format, ...) @@ -258,11 +226,11 @@ { va_list arg; VENDOR_SPECIFIC *vs; -/* Use a simplied log to get all messages including messages +/* Use a simplified log to get all messages including messages * before opensc is loaded. The file must be modifiable by all * users as we maybe called under lsa or user. Note data from * multiple process and threads may get intermingled. - * flush to get last message before ann crash + * flush to get last message before any crash * close so as the file is not left open during any wait. */ DWORD md_debug = 0; @@ -330,22 +298,114 @@ logprintf(pCardData, level, " %04X %s\n", a, line); } +static DWORD reinit_card(PCARD_DATA pCardData) +{ + VENDOR_SPECIFIC *vs; + DWORD r; + + if (!pCardData) + return SCARD_E_INVALID_PARAMETER; + + vs = (VENDOR_SPECIFIC *)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + + logprintf(pCardData, 2, "trying to reinit card\n"); + + if (vs->initialized) { + disassociate_card(pCardData); + md_fs_finalize(pCardData); + } + + r = associate_card(pCardData); + if (r != SCARD_S_SUCCESS) + return r; + + r = md_fs_init(pCardData); + if (r != SCARD_S_SUCCESS) { + logprintf(pCardData, 1, + "reinit_card md_fs_init failed, r = 0x%lX\n", + (unsigned long)r); + disassociate_card(pCardData); + return r; + } + + return SCARD_S_SUCCESS; +} + +static BOOL lock(PCARD_DATA pCardData) +{ + if (pCardData) { + VENDOR_SPECIFIC *vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (vs) { + EnterCriticalSection(&vs->hScard_lock); + return TRUE; + } + } + + return FALSE; +} + +static void unlock(PCARD_DATA pCardData) +{ + if (pCardData) { + VENDOR_SPECIFIC *vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (vs) { + LeaveCriticalSection(&vs->hScard_lock); + } + } +} + +static DWORD reinit_card_for(PCARD_DATA pCardData, const char *name) +{ + DWORD r; + + r = reinit_card(pCardData); + if (r != SCARD_S_SUCCESS) + logprintf(pCardData, 1, + "%s was called, but unable to initialize card, r = %u\n", + name, (unsigned int)r); + + return r; +} + +static DWORD check_card_status(PCARD_DATA pCardData, const char *name) +{ + VENDOR_SPECIFIC *vs; + + if (!pCardData) + return SCARD_E_INVALID_PARAMETER; + + vs = (VENDOR_SPECIFIC *)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + + if (vs->initialized) + return SCARD_S_SUCCESS; + + return reinit_card_for(pCardData, name); +} + /* - * check if the card has been removed, or the + * check if the card is OK, has been removed, or the * caller has changed the handles. - * if so, then free up all previous card info - * and reestablish + * if so, then try to reinit card */ -static int -check_reader_status(PCARD_DATA pCardData) +static DWORD +check_card_reader_status(PCARD_DATA pCardData, const char *name) { - int r = SCARD_S_SUCCESS; VENDOR_SPECIFIC *vs = NULL; + DWORD dwRet; + int r; logprintf(pCardData, 4, "check_reader_status\n"); if(!pCardData) return SCARD_E_INVALID_PARAMETER; + dwRet = check_card_status(pCardData, name); + if (dwRet != SCARD_S_SUCCESS) + return dwRet; + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if(!vs) return SCARD_E_INVALID_PARAMETER; @@ -358,34 +418,36 @@ logprintf(pCardData, 1, "HANDLES CHANGED from 0x%08X 0x%08X\n", (unsigned int)vs->hSCardCtx, (unsigned int)vs->hScard); + return reinit_card_for(pCardData, name); + } - /* Basically a mini AcquireContext */ - r = disassociate_card(pCardData); - logprintf(pCardData, 1, "disassociate_card r = 0x%08X\n", r); - r = associate_card(pCardData); /* need to check return codes */ - if (r != SCARD_S_SUCCESS) - return r; - logprintf(pCardData, 1, "associate_card r = 0x%08X\n", r); - /* Rebuild 'soft' fs - in case changed */ - r = md_fs_init(pCardData); - logprintf(pCardData, 1, "md_fs_init r = 0x%08X\n", r); - } - else if (vs->reader) { - /* This should always work, as BaseCSP should be checking for removal too */ - r = sc_detect_card_presence(vs->reader); - logprintf(pCardData, 2, - "check_reader_status r=%d flags 0x%08X\n", r, - (unsigned int)vs->reader->flags); + /* This should always work, as BaseCSP should be checking for removal too */ + r = sc_detect_card_presence(vs->reader); + logprintf(pCardData, 2, + "check_reader_status r=%d flags 0x%08X\n", r, + (unsigned int)vs->reader->flags); + if (r < 0) + return md_translate_OpenSC_to_Windows_error(r, + SCARD_F_INTERNAL_ERROR); + + if (!(r & SC_READER_CARD_PRESENT)) { + /* + * if there is really no card present it may not make sense to + * try initializing the card but since it won't hurt let's try + * it anyway for completeness + */ + logprintf(pCardData, 1, "no card present? trying to reinit\n"); + return reinit_card_for(pCardData, name); } - return r; + return SCARD_S_SUCCESS; } static DWORD md_get_pin_by_role(PCARD_DATA pCardData, PIN_ID role, struct sc_pkcs15_object **ret_obj) { VENDOR_SPECIFIC *vs; - int rv = SC_SUCCESS; + int rv; if (!pCardData) return SCARD_E_INVALID_PARAMETER; @@ -394,61 +456,185 @@ if (!ret_obj) return SCARD_E_INVALID_PARAMETER; - *ret_obj = NULL; - - if (role == ROLE_USER) { - if (!vs->obj_user_pin) { - /* Get 'global' User PIN; if no, get the 'local' one */ - rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL, - SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_user_pin); - if (rv) + /* please keep me in sync with _get_auth_object_by_name() in pkcs11/framework-pkcs15.c */ + if (role == ROLE_USER) { + /* Get 'global' User PIN; if no, get the 'local' one */ + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); + if (rv) + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_LOCAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); + } + else if (role == MD_ROLE_USER_SIGN) { + int idx = 0; + + /* Get the 'global' user PIN */ + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); + if (!rv) { + /* Global (user) PIN exists, get the local one -- sign PIN */ + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_LOCAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); + } + else { + /* No global PIN, try to get first local one -- user PIN */ + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_LOCAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, &idx, ret_obj); + if (!rv) { + /* User PIN is local, try to get the second local -- sign PIN */ + idx++; rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_LOCAL, - SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_user_pin); + SC_PKCS15_PIN_TYPE_FLAGS_MASK, &idx, ret_obj); + } } - - *ret_obj = vs->obj_user_pin; } - else if (role == ROLE_ADMIN) { + else if (role == ROLE_ADMIN) { /* Get SO PIN; if no, get the 'global' PUK; if no get the 'local' one */ - if (!vs->obj_sopin) { - rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_SOPIN, - SC_PKCS15_PIN_TYPE_FLAGS_SOPIN, NULL, &vs->obj_sopin); - if (rv) - rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_GLOBAL, - SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_sopin); - if (rv) - rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_LOCAL, - SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_sopin); - } - - *ret_obj = vs->obj_sopin; + rv = sc_pkcs15_find_so_pin(vs->p15card, ret_obj); + if (rv) + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_GLOBAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); + if (rv) + rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_LOCAL, + SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, ret_obj); } else { - logprintf(pCardData, 2, "cannot get PIN object: unsupported role\n"); + logprintf(pCardData, 2, + "cannot get PIN object: unsupported role %u\n", + (unsigned int)role); return SCARD_E_UNSUPPORTED_FEATURE; } - return (rv == SC_SUCCESS) ? SCARD_S_SUCCESS : SCARD_E_UNSUPPORTED_FEATURE; + if (rv) + return SCARD_E_UNSUPPORTED_FEATURE; + + if (*ret_obj) + logprintf(pCardData, 7, "Returning PIN '%.*s' for role %u\n", + (int) sizeof (*ret_obj)->label, (*ret_obj)->label, + (unsigned int)role); + + return SCARD_S_SUCCESS; } +static const char * +md_get_config_str(PCARD_DATA pCardData, enum ui_str id) +{ + VENDOR_SPECIFIC *vs; + const char *ret = NULL; -static BOOL -md_get_config_bool(PCARD_DATA pCardData, char *flag_name, unsigned flag, BOOL ret_default) + if (!pCardData) + return ret; + + vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (vs->ctx && vs->reader) { + const char *preferred_language = NULL; + struct sc_atr atr; + atr.len = pCardData->cbAtr; + memcpy(atr.value, pCardData->pbAtr, atr.len); + if (vs->p15card && vs->p15card->tokeninfo + && vs->p15card->tokeninfo->preferred_language) { + preferred_language = vs->p15card->tokeninfo->preferred_language; + } + ret = ui_get_str(vs->ctx, &atr, vs->p15card, id); + } + + return ret; +} + + +static HICON +md_get_config_icon(PCARD_DATA pCardData, char *flag_name, HICON ret_default) { VENDOR_SPECIFIC *vs; - BOOL ret = ret_default; + HICON ret = ret_default; if (!pCardData) return ret; logprintf(pCardData, 2, "Get '%s' option\n", flag_name); - if (md_static_data.flags_checked & flag) { - ret = (md_static_data.flags & flag) ? TRUE : FALSE; - logprintf(pCardData, 2, "Returns checked flag: %s\n", ret ? "TRUE" : "FALSE"); + + vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (vs->ctx && vs->reader) { + struct sc_atr atr; + scconf_block *atrblock; + atr.len = pCardData->cbAtr; + memcpy(atr.value, pCardData->pbAtr, atr.len); + atrblock = _sc_match_atr_block(vs->ctx, NULL, &atr); + logprintf(pCardData, 2, "Match ATR:\n"); + loghex(pCardData, 3, atr.value, atr.len); + + if (atrblock) { + const char *filename = scconf_get_str(atrblock, flag_name, NULL); + if (filename) { + ret = (HICON) LoadImage(g_inst, filename, IMAGE_ICON, 0, 0, + LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_SHARED); + } + if (!ret) + ret = ret_default; + } + } + + + return ret; +} + + +static HICON +md_get_pinpad_dlg_icon(PCARD_DATA pCardData) +{ + return md_get_config_icon(pCardData, "md_pinpad_dlg_icon", NULL); +} + + +static int +md_get_config_int(PCARD_DATA pCardData, char *flag_name, int ret_default) +{ + VENDOR_SPECIFIC *vs; + int ret = ret_default; + + if (!pCardData) return ret; + + logprintf(pCardData, 2, "Get '%s' option\n", flag_name); + + vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (vs->ctx && vs->reader) { + struct sc_atr atr; + scconf_block *atrblock; + atr.len = pCardData->cbAtr; + memcpy(atr.value, pCardData->pbAtr, atr.len); + atrblock = _sc_match_atr_block(vs->ctx, NULL, &atr); + logprintf(pCardData, 2, "Match ATR:\n"); + loghex(pCardData, 3, atr.value, atr.len); + + if (atrblock) + ret = scconf_get_int(atrblock, flag_name, ret_default); } + return ret; +} + + +static int +md_get_pinpad_dlg_timeout(PCARD_DATA pCardData) +{ + return md_get_config_int(pCardData, "md_pinpad_dlg_timeout", 30); +} + + +static BOOL +md_get_config_bool(PCARD_DATA pCardData, char *flag_name, BOOL ret_default) +{ + VENDOR_SPECIFIC *vs; + BOOL ret = ret_default; + + if (!pCardData) + return ret; + vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (!vs) + return ret; + if (vs->ctx && vs->reader) { struct sc_atr atr; scconf_block *atrblock; @@ -462,25 +648,44 @@ ret = scconf_get_bool(atrblock, flag_name, ret_default) ? TRUE : FALSE; } - md_static_data.flags_checked |= flag; - if (ret == TRUE) - md_static_data.flags |= flag; - else - md_static_data.flags &= ~flag; - - logprintf(pCardData, 2, "Returns '%s' flag '%s', static flags/checked %X/%X\n", - flag_name, ret ? "TRUE" : "FALSE", - md_static_data.flags, md_static_data.flags_checked); return ret; } +/* 'cancellation' mode can be enabled from the OpenSC configuration file*/ +static BOOL +md_is_pinpad_dlg_enable_cancel(PCARD_DATA pCardData) +{ + TCHAR path[MAX_PATH]={0}; + + logprintf(pCardData, 2, "Is cancelling the PIN pad dialog enabled?\n"); + + if (GetModuleFileName(NULL, path, ARRAYSIZE(path))) { + DWORD enable_cancel; + size_t sz = sizeof enable_cancel; + + if (SC_SUCCESS == sc_ctx_win32_get_config_value(NULL, path, + SUBKEY_ENABLE_CANCEL, + (char *)(&enable_cancel), &sz)) { + switch (enable_cancel) { + case 0: + return FALSE; + case 1: + return TRUE; + } + } + } + + return md_get_config_bool(pCardData, "md_pinpad_dlg_enable_cancel", FALSE); +} + + /* 'Write' mode can be enabled from the OpenSC configuration file*/ static BOOL md_is_read_only(PCARD_DATA pCardData) { logprintf(pCardData, 2, "Is read-only?\n"); - return md_get_config_bool(pCardData, "md_read_only", MD_STATIC_FLAG_READ_ONLY, TRUE); + return md_get_config_bool(pCardData, "md_read_only", TRUE); } @@ -490,7 +695,7 @@ { BOOL defaultvalue = !md_is_read_only(pCardData); logprintf(pCardData, 2, "Is supports X509 enrollment?\n"); - return md_get_config_bool(pCardData, "md_supports_X509_enrollment", MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT, defaultvalue); + return md_get_config_bool(pCardData, "md_supports_X509_enrollment", defaultvalue); } @@ -499,7 +704,7 @@ md_is_guid_as_id(PCARD_DATA pCardData) { logprintf(pCardData, 2, "Is GUID has to be used as ID of crypto objects?\n"); - return md_get_config_bool(pCardData, "md_guid_as_id", MD_STATIC_FLAG_GUID_AS_ID, FALSE); + return md_get_config_bool(pCardData, "md_guid_as_id", FALSE); } @@ -508,7 +713,7 @@ md_is_guid_as_label(PCARD_DATA pCardData) { logprintf(pCardData, 2, "Is GUID has to be used as label of crypto objects?\n"); - return md_get_config_bool(pCardData, "md_guid_as_label", MD_STATIC_FLAG_GUID_AS_LABEL, FALSE); + return md_get_config_bool(pCardData, "md_guid_as_label", FALSE); } @@ -517,7 +722,7 @@ md_is_supports_container_key_gen(PCARD_DATA pCardData) { logprintf(pCardData, 2, "Is supports 'key generation' create_container mechanism?\n"); - return md_get_config_bool(pCardData, "md_supports_container_key_gen", MD_STATIC_FLAG_CREATE_CONTAINER_KEY_GEN, TRUE); + return md_get_config_bool(pCardData, "md_supports_container_key_gen", TRUE); } @@ -526,7 +731,7 @@ md_is_supports_container_key_import(PCARD_DATA pCardData) { logprintf(pCardData, 2, "Is supports 'key import' create container mechanism?\n"); - return md_get_config_bool(pCardData, "md_supports_container_key_import", MD_STATIC_FLAG_CREATE_CONTAINER_KEY_IMPORT, TRUE); + return md_get_config_bool(pCardData, "md_supports_container_key_import", TRUE); } /* generate unique key label (GUID)*/ @@ -549,6 +754,9 @@ size_t guid_len = MAX_CONTAINER_NAME_LEN+1; vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + rv = sc_pkcs15_get_object_guid(vs->p15card, prkey, 1, (unsigned char*) szGuid, &guid_len); if (rv) { logprintf(pCardData, 2, "md_contguid_get_guid_from_card(): error %d\n", rv); @@ -629,7 +837,7 @@ DWORD dwret = SCARD_S_SUCCESS; szGuid[0] = '\0'; - /* priorize the use of the key id over the key label as a container name */ + /* prioritize the use of the key id over the key label as a container name */ if (md_is_guid_as_id(pCardData) && prkey_info->id.len > 0 && prkey_info->id.len <= MAX_CONTAINER_NAME_LEN) { memcpy(szGuid, prkey_info->id.value, prkey_info->id.len); szGuid[prkey_info->id.len] = 0; @@ -651,6 +859,9 @@ int rv; vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + prkey_info = (struct sc_pkcs15_prkey_info *)key_obj->data; *cont_flags = CONTAINER_MAP_VALID_CONTAINER; @@ -678,6 +889,9 @@ return SCARD_E_INVALID_PARAMETER; vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + if (!parent) parent = &vs->root; @@ -857,6 +1071,8 @@ return SCARD_E_INVALID_PARAMETER; vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; dwret = md_fs_find_directory(pCardData, NULL, parent, &dir); if (dwret != SCARD_S_SUCCESS) { @@ -917,7 +1133,7 @@ return dwret; } -static DWORD +static void md_fs_finalize(PCARD_DATA pCardData) { VENDOR_SPECIFIC *vs; @@ -925,9 +1141,11 @@ struct md_directory *dir = NULL, *dir_to_rm; if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + return; vs = pCardData->pvVendorSpecific; + if (!vs) + return; file = vs->root.files; while (file != NULL) { @@ -935,6 +1153,7 @@ file = file->next; md_fs_free_file(pCardData, file_to_rm); } + vs->root.files = NULL; dir = vs->root.subdirs; while(dir) { @@ -948,7 +1167,7 @@ dir = dir->next; pCardData->pfnCspFree(dir_to_rm); } - return 0; + vs->root.subdirs = NULL; } /* @@ -966,6 +1185,8 @@ return SCARD_E_INVALID_PARAMETER; vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; nn_records = (int) size/sizeof(CONTAINER_MAP_RECORD); if (nn_records > MD_MAX_KEY_CONTAINERS) @@ -1012,6 +1233,9 @@ if (!pCardData) return SCARD_E_INVALID_PARAMETER; vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + card = vs->p15card->card; if (!obj) @@ -1092,6 +1316,9 @@ return SCARD_E_INVALID_PARAMETER; vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + if (vs->p15card->tokeninfo && vs->p15card->tokeninfo->serial_number) { unsigned char sn_bin[SC_MAX_SERIALNR]; unsigned char cardid_bin[MD_CARDID_SIZE]; @@ -1107,12 +1334,16 @@ memcpy(sn_bin, vs->p15card->tokeninfo->serial_number, sn_len); } - for (offs=0; offs < MD_CARDID_SIZE; ) { - wr = MD_CARDID_SIZE - offs; - if (wr > sn_len) - wr = sn_len; - memcpy(cardid_bin + offs, sn_bin, wr); - offs += wr; + if (sn_len > 0) { + for (offs=0; offs < MD_CARDID_SIZE; ) { + wr = MD_CARDID_SIZE - offs; + if (wr > sn_len) + wr = sn_len; + memcpy(cardid_bin + offs, sn_bin, wr); + offs += wr; + } + } else { + memset(cardid_bin, 0, MD_CARDID_SIZE); } dwret = md_fs_set_content(pCardData, file, cardid_bin, MD_CARDID_SIZE); @@ -1343,6 +1574,8 @@ return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC *) pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; rv = sc_pkcs15_get_objects(vs->p15card, SC_PKCS15_TYPE_CERT_X509, prkey_objs, MD_MAX_KEY_CONTAINERS); if (rv < 0) { @@ -1371,11 +1604,19 @@ * 2b. Change the index of internal p15_container according to the index from 'DATA' file. * Records from 'DATA' file are ignored is they do not have * the corresponding PKCS#15 private key object. - * 3. Initalize the content of the 'soft' 'cmapfile' from the inernal p15-containers. + * 3. Initialize the content of the 'soft' 'cmapfile' from the internal p15-containers. */ static DWORD md_set_cmapfile(PCARD_DATA pCardData, struct md_file *file) { + typedef enum { SCF_NONE, + SCF_NONDEFAULT_SIGN_PIN, + SCF_NONDEFAULT_OTHER_PIN, + SCF_NONDEFAULT_USER_PIN, + SCF_DEFAULT_SIGN_PIN, + SCF_DEFAULT_OTHER_PIN, + SCF_DEFAULT_USER_PIN + } pin_mode_t; VENDOR_SPECIFIC *vs; PCONTAINER_MAP_RECORD p; unsigned char *cmap_buf = NULL; @@ -1384,12 +1625,35 @@ int ii, rv, conts_num, found_default = 0; /* struct sc_pkcs15_data *data_object; */ struct sc_pkcs15_object *prkey_objs[MD_MAX_KEY_CONTAINERS]; + pin_mode_t pin_mode = SCF_NONE; + int pin_cont_idx = -1; if (!pCardData || !file) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 2, "set 'cmapfile'\n"); vs = pCardData->pvVendorSpecific; + if (!vs) + return SCARD_E_INVALID_PARAMETER; + + dwret = md_get_pin_by_role(pCardData, ROLE_USER, &vs->pin_objs[ROLE_USER]); + if (dwret != SCARD_S_SUCCESS) { + logprintf(pCardData, 2, "Cannot get User PIN object"); + return dwret; + } + + dwret = md_get_pin_by_role(pCardData, MD_ROLE_USER_SIGN, &vs->pin_objs[MD_ROLE_USER_SIGN]); + if (dwret != SCARD_S_SUCCESS) { + logprintf(pCardData, 2, "Cannot get Sign PIN object -- ignored"); + vs->pin_objs[MD_ROLE_USER_SIGN] = NULL; + } + + dwret = md_get_pin_by_role(pCardData, ROLE_ADMIN, &vs->pin_objs[ROLE_ADMIN]); + if (dwret != SCARD_S_SUCCESS) { + logprintf(pCardData, 2, "Cannot get Admin PIN object -- ignored"); + vs->pin_objs[ROLE_ADMIN] = NULL; + } + cmap_len = MD_MAX_KEY_CONTAINERS*sizeof(CONTAINER_MAP_RECORD); cmap_buf = pCardData->pfnCspAlloc(cmap_len); if(!cmap_buf) @@ -1431,7 +1695,116 @@ dwret = md_cont_flags_from_key(pCardData, key_obj, &cont->flags); if (dwret != SCARD_S_SUCCESS) return dwret; - if (cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER) + + logprintf(pCardData, 7, "Container[%i] is '%.*s' guid=%.*s\n", ii, + (int) sizeof key_obj->label, key_obj->label, + (int) sizeof cont->guid, cont->guid); + + if (cont->flags & CONTAINER_MAP_VALID_CONTAINER && + key_obj->auth_id.len > 0) { + struct sc_pkcs15_object *keypin_obj; + struct sc_pkcs15_auth_info *userpin_info = + (struct sc_pkcs15_auth_info *)vs->pin_objs[ROLE_USER]->data; + struct sc_pkcs15_auth_info *signpin_info = + vs->pin_objs[MD_ROLE_USER_SIGN] ? + (struct sc_pkcs15_auth_info *)vs->pin_objs[MD_ROLE_USER_SIGN]->data : + NULL; + struct sc_pkcs15_auth_info *adminpin_info = + vs->pin_objs[ROLE_ADMIN] ? + (struct sc_pkcs15_auth_info *)vs->pin_objs[ROLE_ADMIN]->data : + NULL; + + if (sc_pkcs15_find_pin_by_auth_id(vs->p15card, &key_obj->auth_id, &keypin_obj)) + logprintf(pCardData, 2, + "Container[%i] has an unknown auth id, might not work properly\n", + ii); + else { + size_t pinidx; + size_t pinidxempty = MD_MAX_PINS; + for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { + struct sc_pkcs15_auth_info *pin_info; + + if (!vs->pin_objs[pinidx]) { + if (pinidxempty >= MD_MAX_PINS) + pinidxempty = pinidx; + + continue; + } + + pin_info = + (struct sc_pkcs15_auth_info *)vs->pin_objs[pinidx]->data; + + if (sc_pkcs15_compare_id(&key_obj->auth_id, + &pin_info->auth_id)) + break; + } + + if (pinidx >= MD_MAX_PINS) { + if (pinidxempty >= MD_MAX_PINS) + logprintf(pCardData, 2, + "no free slot for container[%i] auth id, might not work properly\n", + ii); + else + vs->pin_objs[pinidxempty] = keypin_obj; + } + + if (sc_pkcs15_compare_id(&key_obj->auth_id, &userpin_info->auth_id)) { + pin_mode_t pin_mode_n = + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + SCF_DEFAULT_USER_PIN : SCF_NONDEFAULT_USER_PIN; + + logprintf(pCardData, 7, + "Container[%i]%s is secured by User PIN\n", + ii, + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + " (default)" : ""); + + if (pin_mode < pin_mode_n) { + pin_mode = pin_mode_n; + pin_cont_idx = ii; + } + } else if (signpin_info != NULL && + sc_pkcs15_compare_id(&key_obj->auth_id, &signpin_info->auth_id)) { + pin_mode_t pin_mode_n = + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + SCF_DEFAULT_SIGN_PIN : SCF_NONDEFAULT_SIGN_PIN; + + logprintf(pCardData, 7, + "Container[%i]%s is secured by Sign PIN\n", + ii, + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + " (default)" : ""); + + if (pin_mode < pin_mode_n) { + pin_mode = pin_mode_n; + pin_cont_idx = ii; + } + } else if (adminpin_info != NULL && + sc_pkcs15_compare_id(&key_obj->auth_id, &adminpin_info->auth_id)) { + logprintf(pCardData, 2, + "Container[%i] is secured by Admin PIN, might not work properly\n", + ii); + } else { + pin_mode_t pin_mode_n = + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + SCF_DEFAULT_OTHER_PIN : SCF_NONDEFAULT_OTHER_PIN; + + logprintf(pCardData, 7, + "Container[%i]%s is secured by other PIN\n", + ii, + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER ? + " (default)" : ""); + + if (pin_mode < pin_mode_n) { + pin_mode = pin_mode_n; + pin_cont_idx = ii; + } + } + } + } + + if (cont->flags & CONTAINER_MAP_VALID_CONTAINER && + cont->flags & CONTAINER_MAP_DEFAULT_CONTAINER) found_default = 1; /* AT_KEYEXCHANGE is more general key usage, @@ -1455,7 +1828,6 @@ cont->size_key_exchange = prkey_info->field_length; } - logprintf(pCardData, 7, "Container[%i]'s guid=%.*s\n", ii, (int) sizeof cont->guid, cont->guid); logprintf(pCardData, 7, "Container[%i]'s key-exchange:%"SC_FORMAT_LEN_SIZE_T"u, sign:%"SC_FORMAT_LEN_SIZE_T"u\n", ii, cont->size_key_exchange, cont->size_sign); @@ -1463,7 +1835,7 @@ cont->id = prkey_info->id; cont->prkey_obj = prkey_objs[ii]; - /* Try to find the friend objects: certficate and public key */ + /* Try to find the friend objects: certificate and public key */ if (!sc_pkcs15_find_cert_by_id(vs->p15card, &cont->id, &cont->cert_obj)) logprintf(pCardData, 2, "found certificate friend '%.*s'\n", (int) sizeof cont->cert_obj->label, cont->cert_obj->label); @@ -1489,11 +1861,11 @@ for (ii=0;iidata; - if (strcmp(dinfo->app_label, MD_DATA_APPLICAITON_NAME)) + if (strcmp(dinfo->app_label, "CSP")) continue; logprintf(pCardData, 2, "Found 'DATA' object '%.*s'\n", (int) sizeof dobjs[ii]->label, dobjs[ii]->label); - if (!strncmp(dobjs[ii]->label, MD_DATA_DEFAULT_CONT_LABEL, sizeof dobjs[ii]->label)) { + if (!strncmp(dobjs[ii]->label, "Default Key Container", sizeof dobjs[ii]->label)) { default_cont = dobjs[ii]; continue; } @@ -1513,13 +1885,115 @@ } } #endif - /* Initialize 'CMAPFILE' content from the P15 containers */ - p = (PCONTAINER_MAP_RECORD)cmap_buf; - for (ii=0; iip15_containers[ii].flags & CONTAINER_MAP_VALID_CONTAINER)) - continue; - if (!found_default) { + /* if no default container was found promote the best one (PIN-wise) to default */ + if (!found_default && (pin_mode == SCF_NONDEFAULT_SIGN_PIN || + pin_mode == SCF_NONDEFAULT_OTHER_PIN || + pin_mode == SCF_NONDEFAULT_USER_PIN)) { + struct md_pkcs15_container *cont = + &vs->p15_containers[pin_cont_idx]; + cont->flags |= CONTAINER_MAP_DEFAULT_CONTAINER; + + found_default = 1; + + logprintf(pCardData, 7, + "Container[%i] promoted to default\n", + pin_cont_idx); + + if (pin_mode == SCF_NONDEFAULT_SIGN_PIN) + pin_mode = SCF_DEFAULT_SIGN_PIN; + else if (pin_mode == SCF_NONDEFAULT_OTHER_PIN) + pin_mode = SCF_DEFAULT_OTHER_PIN; + else + pin_mode = SCF_DEFAULT_USER_PIN; + } + + /* if all containers use non-user PINs we need to make the best container PIN the user (primary) one */ + if (pin_mode == SCF_NONDEFAULT_SIGN_PIN || + pin_mode == SCF_DEFAULT_SIGN_PIN || + pin_mode == SCF_NONDEFAULT_OTHER_PIN || + pin_mode == SCF_DEFAULT_OTHER_PIN) { + struct sc_pkcs15_object *user_pin_old = + vs->pin_objs[ROLE_USER]; + struct sc_pkcs15_object *user_pin_new = + NULL; + + if (pin_mode == SCF_NONDEFAULT_SIGN_PIN || + pin_mode == SCF_DEFAULT_SIGN_PIN) { + user_pin_new = vs->pin_objs[MD_ROLE_USER_SIGN]; + vs->pin_objs[MD_ROLE_USER_SIGN] = NULL; + + logprintf(pCardData, 7, + "Sign PIN%s promoted to user one\n", + pin_mode == SCF_DEFAULT_SIGN_PIN ? + " (from default container)" : ""); + } else { + struct sc_pkcs15_object *key_obj = + vs->p15_containers[pin_cont_idx].prkey_obj; + struct sc_pkcs15_object *keypin_obj; + + if (sc_pkcs15_find_pin_by_auth_id(vs->p15card, &key_obj->auth_id, &keypin_obj)) + logprintf(pCardData, 2, + "Cannot find container[%i] auth id again, might not work properly\n", + pin_cont_idx); + else { + size_t pinidx; + + logprintf(pCardData, 7, + "Container[%i]%s PIN will be made the user one\n", + pin_cont_idx, + pin_mode == SCF_DEFAULT_OTHER_PIN ? + " (default)" : ""); + + for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { + struct sc_pkcs15_auth_info *pin_info; + + if (!vs->pin_objs[pinidx]) + continue; + + pin_info = + (struct sc_pkcs15_auth_info *)vs->pin_objs[pinidx]->data; + + if (sc_pkcs15_compare_id(&key_obj->auth_id, + &pin_info->auth_id)) { + vs->pin_objs[pinidx] = NULL; + break; + } + } + + user_pin_new = keypin_obj; + } + } + + if (user_pin_new) { + size_t pinidx; + + vs->pin_objs[ROLE_USER] = user_pin_new; + + for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { + if (vs->pin_objs[pinidx]) + continue; + + vs->pin_objs[pinidx] = user_pin_old; + break; + } + + if (pinidx >= MD_MAX_PINS) { + logprintf(pCardData, 2, + "no free slot for previous User PIN, replacing last one\n"); + + vs->pin_objs[MD_MAX_PINS - 1] = user_pin_old; + } + } + } + + /* Initialize 'CMAPFILE' content from the P15 containers */ + p = (PCONTAINER_MAP_RECORD)cmap_buf; + for (ii=0; iip15_containers[ii].flags & CONTAINER_MAP_VALID_CONTAINER)) + continue; + + if (!found_default) { vs->p15_containers[ii].flags |= CONTAINER_MAP_DEFAULT_CONTAINER; found_default = 1; } @@ -1589,32 +2063,32 @@ return dwret; dwret = md_set_cardid(pCardData, cardid); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_fs_add_file(pCardData, &(vs->root.files), "cardcf", EveryoneReadUserWriteAc, NULL, 0, &cardcf); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_set_cardcf(pCardData, cardcf); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_fs_add_file(pCardData, &(vs->root.files), "cardapps", EveryoneReadAdminWriteAc, NULL, 0, &cardapps); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_set_cardapps(pCardData, cardapps); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_fs_add_directory(pCardData, &(vs->root.subdirs), "mscp", UserCreateDeleteDirAc, &mscp); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_fs_add_file(pCardData, &(mscp->files), "cmapfile", EveryoneReadUserWriteAc, NULL, 0, &cmapfile); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; dwret = md_set_cmapfile(pCardData, cmapfile); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto ret_cleanup; #ifdef OPENSSL_VERSION_NUMBER logprintf(pCardData, 3, @@ -1625,6 +2099,10 @@ "MD virtual file system initialized; Without OPENSSL\n"); #endif return SCARD_S_SUCCESS; + +ret_cleanup: + md_fs_finalize(pCardData); + return dwret; } /* Create SC context */ @@ -1684,6 +2162,8 @@ return ERROR_REVISION_MISMATCH; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; /* Count free containers */ for (idx=0, count=0; idxpvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; if (flags & CARD_CREATE_CONTAINER_KEY_IMPORT) { if (key_algo == SC_ALGORITHM_RSA) { @@ -1833,7 +2315,7 @@ static DWORD -md_pkcs15_generate_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, DWORD key_size) +md_pkcs15_generate_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, DWORD key_size, PIN_ID PinId) { VENDOR_SPECIFIC *vs; struct sc_card *card = NULL; @@ -1845,13 +2327,19 @@ struct sc_pkcs15init_pubkeyargs pub_args; struct md_pkcs15_container *cont = NULL; int rv; - DWORD dw, dwret = SCARD_F_INTERNAL_ERROR; + DWORD dwret = SCARD_F_INTERNAL_ERROR; CHAR szGuid[MAX_CONTAINER_NAME_LEN +1] = "Default key label"; if (!pCardData) return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + + if (PinId >= MD_MAX_PINS || !vs->pin_objs[PinId]) + return SCARD_E_INVALID_PARAMETER; + card = vs->p15card->card; memset(&pub_args, 0, sizeof(pub_args)); @@ -1904,12 +2392,7 @@ keygen_args.prkey_args.access_flags = MD_KEY_ACCESS; - dw = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj); - if (dw != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "MdGenerateKey(): cannot get User PIN object"); - return dw; - } - + pin_obj = vs->pin_objs[PinId]; auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data; keygen_args.prkey_args.auth_id = pub_args.auth_id = auth_info->auth_id; @@ -1970,9 +2453,8 @@ return dwret; } - static DWORD -md_pkcs15_store_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, BYTE *blob, DWORD blob_size) +md_pkcs15_store_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, BYTE *blob, DWORD blob_size, PIN_ID PinId) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L VENDOR_SPECIFIC *vs; @@ -1986,13 +2468,19 @@ BYTE *ptr = blob; EVP_PKEY *pkey=NULL; int rv; - DWORD dw, dwret = SCARD_F_INTERNAL_ERROR; + DWORD dwret = SCARD_F_INTERNAL_ERROR; CHAR szGuid[MAX_CONTAINER_NAME_LEN +1] = "Default key label"; if (!pCardData) return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + + if (PinId >= MD_MAX_PINS || !vs->pin_objs[PinId]) + return SCARD_E_INVALID_PARAMETER; + card = vs->p15card->card; pkey = b2i_PrivateKey((const unsigned char **)&ptr, blob_size); @@ -2032,12 +2520,7 @@ prkey_args.access_flags = MD_KEY_ACCESS; - dw = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj); - if (dw != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "MdStoreKey(): cannot get User PIN object"); - return dw; - } - + pin_obj = vs->pin_objs[PinId]; prkey_args.auth_id = ((struct sc_pkcs15_auth_info *) pin_obj->data)->auth_id; rv = sc_lock(card); @@ -2130,6 +2613,9 @@ logprintf(pCardData, 1, "MdStoreCert(): store certificate '%s'\n", file_name); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + card = vs->p15card->card; memset(&args, 0, sizeof(args)); @@ -2199,6 +2685,9 @@ logprintf(pCardData, 1, "md_query_key_sizes: store dwKeySpec '%lu'\n", (unsigned long)dwKeySpec); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + count = vs->p15card->card->algorithm_count; pKeySizes->dwVersion = CARD_KEY_SIZES_CURRENT_VERSION; @@ -2207,7 +2696,7 @@ pKeySizes->dwMaximumBitlen = 0; pKeySizes->dwIncrementalBitlen = 0; - /* dwKeySpec=0 is a special value when the key size is queried without specifing the algorithm. + /* dwKeySpec=0 is a special value when the key size is queried without specifying the algorithm. Used on old minidriver version. In this case, it is RSA */ if ((dwKeySpec == 0) || (dwKeySpec == AT_KEYEXCHANGE) || (dwKeySpec == AT_SIGNATURE)) { for (i = 0; i < count; i++) { @@ -2302,39 +2791,6 @@ return SCARD_S_SUCCESS; } -static VOID CenterWindow(HWND hwndWindow, HWND hwndParent) -{ - RECT rectWindow, rectParent; - int nWidth,nHeight, nScreenWidth, nScreenHeight; - int nX, nY; - GetWindowRect(hwndWindow, &rectWindow); - - nWidth = rectWindow.right - rectWindow.left; - nHeight = rectWindow.bottom - rectWindow.top; - - nScreenWidth = GetSystemMetrics(SM_CXSCREEN); - nScreenHeight = GetSystemMetrics(SM_CYSCREEN); - - // make the window relative to its parent - if (hwndParent != NULL) { - GetWindowRect(hwndParent, &rectParent); - nX = ((rectParent.right - rectParent.left) - nWidth) / 2 + rectParent.left; - nY = ((rectParent.bottom - rectParent.top) - nHeight) / 2 + rectParent.top; - } - else { - nX = (nScreenWidth - nWidth) /2; - nY = (nScreenHeight - nHeight) /2; - } - // make sure that the dialog box never moves outside of the screen - if (nX < 0) nX = 0; - if (nY < 0) nY = 0; - if (nX + nWidth > nScreenWidth) nX = nScreenWidth - nWidth; - if (nY + nHeight > nScreenHeight) nY = nScreenHeight - nHeight; - - MoveWindow(hwndWindow, nX, nY, nWidth, nHeight, TRUE); -} - - static DWORD WINAPI md_dialog_perform_pin_operation_thread(PVOID lpParameter) { @@ -2366,56 +2822,121 @@ rv = (DWORD) ERROR_INVALID_PARAMETER; break; } - if (parameter[9] != 0) { - EndDialog((HWND) parameter[9], rv); + if (parameter[10] != 0) { + EndDialog((HWND) parameter[10], rv); } return (DWORD) rv; } -static INT_PTR CALLBACK md_dialog_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +static const char *md_get_ui_str(PCARD_DATA pCardData, enum ui_str id) { - UNREFERENCED_PARAMETER(wParam); - switch (message) - { - case WM_INITDIALOG: - { - HICON hIcon = NULL; - PCARD_DATA pCardData = (PCARD_DATA) (((LONG_PTR*)lParam)[7]); - VENDOR_SPECIFIC* vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; - /* store parameter like pCardData for further use if needed */ - SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam); - /* change the text shown on the screen */ - if (vs->wszPinContext ) { - SetWindowTextW(GetDlgItem(hWnd, IDC_PINPAD_TEXT), vs->wszPinContext ); - } - CenterWindow(hWnd, vs->hwndParent); - /* load the information icon */ - hIcon = (HICON) LoadImage(0, IDI_INFORMATION, IMAGE_ICON, 0, 0, LR_SHARED); - SendMessage(GetDlgItem(hWnd, IDC_PINPAD_ICON),STM_SETIMAGE,IMAGE_ICON, (LPARAM) hIcon); - /* change the icon */ - hIcon = LoadIcon(g_inst, MAKEINTRESOURCE(IDI_LOGO)); - if (hIcon) + const char *str = md_get_config_str(pCardData, id); + + if (str && *str == '\0') { + /* if the user used an empty string, remove the field by setting it to NULL */ + str = NULL; + } + + return str; +} + +static HRESULT CALLBACK md_dialog_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData) +{ + LONG_PTR param; + + UNREFERENCED_PARAMETER(lParam); + switch (message) { + case TDN_CREATED: { - SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon); - SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + PCARD_DATA pCardData = (PCARD_DATA)((LONG_PTR*)dwRefData)[7]; + DWORD now = timeGetTime(); + + /* remove the icon from the window title */ + SendMessage(hWnd, WM_SETICON, (LPARAM) ICON_BIG, (LONG_PTR) NULL); + SendMessage(hWnd, WM_SETICON, (LPARAM) ICON_SMALL, (LONG_PTR) NULL); + + /* store parameter like pCardData for further use if needed */ + ((LONG_PTR*)dwRefData)[11] = (LONG_PTR) now; + SetWindowLongPtr(hWnd, GWLP_USERDATA, dwRefData); + ((LONG_PTR*)dwRefData)[10] = (LONG_PTR) hWnd; + + if (!md_is_pinpad_dlg_enable_cancel(pCardData)) { + int timeout = md_get_pinpad_dlg_timeout(pCardData); + if (timeout > 0) { + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(0, timeout*1000)); + } + + /* disable "Close" */ + SendMessage(hWnd, TDM_ENABLE_BUTTON, IDCLOSE, 0); + + /* launch the function in another thread context store the thread handle */ + ((LONG_PTR*)dwRefData)[9] = (LONG_PTR) CreateThread(NULL, 0, md_dialog_perform_pin_operation_thread, (LPVOID) dwRefData, 0, NULL); + } else { + int timeout = md_get_pinpad_dlg_timeout(pCardData); + if (timeout > 0) { + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, 0); + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_STATE, PBST_PAUSED, 0); + } + } + } + return S_OK; + + case TDN_TIMER: + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_POS, wParam, 0L); + return S_OK; + + case TDN_BUTTON_CLICKED: + switch(LOWORD(wParam)) { + case IDCANCEL: + DestroyWindow(hWnd); + break; + + case IDOK: + param = GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (param) { + PCARD_DATA pCardData = (PCARD_DATA)((LONG_PTR*)param)[7]; + VENDOR_SPECIFIC* vs = (VENDOR_SPECIFIC*) pCardData->pvVendorSpecific; + + int timeout = md_get_pinpad_dlg_timeout(pCardData); + if (timeout > 0) { + DWORD start = (DWORD)((LONG_PTR*)dwRefData)[11]; + DWORD delta = timeGetTime() - start; + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(delta, delta + timeout*1000)); + SendMessage(hWnd, TDM_SET_PROGRESS_BAR_STATE, PBST_NORMAL, 0); + } + + /* disable "OK" and "Cancel" */ + SendMessage(hWnd, TDM_ENABLE_BUTTON, IDOK, 0); + SendMessage(hWnd, TDM_ENABLE_BUTTON, IDCANCEL, 0); + + /* disable "x" */ + HMENU menu = GetSystemMenu(hWnd, FALSE); + if (menu) { + EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED); + } + + /* launch the function in another thread context store the thread handle */ + ((LONG_PTR*)dwRefData)[9] = (LONG_PTR) CreateThread(NULL, 0, md_dialog_perform_pin_operation_thread, (LPVOID) dwRefData, 0, NULL); + } + break; + + default: + return S_FALSE; } - /* launch the function in another thread context store the thread handle */ - ((LONG_PTR*)lParam)[9] = (LONG_PTR) hWnd; - ((LONG_PTR*)lParam)[8] = (LONG_PTR) CreateThread(NULL, 0, md_dialog_perform_pin_operation_thread, (PVOID) lParam, 0, NULL); - } - return TRUE; - case WM_DESTROY: - { + break; + + case TDN_DESTROYED: /* clean resources used */ - LPARAM param = GetWindowLongPtr(hWnd, GWLP_USERDATA); + param = GetWindowLongPtr(hWnd, GWLP_USERDATA); if (param) { - HANDLE hThread = (HANDLE)((LONG_PTR*)param)[8]; + HANDLE hThread = (HANDLE)((LONG_PTR*)param)[9]; CloseHandle(hThread); } - } - break; + break; } - return FALSE; + + /* don't close the Task Dialog */ + return S_FALSE; } @@ -2424,12 +2945,16 @@ md_dialog_perform_pin_operation(PCARD_DATA pCardData, int operation, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const u8 *pin1, size_t pin1len, - const u8 *pin2, size_t *pin2len, BOOL displayUI) + const u8 *pin2, size_t *pin2len, BOOL displayUI, DWORD role) { - LONG_PTR parameter[10]; + LONG_PTR parameter[12]; INT_PTR result = 0; + HWND hWndDlg = 0; + TASKDIALOGCONFIG tc = {0}; int rv = 0; + BOOL checked, user_checked; VENDOR_SPECIFIC* pv = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + /* stack the parameters */ parameter[0] = (LONG_PTR)operation; parameter[1] = (LONG_PTR)p15card; @@ -2439,18 +2964,119 @@ parameter[5] = (LONG_PTR)pin2; parameter[6] = (LONG_PTR)pin2len; parameter[7] = (LONG_PTR)pCardData; - parameter[8] = 0; /* place holder for thread handle */ - parameter[9] = 0; /* place holder for window handle */ + parameter[8] = (LONG_PTR)role; + parameter[9] = 0; /* place holder for thread handle */ + parameter[10] = 0; /* place holder for window handle */ + parameter[11] = 0; /* place holder for end of timer */ + /* launch the function to perform in the same thread context */ if (!displayUI) { rv = md_dialog_perform_pin_operation_thread(parameter); SecureZeroMemory(parameter, sizeof(parameter)); return rv; } + /* launch the UI in the same thread context than the parent and the function to perform in another thread context this is the only way to display a modal dialog attached to a parent (hwndParent != 0) */ - result = DialogBoxParam(g_inst, MAKEINTRESOURCE(IDD_PINPAD), pv->hwndParent, md_dialog_proc, (LPARAM) parameter); + tc.hwndParent = pv->hwndParent; + tc.hInstance = g_inst; + + tc.pszWindowTitle = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_TITLE)); + tc.pszMainInstruction = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_MAIN)); + tc.pszExpandedControlText = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_CONTROL_EXPANDED)); + tc.pszCollapsedControlText = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_CONTROL_COLLAPSED)); + tc.pszExpandedInformation = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_EXPANDED)); + tc.pszVerificationText = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_VERIFICATION)); + switch (role) { + case ROLE_ADMIN: + tc.pszContent = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_CONTENT_ADMIN)); + break; + case MD_ROLE_USER_SIGN: + tc.pszContent = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_CONTENT_USER_SIGN)); + break; + case ROLE_USER: + default: + tc.pszContent = wchar_from_char_str(md_get_ui_str(pCardData, + MD_PINPAD_DLG_CONTENT_USER)); + break; + } + + if (pv->wszPinContext) { + /* overwrite the main instruction with the application's information if + * possible */ + tc.pszMainInstruction = pv->wszPinContext; + } + + tc.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; + if (tc.pszExpandedInformation != NULL) { + tc.dwFlags |= TDF_EXPAND_FOOTER_AREA; + } + if (md_get_pinpad_dlg_timeout(pCardData) > 0) { + tc.dwFlags |= TDF_SHOW_PROGRESS_BAR | TDF_CALLBACK_TIMER; + } + + checked = !md_is_pinpad_dlg_enable_cancel(pCardData); + if (checked) { + tc.dwFlags |= TDF_VERIFICATION_FLAG_CHECKED; + /* can't use TDCBF_CANCEL_BUTTON since this would implicitly set TDF_ALLOW_DIALOG_CANCELLATION */ + tc.dwCommonButtons = TDCBF_CLOSE_BUTTON; + } else { + tc.dwFlags |= TDF_ALLOW_DIALOG_CANCELLATION; + tc.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_OK_BUTTON; + } + + tc.hMainIcon = md_get_pinpad_dlg_icon(pCardData); + if (tc.hMainIcon) { + tc.dwFlags |= TDF_USE_HICON_MAIN; + } else { + tc.pszMainIcon = MAKEINTRESOURCEW(IDI_SMARTCARD); + } + tc.pfCallback = md_dialog_proc; + tc.lpCallbackData = (LONG_PTR)parameter; + tc.cbSize = sizeof(tc); + + result = TaskDialogIndirect(&tc, NULL, NULL, &user_checked); + + if (user_checked != checked) { + TCHAR path[MAX_PATH]={0}; + if (GetModuleFileName(NULL, path, ARRAYSIZE(path))) { + HKEY hKey; + LSTATUS lstatus = RegOpenKeyExA(HKEY_CURRENT_USER, + SUBKEY_ENABLE_CANCEL, 0, KEY_WRITE, &hKey); + if (ERROR_SUCCESS != lstatus) { + lstatus = RegCreateKeyExA(HKEY_CURRENT_USER, + SUBKEY_ENABLE_CANCEL, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_WRITE, NULL, &hKey, NULL); + } + if (ERROR_SUCCESS == lstatus) { + DWORD enable_cancel = 0; + if (user_checked == FALSE) { + enable_cancel = 1; + } + lstatus = RegSetValueEx(hKey, path, 0, REG_DWORD, + (const BYTE*)&enable_cancel, sizeof(enable_cancel)); + RegCloseKey(hKey); + } + } + } + + LocalFree((WCHAR *) tc.pszWindowTitle); + LocalFree((WCHAR *) tc.pszMainInstruction); + LocalFree((WCHAR *) tc.pszExpandedControlText); + LocalFree((WCHAR *) tc.pszCollapsedControlText); + LocalFree((WCHAR *) tc.pszExpandedInformation); + LocalFree((WCHAR *) tc.pszContent); + SecureZeroMemory(parameter, sizeof(parameter)); + return (int) result; } @@ -2522,9 +3148,7 @@ DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) { VENDOR_SPECIFIC *vs = NULL; - - if (md_static_data.attach_check != MD_STATIC_PROCESS_ATTACHED) - return SCARD_S_SUCCESS; + CRITICAL_SECTION hScard_lock; if(!pCardData) return SCARD_E_INVALID_PARAMETER; @@ -2540,21 +3164,26 @@ if(!vs) return SCARD_E_INVALID_PARAMETER; + hScard_lock = vs->hScard_lock; + EnterCriticalSection(&hScard_lock); + disassociate_card(pCardData); + md_fs_finalize(pCardData); if(vs->ctx) { logprintf(pCardData, 6, "release context\n"); sc_release_context(vs->ctx); - md_static_data.flags |= MD_STATIC_FLAG_CONTEXT_DELETED; vs->ctx = NULL; } logprintf(pCardData, 1, "**********************************************************************\n"); - md_fs_finalize(pCardData); pCardData->pfnCspFree(pCardData->pvVendorSpecific); pCardData->pvVendorSpecific = NULL; + LeaveCriticalSection(&hScard_lock); + DeleteCriticalSection(&hScard_lock); + return SCARD_S_SUCCESS; } @@ -2568,16 +3197,23 @@ (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "pCardCapabilities=%p\n", pCardCapabilities); - if (!pCardData || !pCardCapabilities) + if (!pCardData || !pCardCapabilities || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; + dwret = check_card_status(pCardData, "CardQueryCapabilities"); + if (dwret != SCARD_S_SUCCESS) { + goto err; + } + dwret = md_card_capabilities(pCardData, pCardCapabilities); - if (dwret != SCARD_S_SUCCESS) - return dwret; + if (dwret != SCARD_S_SUCCESS) { + goto err; + } - check_reader_status(pCardData); +err: + unlock(pCardData); - return SCARD_S_SUCCESS; + return dwret; } DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData, @@ -2593,61 +3229,95 @@ logprintf(pCardData, 1, "CardDeleteContainer(idx:%u)\n", (unsigned int)bContainerIndex); - if (!pCardData) + if (!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; - if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_INVALID_PARAMETER; + dwret = check_card_reader_status(pCardData, "CardDeleteContainer"); + if (dwret != SCARD_S_SUCCESS) { + goto err; + } + + if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } if (!md_is_supports_container_key_gen(pCardData)) { logprintf(pCardData, 1, "Denied 'deletion' mechanism to delete container.\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - if(!vs) - return SCARD_E_INVALID_PARAMETER; + if(!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } cont = &(vs->p15_containers[bContainerIndex]); dwret = md_pkcs15_delete_object(pCardData, cont->prkey_obj); - if (dwret != SCARD_S_SUCCESS) { + if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "private key deletion failed\n"); - return dwret; + goto err; } dwret = md_pkcs15_delete_object(pCardData, cont->pubkey_obj); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "public key deletion failed\n"); - return dwret; + goto err; } ZeroMemory(cont, sizeof(struct md_pkcs15_container)); logprintf(pCardData, 1, "key deleted\n"); - return SCARD_S_SUCCESS; -} +err: + unlock(pCardData); -DWORD WINAPI CardCreateContainer(__in PCARD_DATA pCardData, - __in BYTE bContainerIndex, - __in DWORD dwFlags, - __in DWORD dwKeySpec, - __in DWORD dwKeySize, - __in PBYTE pbKeyData) + return dwret; +} + +/** The CardCreateContainerEx function creates a new key container that the +container index identifies and the bContainerIndex parameter specifies. The function +associates the key container with the PIN that the PinId parameter specified. +This function is useful if the card-edge does not allow for changing the key attributes +after the key container is created. This function replaces the need to call +CardSetContainerProperty to set the CCP_PIN_IDENTIFIER property CardCreateContainer +is called. +The caller of this function can provide the key material that the card imports. +This is useful in those situations in which the card either does not support internal +key generation or the caller requests that the key be archived in the card.*/ +DWORD WINAPI CardCreateContainerEx(__in PCARD_DATA pCardData, + __in BYTE bContainerIndex, + __in DWORD dwFlags, + __in DWORD dwKeySpec, + __in DWORD dwKeySize, + __in PBYTE pbKeyData, + __in PIN_ID PinId) { DWORD dwret; - if (!pCardData) + if (!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; + if (PinId == ROLE_ADMIN) { + dwret = SCARD_W_SECURITY_VIOLATION; + goto err; + } + + dwret = check_card_reader_status(pCardData, "CardCreateContainerEx"); + if (dwret != SCARD_S_SUCCESS) + goto err; + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, - "CardCreateContainerEx(idx:%u,flags:%lX,type:%lX,size:%lu,data:%p)\n", + "CardCreateContainerEx(idx:%u,flags:%lX,type:%lX,size:%lu,data:%p,pin:%u)\n", (unsigned int)bContainerIndex, (unsigned long)dwFlags, - (unsigned long)dwKeySpec, (unsigned long)dwKeySize, pbKeyData); + (unsigned long)dwKeySpec, (unsigned long)dwKeySize, pbKeyData, + (unsigned int)PinId); if (pbKeyData) { logprintf(pCardData, 7, "Key data\n"); @@ -2657,7 +3327,7 @@ dwret = md_check_key_compatibility(pCardData, dwFlags, dwKeySpec, dwKeySize, pbKeyData); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "check key compatibility failed\n"); - return dwret; + goto err; } if (!md_is_supports_container_key_gen(pCardData)) { @@ -2672,34 +3342,50 @@ if (!dwFlags) { logprintf(pCardData, 1, "Unsupported create container mechanism.\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } if (dwFlags & CARD_CREATE_CONTAINER_KEY_GEN) { - dwret = md_pkcs15_generate_key(pCardData, bContainerIndex, dwKeySpec, dwKeySize); + dwret = md_pkcs15_generate_key(pCardData, bContainerIndex, dwKeySpec, dwKeySize, PinId); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "key generation failed\n"); - return dwret; + goto err; } logprintf(pCardData, 1, "key generated\n"); } else if ((dwFlags & CARD_CREATE_CONTAINER_KEY_IMPORT) && (pbKeyData != NULL)) { - dwret = md_pkcs15_store_key(pCardData, bContainerIndex, dwKeySpec, pbKeyData, dwKeySize); + dwret = md_pkcs15_store_key(pCardData, bContainerIndex, dwKeySpec, pbKeyData, dwKeySize, PinId); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "key store failed\n"); - return dwret; + goto err; } logprintf(pCardData, 1, "key imported\n"); } else { logprintf(pCardData, 1, "Invalid dwFlags value: 0x%lX\n", (unsigned long)dwFlags); - return SCARD_E_INVALID_PARAMETER; + dwret = SCARD_E_INVALID_PARAMETER; + goto err; } - return SCARD_S_SUCCESS; +err: + unlock(pCardData); + + return dwret; } +DWORD WINAPI CardCreateContainer(__in PCARD_DATA pCardData, + __in BYTE bContainerIndex, + __in DWORD dwFlags, + __in DWORD dwKeySpec, + __in DWORD dwKeySize, + __in PBYTE pbKeyData) +{ + return CardCreateContainerEx(pCardData, bContainerIndex, dwFlags, + dwKeySpec, dwKeySize, pbKeyData, + ROLE_USER); +} typedef struct { PUBLICKEYSTRUC publickeystruc; @@ -2711,17 +3397,23 @@ { VENDOR_SPECIFIC *vs = NULL; DWORD sz = 0; - DWORD ret = SCARD_F_UNKNOWN_ERROR; + DWORD ret; struct md_pkcs15_container *cont = NULL; struct sc_pkcs15_der pubkey_der; struct sc_pkcs15_prkey_info *prkey_info = NULL; int rv; + pubkey_der.value = NULL; + pubkey_der.len = 0; if(!pCardData) return SCARD_E_INVALID_PARAMETER; - if (!pContainerInfo) + if (!pContainerInfo || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; + ret = check_card_reader_status(pCardData, "CardGetContainerInfo"); + if (ret != SCARD_S_SUCCESS) + goto err; + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -2732,34 +3424,39 @@ (unsigned long)pContainerInfo->cbSigPublicKey, (unsigned long)pContainerInfo->cbKeyExPublicKey); - if (dwFlags) - return SCARD_E_INVALID_PARAMETER; - if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_NO_KEY_CONTAINER; - if (pContainerInfo->dwVersion > CONTAINER_INFO_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + if (dwFlags) { + ret = SCARD_E_INVALID_PARAMETER; + goto err; + } + if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) { + ret = SCARD_E_NO_KEY_CONTAINER; + goto err; + } + if (pContainerInfo->dwVersion > CONTAINER_INFO_CURRENT_VERSION) { + ret = ERROR_REVISION_MISMATCH; + goto err; + } pContainerInfo->dwVersion = CONTAINER_INFO_CURRENT_VERSION; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + ret = SCARD_E_INVALID_PARAMETER; + goto err; + } + cont = &vs->p15_containers[bContainerIndex]; if (!cont->prkey_obj) { logprintf(pCardData, 7, "Container %u is empty\n", (unsigned int)bContainerIndex); - return SCARD_E_NO_KEY_CONTAINER; - } - - if (vs->p15card == NULL) { - return SCARD_F_INTERNAL_ERROR; + ret = SCARD_E_NO_KEY_CONTAINER; + goto err; } + ret = SCARD_F_UNKNOWN_ERROR; prkey_info = (struct sc_pkcs15_prkey_info *)cont->prkey_obj->data; - check_reader_status(pCardData); - pubkey_der.value = NULL; - pubkey_der.len = 0; - if ((cont->prkey_obj->content.value != NULL) && (cont->prkey_obj->content.len > 0)) { sc_der_copy(&pubkey_der, &cont->prkey_obj->content); ret = SCARD_S_SUCCESS; @@ -2817,14 +3514,15 @@ if (!pubkey_der.value && (cont->size_sign || cont->size_key_exchange)) { logprintf(pCardData, 2, "cannot find public key\n"); - return SCARD_F_INTERNAL_ERROR; + ret = SCARD_F_INTERNAL_ERROR; + goto err; } if (ret != SCARD_S_SUCCESS) { logprintf(pCardData, 7, "GetContainerInfo(idx:%u) failed; error %lX", (unsigned int)bContainerIndex, (unsigned long)ret); - return ret; + goto err; } logprintf(pCardData, 7, "SubjectPublicKeyInfo:\n"); @@ -2839,8 +3537,10 @@ if (cont->size_sign) { PUBRSAKEYSTRUCT_BASE *publicKey = (PUBRSAKEYSTRUCT_BASE *)pCardData->pfnCspAlloc(sz); - if (!publicKey) - return SCARD_E_NO_MEMORY; + if (!publicKey) { + ret = SCARD_E_NO_MEMORY; + goto err; + } CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pubkey_der.value, (DWORD) pubkey_der.len, 0, publicKey, &sz); @@ -2856,8 +3556,10 @@ if (cont->size_key_exchange) { PUBRSAKEYSTRUCT_BASE *publicKey = (PUBRSAKEYSTRUCT_BASE*)pCardData->pfnCspAlloc(sz); - if (!publicKey) - return SCARD_E_NO_MEMORY; + if (!publicKey) { + ret = SCARD_E_NO_MEMORY; + goto err; + } CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pubkey_der.value, (DWORD) pubkey_der.len, 0, publicKey, &sz); @@ -2895,12 +3597,15 @@ logprintf(pCardData, 3, "Unable to match the ECC public size to one of Microsoft algorithm %"SC_FORMAT_LEN_SIZE_T"u\n", cont->size_sign); - return SCARD_F_INTERNAL_ERROR; + ret = SCARD_F_INTERNAL_ERROR; + goto err; } publicKey = (BCRYPT_ECCKEY_BLOB *)pCardData->pfnCspAlloc(sz); - if (!publicKey) - return SCARD_E_NO_MEMORY; + if (!publicKey) { + ret = SCARD_E_NO_MEMORY; + goto err; + } publicKey->cbKey = (DWORD)(pubkey_der.len -3) /2; publicKey->dwMagic = dwMagic; @@ -2931,12 +3636,15 @@ logprintf(pCardData, 3, "Unable to match the ECC public size to one of Microsoft algorithm %"SC_FORMAT_LEN_SIZE_T"u\n", cont->size_key_exchange); - return SCARD_F_INTERNAL_ERROR; + ret = SCARD_F_INTERNAL_ERROR; + goto err; } publicKey = (BCRYPT_ECCKEY_BLOB *)pCardData->pfnCspAlloc(sz); - if (!publicKey) - return SCARD_E_NO_MEMORY; + if (!publicKey) { + ret = SCARD_E_NO_MEMORY; + goto err; + } publicKey->cbKey = (DWORD)(pubkey_der.len -3) /2; publicKey->dwMagic = dwMagic; @@ -2951,10 +3659,14 @@ } } } - logprintf(pCardData, 7, "returns container(idx:%u) info", (unsigned int)bContainerIndex); - return SCARD_S_SUCCESS; + +err: + free(pubkey_der.value); + unlock(pCardData); + + return ret; } DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData, @@ -2991,6 +3703,7 @@ __out PDWORD pcbChallengeData) { VENDOR_SPECIFIC *vs; + DWORD dwret; int rv; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", @@ -3000,31 +3713,45 @@ if(!pCardData) return SCARD_E_INVALID_PARAMETER; - if (!ppbChallengeData || !pcbChallengeData) + if (!ppbChallengeData || !pcbChallengeData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + dwret = check_card_reader_status(pCardData, "CardGetChallenge"); + if (dwret != SCARD_S_SUCCESS) { + goto err; + } - check_reader_status(pCardData); + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } *pcbChallengeData = 8; *ppbChallengeData = (PBYTE) pCardData->pfnCspAlloc(8); - if (!*ppbChallengeData) - return SCARD_E_NO_MEMORY; + if (!*ppbChallengeData) { + dwret = SCARD_E_NO_MEMORY; + goto err; + } rv = sc_get_challenge(vs->p15card->card, *ppbChallengeData, 8); - if (rv) { + if (rv < 0) { logprintf(pCardData, 1, "Get challenge failed: %s\n", sc_strerror(rv)); pCardData->pfnCspFree(*ppbChallengeData); *ppbChallengeData = NULL; - return SCARD_E_UNEXPECTED; + dwret = SCARD_E_UNEXPECTED; + goto err; } + dwret = SCARD_S_SUCCESS; logprintf(pCardData, 7, "returns %lu bytes:\n", (unsigned long)*pcbChallengeData); loghex(pCardData, 7, *ppbChallengeData, *pcbChallengeData); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } @@ -3050,7 +3777,9 @@ __in DWORD cRetryCount, __in DWORD dwFlags) { - if(!pCardData) + DWORD r = SCARD_S_SUCCESS; + + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", @@ -3060,43 +3789,52 @@ if (pwszUserId == NULL) { logprintf(pCardData, 1, "no user ID\n"); - return SCARD_E_INVALID_PARAMETER; + r = SCARD_E_INVALID_PARAMETER; + goto err; } if (wcscmp(wszCARD_USER_USER, pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN,pwszUserId) != 0) { logprintf(pCardData, 1, "unknown user ID %S\n", pwszUserId); - return SCARD_E_INVALID_PARAMETER; + r = SCARD_E_INVALID_PARAMETER; + goto err; } if (wcscmp(wszCARD_USER_ADMIN, pwszUserId) == 0) { logprintf(pCardData, 1, "unlocking admin not supported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + r = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } if (dwFlags & CARD_AUTHENTICATE_PIN_CHALLENGE_RESPONSE) { logprintf(pCardData, 1, - "challenge / response not supported, we'll treat response as a PUK\n"); + "challenge / response not supported, we'll treat response as a PUK\n"); logprintf(pCardData, 1, - "note that you'll need to type PUK in hex (replace every PUK digit X with '3X') in Win CAD unblock dialog response field\n"); + "note that you'll need to type PUK in hex (replace every PUK digit X with '3X') in Win CAD unblock dialog response field\n"); dwFlags &= ~CARD_AUTHENTICATE_PIN_CHALLENGE_RESPONSE; } if (dwFlags) { logprintf(pCardData, 1, "flags of %x not supported\n", - (unsigned int)dwFlags); - return SCARD_E_INVALID_PARAMETER; + (unsigned int)dwFlags); + r = SCARD_E_INVALID_PARAMETER; + goto err; } logprintf(pCardData, 1, - "UserID('%S'), AuthData(%p, %lu), NewPIN(%p, %lu), Retry(%lu), dwFlags(0x%lX)\n", - pwszUserId, pbAuthenticationData, - (unsigned long)cbAuthenticationData, pbNewPinData, - (unsigned long)cbNewPinData, (unsigned long)cRetryCount, - (unsigned long)dwFlags); + "UserID('%S'), AuthData(%p, %lu), NewPIN(%p, %lu), Retry(%lu), dwFlags(0x%lX)\n", + pwszUserId, pbAuthenticationData, + (unsigned long)cbAuthenticationData, pbNewPinData, + (unsigned long)cbNewPinData, (unsigned long)cRetryCount, + (unsigned long)dwFlags); + + r = CardChangeAuthenticatorEx(pCardData, + PIN_CHANGE_FLAG_UNBLOCK | + CARD_PIN_SILENT_CONTEXT, + ROLE_ADMIN, pbAuthenticationData, + cbAuthenticationData, ROLE_USER, + pbNewPinData, cbNewPinData, + cRetryCount, NULL); - return CardChangeAuthenticatorEx(pCardData, - PIN_CHANGE_FLAG_UNBLOCK | - CARD_PIN_SILENT_CONTEXT, - ROLE_ADMIN, pbAuthenticationData, - cbAuthenticationData, ROLE_USER, - pbNewPinData, cbNewPinData, - cRetryCount, NULL); +err: + unlock(pCardData); + + return r; } @@ -3110,78 +3848,106 @@ __in DWORD dwFlags, __out_opt PDWORD pcAttemptsRemaining) { + DWORD r = SCARD_S_SUCCESS; PIN_ID pinid; - if(!pCardData) + + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", - (unsigned long)GetCurrentProcessId(), - (unsigned long)GetCurrentThreadId(), pCardData); + (unsigned long)GetCurrentProcessId(), + (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardChangeAuthenticator\n"); - if (pwszUserId == NULL) - return SCARD_E_INVALID_PARAMETER; + if (pwszUserId == NULL) { + r = SCARD_E_INVALID_PARAMETER; + goto err; + } if (dwFlags == CARD_AUTHENTICATE_PIN_CHALLENGE_RESPONSE) { logprintf(pCardData, 1, "Other then 'authentication' the PIN are not supported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + r = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } else if (dwFlags != CARD_AUTHENTICATE_PIN_PIN){ - return SCARD_E_INVALID_PARAMETER; + r = SCARD_E_INVALID_PARAMETER; + goto err; } - if (wcscmp(wszCARD_USER_USER, pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN, pwszUserId) != 0) - return SCARD_E_INVALID_PARAMETER; + if (wcscmp(wszCARD_USER_USER, pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN, pwszUserId) != 0) { + r = SCARD_E_INVALID_PARAMETER; + goto err; + } logprintf(pCardData, 1, - "UserID('%S'), CurrentPIN(%p, %lu), NewPIN(%p, %lu), Retry(%lu), dwFlags(0x%lX)\n", - pwszUserId, pbCurrentAuthenticator, - (unsigned long)cbCurrentAuthenticator, pbNewAuthenticator, - (unsigned long)cbNewAuthenticator, (unsigned long)cRetryCount, - (unsigned long)dwFlags); + "UserID('%S'), CurrentPIN(%p, %lu), NewPIN(%p, %lu), Retry(%lu), dwFlags(0x%lX)\n", + pwszUserId, pbCurrentAuthenticator, + (unsigned long)cbCurrentAuthenticator, pbNewAuthenticator, + (unsigned long)cbNewAuthenticator, (unsigned long)cRetryCount, + (unsigned long)dwFlags); if (wcscmp(wszCARD_USER_USER, pwszUserId) == 0) pinid = ROLE_USER; else pinid = ROLE_ADMIN; - return CardChangeAuthenticatorEx(pCardData, PIN_CHANGE_FLAG_CHANGEPIN | - CARD_PIN_SILENT_CONTEXT, pinid, - pbCurrentAuthenticator, - cbCurrentAuthenticator, pinid, - pbNewAuthenticator, cbNewAuthenticator, - cRetryCount, pcAttemptsRemaining); + r = CardChangeAuthenticatorEx(pCardData, PIN_CHANGE_FLAG_CHANGEPIN | + CARD_PIN_SILENT_CONTEXT, pinid, + pbCurrentAuthenticator, + cbCurrentAuthenticator, pinid, + pbNewAuthenticator, cbNewAuthenticator, + cRetryCount, pcAttemptsRemaining); + +err: + unlock(pCardData); + return r; } -/* this function is not called on purpose. -If a deauthentication is not possible, it should be set to NULL in CardAcquireContext. -Because this function do nothing - it is not called. -Note: the PIN freshnesh will be managed by the Base CSP*/ +/* Note: the PIN freshness will be managed by the Base CSP */ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, __in LPWSTR pwszUserId, __in DWORD dwFlags) { + DWORD dwret; VENDOR_SPECIFIC* vs = NULL; int rv; + logprintf(pCardData, 1, "\nP:%ld T:%ld pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeauthenticate(%S) %lu\n", NULLWSTR(pwszUserId), (unsigned long)dwFlags); - if(!pCardData) + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; + dwret = check_card_reader_status(pCardData, "CardDeauthenticate"); + if (dwret != SCARD_S_SUCCESS) + goto err; + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } sc_pkcs15_pincache_clear(vs->p15card); rv = sc_logout(vs->p15card->card); - if (rv != SC_SUCCESS) - return SCARD_E_UNSUPPORTED_FEATURE; - /* force a reset of a card - SCARD_S_SUCCESS do not lead to the reset of the card and leave it still authenticated */ - return SCARD_S_SUCCESS; + if (rv != SC_SUCCESS) { + /* force a reset of a card - SCARD_S_SUCCESS do not lead to the reset + * of the card and leave it still authenticated */ + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; + } + + dwret = SCARD_S_SUCCESS; + +err: + unlock(pCardData); + + return dwret; } DWORD WINAPI CardCreateDirectory(__in PCARD_DATA pCardData, @@ -3222,17 +3988,27 @@ NULLSTR(pszDirectoryName), NULLSTR(pszFileName), (unsigned long)cbInitialCreationSize, AccessCondition); + if (!lock(pCardData)) + return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_status(pCardData, "CardCreateFile"); + if (dwret != SCARD_S_SUCCESS) + goto err; + dwret = md_fs_find_directory(pCardData, NULL, pszDirectoryName, &dir); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "CardCreateFile() cannot find parent directory '%s'", NULLSTR(pszDirectoryName)); - return dwret; + goto err; } dwret = md_fs_add_file(pCardData, &dir->files, pszFileName, AccessCondition, NULL, cbInitialCreationSize, NULL); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto err; - return SCARD_S_SUCCESS; +err: + unlock(pCardData); + + return dwret; } @@ -3244,13 +4020,14 @@ __out PDWORD pcbData) { struct md_file *file = NULL; + DWORD dwret; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardReadFile\n"); - if(!pCardData) + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 2, @@ -3258,31 +4035,34 @@ NULLSTR(pszDirectoryName), NULLSTR(pszFileName), (unsigned long)dwFlags, pcbData, ppbData); - if (!pszFileName || !strlen(pszFileName)) - return SCARD_E_INVALID_PARAMETER; - if (dwFlags) - return SCARD_E_INVALID_PARAMETER; + if (!pszFileName || !strlen(pszFileName) || dwFlags) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } - check_reader_status(pCardData); + dwret = check_card_reader_status(pCardData, "CardReadFile"); + if (dwret != SCARD_S_SUCCESS) + goto err; md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file); if (!file) { logprintf(pCardData, 2, "CardReadFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName)); - return SCARD_E_FILE_NOT_FOUND; + dwret = SCARD_E_FILE_NOT_FOUND; + goto err; } if (!file->blob) { - DWORD dwret; - dwret = md_fs_read_content(pCardData, pszDirectoryName, file); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto err; } if (ppbData) { *ppbData = pCardData->pfnCspAlloc(file->size); - if(!*ppbData) - return SCARD_E_NO_MEMORY; + if(!*ppbData) { + dwret = SCARD_E_NO_MEMORY; + goto err; + } memcpy(*ppbData, file->blob, file->size); } @@ -3292,7 +4072,11 @@ logprintf(pCardData, 7, "returns '%s' content:\n", NULLSTR(pszFileName)); loghex(pCardData, 7, file->blob, file->size); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + + return dwret; } @@ -3306,7 +4090,7 @@ struct md_file *file = NULL; DWORD dwret; - if(!pCardData) + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", @@ -3314,7 +4098,9 @@ (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardWriteFile() dirName:'%s', fileName:'%s' \n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName)); - check_reader_status(pCardData); + dwret = check_card_reader_status(pCardData, "CardWriteFile"); + if (dwret != SCARD_S_SUCCESS) + goto err; if (pbData && cbData) { logprintf(pCardData, 1, "CardWriteFile try to write (%lu):\n", @@ -3325,7 +4111,8 @@ md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file); if (!file) { logprintf(pCardData, 2, "CardWriteFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName)); - return SCARD_E_FILE_NOT_FOUND; + dwret = SCARD_E_FILE_NOT_FOUND; + goto err; } logprintf(pCardData, 7, "set content of '%s' to:\n", NULLSTR(pszFileName)); @@ -3335,20 +4122,23 @@ if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "cannot set file content: %lu\n", (unsigned long)dwret); - return dwret; + goto err; } if (pszDirectoryName && !strcmp(pszDirectoryName, "mscp")) { if ((strstr(pszFileName, "kxc") == pszFileName) || (strstr(pszFileName, "ksc") == pszFileName)) { dwret = md_pkcs15_store_certificate(pCardData, pszFileName, pbData, cbData); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto err; logprintf(pCardData, 2, "md_pkcs15_store_certificate() OK\n"); } } logprintf(pCardData, 2, "write '%s' ok.\n", NULLSTR(pszFileName)); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, @@ -3363,20 +4153,24 @@ (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeleteFile(%s, %s) called\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName)); - if(!pCardData) + if(!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; - check_reader_status(pCardData); + dwret = check_card_reader_status(pCardData, "CardDeleteFile"); + if (dwret != SCARD_S_SUCCESS) + goto err; dwret = md_fs_delete_file(pCardData, pszDirectoryName, pszFileName); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 2, "CardDeleteFile(): delete file error: %lX\n", (unsigned long)dwret); - return dwret; + goto err; } - return SCARD_S_SUCCESS; +err: + unlock(pCardData); + return dwret; } @@ -3387,6 +4181,7 @@ __in DWORD dwFlags) { VENDOR_SPECIFIC *vs = NULL; + DWORD dwret; char mstr[0x100]; struct md_directory *dir = NULL; struct md_file *file = NULL; @@ -3397,18 +4192,25 @@ (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardEnumFiles() directory '%s'\n", NULLSTR(pszDirectoryName)); - if (!pCardData) - return SCARD_E_INVALID_PARAMETER; - if (!pmszFileNames || !pdwcbFileName) + if (!pCardData || !pmszFileNames || !pdwcbFileName || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; if (dwFlags) { logprintf(pCardData, 1, "CardEnumFiles() dwFlags not 'zero' -- %lX\n", (unsigned long)dwFlags); - return SCARD_E_INVALID_PARAMETER; + dwret = SCARD_E_INVALID_PARAMETER; + goto err; } + dwret = check_card_status(pCardData, "CardEnumFiles"); + if (dwret != SCARD_S_SUCCESS) + goto err; + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } memset(mstr, 0, sizeof(mstr)); @@ -3418,7 +4220,8 @@ md_fs_find_directory(pCardData, NULL, pszDirectoryName, &dir); if (!dir) { logprintf(pCardData, 2, "enum files() failed: directory '%s' not found\n", NULLSTR(pszDirectoryName)); - return SCARD_E_FILE_NOT_FOUND; + dwret = SCARD_E_FILE_NOT_FOUND; + goto err; } file = dir->files; @@ -3432,12 +4235,17 @@ offs += 1; *pmszFileNames = (LPSTR)(*pCardData->pfnCspAlloc)(offs); - if (*pmszFileNames == NULL) - return SCARD_E_NO_MEMORY; + if (*pmszFileNames == NULL) { + dwret = SCARD_E_NO_MEMORY; + goto err; + } CopyMemory(*pmszFileNames, mstr, offs); *pdwcbFileName = (DWORD) offs; - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } @@ -3446,24 +4254,35 @@ __in LPSTR pszFileName, __inout PCARD_FILE_INFO pCardFileInfo) { + DWORD dwret; struct md_file *file = NULL; + if(!pCardData || !lock(pCardData)) + return SCARD_E_INVALID_PARAMETER; + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetFileInfo(dirName:'%s',fileName:'%s', out %p)\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName), pCardFileInfo); + dwret = check_card_status(pCardData, "CardGetFileInfo"); + if (dwret != SCARD_S_SUCCESS) + goto err; + md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file); if (!file) { logprintf(pCardData, 2, "CardWriteFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName)); - return SCARD_E_FILE_NOT_FOUND; + dwret = SCARD_E_FILE_NOT_FOUND; + goto err; } pCardFileInfo->dwVersion = CARD_FILE_INFO_CURRENT_VERSION; pCardFileInfo->cbFileSize = (DWORD) file->size; pCardFileInfo->AccessCondition = file->acl; - return SCARD_S_SUCCESS; +err: + unlock(pCardData); + return dwret; } @@ -3480,20 +4299,25 @@ pCardFreeSpaceInfo, (unsigned long)dwFlags, (unsigned long)pCardFreeSpaceInfo->dwVersion); - if (!pCardData) + if (!pCardData || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; - check_reader_status(pCardData); + dwret = check_card_status(pCardData, "CardQueryFreeSpace"); + if (dwret != SCARD_S_SUCCESS) + goto err; dwret = md_free_space(pCardData, pCardFreeSpaceInfo); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "CardQueryFreeSpace() md free space error"); - return dwret; + goto err; } logprintf(pCardData, 7, "FreeSpace:\n"); loghex(pCardData, 7, (BYTE *)pCardFreeSpaceInfo, sizeof(*pCardFreeSpaceInfo)); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } @@ -3512,20 +4336,23 @@ (unsigned long)dwKeySpec, (unsigned long)dwFlags, pKeySizes ? (unsigned long)pKeySizes->dwVersion : 0); - if (!pCardData) - return SCARD_E_INVALID_PARAMETER; - if ( dwFlags != 0 ) - return SCARD_E_INVALID_PARAMETER; - if ( dwKeySpec == 0 ) + if (!pCardData || dwFlags != 0 || dwKeySpec == 0 || !lock(pCardData)) return SCARD_E_INVALID_PARAMETER; + dwret = check_card_status(pCardData, "CardQueryKeySizes"); + if (dwret != SCARD_S_SUCCESS) + goto err; + dwret = md_query_key_sizes(pCardData, dwKeySpec, pKeySizes); if (dwret != SCARD_S_SUCCESS) - return dwret; + goto err; logprintf(pCardData, 7, "pKeySizes:\n"); loghex(pCardData, 7, (BYTE *)pKeySizes, sizeof(*pKeySizes)); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } @@ -3533,6 +4360,7 @@ __inout PCARD_RSA_DECRYPT_INFO pInfo) { + DWORD dwret; int r, opt_crypt_flags = 0; unsigned ui; VENDOR_SPECIFIC *vs; @@ -3545,11 +4373,7 @@ (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardRSADecrypt\n"); - if (!pCardData) - return SCARD_E_INVALID_PARAMETER; - if (!pInfo) - return SCARD_E_INVALID_PARAMETER; - if ( pInfo->pbData == NULL ) + if (!pCardData || !pInfo || pInfo->pbData == NULL) return SCARD_E_INVALID_PARAMETER; if (pInfo->dwVersion > CARD_RSA_KEY_DECRYPT_INFO_CURRENT_VERSION) return ERROR_REVISION_MISMATCH; @@ -3559,13 +4383,24 @@ if (pInfo->dwKeySpec != AT_KEYEXCHANGE) return SCARD_E_INVALID_PARAMETER; + if (!lock(pCardData)) + return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_reader_status(pCardData, "CardRSADecrypt"); + if (dwret != SCARD_S_SUCCESS) + goto err; + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } /* check if the container exists */ - if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_NO_KEY_CONTAINER; - - check_reader_status(pCardData); + if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) { + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; + } logprintf(pCardData, 2, "CardRSADecrypt dwVersion=%lu, bContainerIndex=%u, dwKeySpec=%lu pbData=%p, cbData=%lu\n", @@ -3583,18 +4418,22 @@ pkey = vs->p15_containers[pInfo->bContainerIndex].prkey_obj; if (!pkey) { logprintf(pCardData, 2, "CardRSADecrypt prkey not found\n"); - return SCARD_E_NO_KEY_CONTAINER; + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; } /* input and output buffers are always the same size */ pbuf = pCardData->pfnCspAlloc(pInfo->cbData); - if (!pbuf) - return SCARD_E_NO_MEMORY; + if (!pbuf) { + dwret = SCARD_E_NO_MEMORY; + goto err; + } pbuf2 = pCardData->pfnCspAlloc(pInfo->cbData); if (!pbuf2) { pCardData->pfnCspFree(pbuf); - return SCARD_E_NO_MEMORY; + dwret = SCARD_E_NO_MEMORY; + goto err; } /*inversion donnees*/ @@ -3611,17 +4450,19 @@ prkey_info->modulus_length); pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_F_INTERNAL_ERROR; + dwret = SCARD_F_INTERNAL_ERROR; + goto err; } - /* filter boggus input: the data to decrypt is shorter than the RSA key ? */ + /* filter bogus input: the data to decrypt is shorter than the RSA key ? */ if ( pInfo->cbData < prkey_info->modulus_length / 8) { /* according to the minidriver specs, this is the error code to return (instead of invalid parameter when the call is forwarded to the card implementation) */ pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_E_INSUFFICIENT_BUFFER; + dwret = SCARD_E_INSUFFICIENT_BUFFER; + goto err; } if (alg_info->flags & SC_ALGORITHM_RSA_RAW) { @@ -3644,7 +4485,8 @@ logprintf(pCardData, 2, "Cannot strip PKCS1 padding: %i\n", r); pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_F_INTERNAL_ERROR; + dwret = SCARD_F_INTERNAL_ERROR; + goto err; } } else if (pInfo->dwPaddingType == CARD_PADDING_OAEP) { @@ -3652,7 +4494,8 @@ logprintf(pCardData, 2, "OAEP padding not implemented\n"); pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_F_INTERNAL_ERROR; + dwret = SCARD_F_INTERNAL_ERROR; + goto err; } } } @@ -3688,14 +4531,16 @@ logprintf(pCardData, 2, "CardRSADecrypt: no usable RSA algorithm\n"); pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_E_INVALID_PARAMETER; + dwret = SCARD_E_INVALID_PARAMETER; + goto err; } if ( r < 0) { logprintf(pCardData, 2, "sc_pkcs15_decipher error(%i): %s\n", r, sc_strerror(r)); pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + dwret = md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + goto err; } logprintf(pCardData, 2, "decrypted data(%lu):\n", @@ -3708,12 +4553,16 @@ pCardData->pfnCspFree(pbuf); pCardData->pfnCspFree(pbuf2); - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __inout PCARD_SIGNING_INFO pInfo) { + DWORD dwret; VENDOR_SPECIFIC *vs; ALG_ID hashAlg; sc_pkcs15_prkey_info_t *prkey_info; @@ -3751,6 +4600,13 @@ if (pInfo->dwSigningFlags & ~(CARD_PADDING_INFO_PRESENT | CARD_PADDING_NONE | CARD_BUFFER_SIZE_ONLY | CARD_PADDING_PKCS1 | CARD_PADDING_PSS | CARD_PADDING_OAEP)) return SCARD_E_INVALID_PARAMETER; + if (!lock(pCardData)) + return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_reader_status(pCardData, "CardSignData"); + if (dwret != SCARD_S_SUCCESS) + goto err; + logprintf(pCardData, 2, "CardSignData dwVersion=%lu, bContainerIndex=%u, dwKeySpec=%lu, dwSigningFlags=0x%08X, aiHashAlg=0x%08X\n", (unsigned long)pInfo->dwVersion, @@ -3766,21 +4622,30 @@ hashAlg = pInfo->aiHashAlg; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_NO_KEY_CONTAINER; + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } + + if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) { + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; + } pkey = vs->p15_containers[pInfo->bContainerIndex].prkey_obj; - if (!pkey) - return SCARD_E_NO_KEY_CONTAINER; + if (!pkey) { + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; + } prkey_info = (struct sc_pkcs15_prkey_info *)(pkey->data); - check_reader_status(pCardData); - logprintf(pCardData, 2, "pInfo->dwVersion = %lu\n", (unsigned long)pInfo->dwVersion); - if (dataToSignLen < pInfo->cbData) - return SCARD_E_INSUFFICIENT_BUFFER; + if (dataToSignLen < pInfo->cbData) { + dwret = SCARD_E_INSUFFICIENT_BUFFER; + goto err; + } memcpy(dataToSign, pInfo->pbData, pInfo->cbData); dataToSignLen = pInfo->cbData; @@ -3788,11 +4653,13 @@ BCRYPT_PKCS1_PADDING_INFO *pinf = (BCRYPT_PKCS1_PADDING_INFO *)pInfo->pPaddingInfo; if (CARD_PADDING_PSS == pInfo->dwPaddingType) { logprintf(pCardData, 0, "unsupported paddingtype CARD_PADDING_PSS\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } else if (CARD_PADDING_PKCS1 != pInfo->dwPaddingType) { logprintf(pCardData, 0, "unsupported paddingtype\n"); - return SCARD_E_INVALID_PARAMETER; + dwret = SCARD_E_INVALID_PARAMETER; + goto err; } if (!pinf->pszAlgId) { @@ -3817,11 +4684,11 @@ opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA512; else if (wcscmp(pinf->pszAlgId, L"RIPEMD160") == 0) opt_hash_flags = SC_ALGORITHM_RSA_HASH_RIPEMD160; - else - { + else { logprintf(pCardData, 0,"unknown AlgId %S\n",NULLWSTR(pinf->pszAlgId)); - return SCARD_E_UNSUPPORTED_FEATURE; - } + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; + } } } else { @@ -3843,7 +4710,8 @@ opt_hash_flags = SC_ALGORITHM_RSA_HASH_RIPEMD160; else if (hashAlg !=0) { logprintf(pCardData, 0, "bogus aiHashAlg %i\n", hashAlg); - return SCARD_E_UNSUPPORTED_FEATURE; + dwret = SCARD_E_UNSUPPORTED_FEATURE; + goto err; } } @@ -3874,7 +4742,8 @@ r = sc_pkcs1_encode(vs->ctx, opt_hash_flags, pInfo->pbData, pInfo->cbData, dataToSign, &dataToSignLen, 0); if (r) { logprintf(pCardData, 2, "PKCS#1 encode error %s\n", sc_strerror(r)); - return SCARD_E_INVALID_VALUE; + dwret = SCARD_E_INVALID_VALUE; + goto err; } } @@ -3902,11 +4771,13 @@ logprintf(pCardData, 0, "unknown ECC key size %"SC_FORMAT_LEN_SIZE_T"u\n", prkey_info->field_length); - return SCARD_E_INVALID_VALUE; + dwret = SCARD_E_INVALID_VALUE; + goto err; } } else { logprintf(pCardData, 0, "invalid private key\n"); - return SCARD_E_INVALID_VALUE; + dwret = SCARD_E_INVALID_VALUE; + goto err; } logprintf(pCardData, 3, "pInfo->cbSignedData = %lu\n", @@ -3920,8 +4791,10 @@ lg = pInfo->cbSignedData; logprintf(pCardData, 3, "lg = %lu\n", (unsigned long)lg); pbuf = pCardData->pfnCspAlloc(lg); - if (!pbuf) - return SCARD_E_NO_MEMORY; + if (!pbuf) { + dwret = SCARD_E_NO_MEMORY; + goto err; + } logprintf(pCardData, 7, "Data to sign: "); loghex(pCardData, 7, dataToSign, dataToSignLen); @@ -3929,7 +4802,8 @@ pInfo->pbSignedData = (PBYTE) pCardData->pfnCspAlloc(pInfo->cbSignedData); if (!pInfo->pbSignedData) { pCardData->pfnCspFree(pbuf); - return SCARD_E_NO_MEMORY; + dwret = SCARD_E_NO_MEMORY; + goto err; } r = sc_pkcs15_compute_signature(vs->p15card, pkey, opt_crypt_flags, dataToSign, dataToSignLen, pbuf, lg); @@ -3937,7 +4811,8 @@ if(r < 0) { logprintf(pCardData, 2, "sc_pkcs15_compute_signature error %s\n", sc_strerror(r)); pCardData->pfnCspFree(pbuf); - return md_translate_OpenSC_to_Windows_error(r, SCARD_F_INTERNAL_ERROR); + dwret = md_translate_OpenSC_to_Windows_error(r, SCARD_F_INTERNAL_ERROR); + goto err; } pInfo->cbSignedData = r; @@ -3965,12 +4840,15 @@ (unsigned int)pCardData->hScard, (unsigned int)pCardData->hSCardCtx); - return SCARD_S_SUCCESS; +err: + unlock(pCardData); + return dwret; } DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, __inout PCARD_DH_AGREEMENT_INFO pAgreementInfo) { + DWORD dwret; VENDOR_SPECIFIC *vs; struct sc_pkcs15_object *pkey = NULL; int r, opt_derive_flags = 0; @@ -3999,13 +4877,24 @@ && pCardData->dwVersion == CARD_DATA_CURRENT_VERSION) return ERROR_REVISION_MISMATCH; + if (!lock(pCardData)) + return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_reader_status(pCardData, "CardConstructDHAgreement"); + if (dwret != SCARD_S_SUCCESS) + goto err; + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + dwret = SCARD_E_INVALID_PARAMETER; + goto err; + } /* check if the container exists */ - if (pAgreementInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_NO_KEY_CONTAINER; - - check_reader_status(pCardData); + if (pAgreementInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) { + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; + } logprintf(pCardData, 2, "CardConstructDHAgreement dwVersion=%lu, dwKeySpec=%u pbData=%p, cbData=%lu\n", (unsigned long)pAgreementInfo->dwVersion, @@ -4016,14 +4905,16 @@ pkey = vs->p15_containers[pAgreementInfo->bContainerIndex].prkey_obj; if (!pkey) { logprintf(pCardData, 2, "CardConstructDHAgreement prkey not found\n"); - return SCARD_E_NO_KEY_CONTAINER; + dwret = SCARD_E_NO_KEY_CONTAINER; + goto err; } /* convert the Windows public key into an OpenSC public key */ dwPublicKeySize = pAgreementInfo->dwPublicKey - sizeof(BCRYPT_ECCKEY_BLOB) + 1; pbPublicKey = (PBYTE) pCardData->pfnCspAlloc(dwPublicKeySize); if (!pbPublicKey) { - return ERROR_OUTOFMEMORY; + dwret = ERROR_OUTOFMEMORY; + goto err; } pbPublicKey[0] = 4; @@ -4036,13 +4927,15 @@ if ( r < 0) { logprintf(pCardData, 2, "sc_pkcs15_derive error(%i): %s\n", r, sc_strerror(r)); pCardData->pfnCspFree(pbPublicKey); - return md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + dwret = md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + goto err; } out = pCardData->pfnCspAlloc(outlen); if (!out) { - return ERROR_OUTOFMEMORY; + dwret = ERROR_OUTOFMEMORY; + goto err; } r = sc_pkcs15_derive(vs->p15card, pkey, opt_derive_flags, pbPublicKey, dwPublicKeySize, out, &outlen ); @@ -4053,7 +4946,8 @@ if ( r < 0) { logprintf(pCardData, 2, "sc_pkcs15_derive error(%i): %s\n", r, sc_strerror(r)); pCardData->pfnCspFree(out); - return md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + dwret = md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); + goto err; } /* save the dh agreement for later use */ @@ -4065,14 +4959,16 @@ pAgreementInfo->bSecretAgreementIndex = i; dh_agreement->pbAgreement = out; dh_agreement->dwSize = outlen; - return SCARD_S_SUCCESS; + dwret = SCARD_S_SUCCESS; + goto err; } } /* no empty space => need to allocate memory */ temp = (struct md_dh_agreement*) pCardData->pfnCspAlloc((vs->allocatedAgreements+1) * sizeof(struct md_dh_agreement)); if (!temp) { pCardData->pfnCspFree(out); - return SCARD_E_NO_MEMORY; + dwret = SCARD_E_NO_MEMORY; + goto err; } if ((vs->allocatedAgreements) > 0) { memcpy(temp, vs->dh_agreements, sizeof(struct md_dh_agreement) * (vs->allocatedAgreements)); @@ -4084,7 +4980,10 @@ dh_agreement->pbAgreement = out; dh_agreement->dwSize = outlen; vs->allocatedAgreements++; - return SCARD_S_SUCCESS; + +err: + unlock(pCardData); + return dwret; } @@ -4534,14 +5433,16 @@ if (pAgreementInfo->dwFlags & ~(KDF_USE_SECRET_AS_HMAC_KEY_FLAG | CARD_RETURN_KEY_HANDLE | CARD_BUFFER_SIZE_ONLY)) return SCARD_E_INVALID_PARAMETER; - /* according to the documenation, CARD_DERIVE_KEY_CURRENT_VERSION should be equal to 2. - In pratice it is not 2 but 1 + /* according to the documentation, CARD_DERIVE_KEY_CURRENT_VERSION should be equal to 2. + In practice it is not 2 but 1 if ( pAgreementInfo->dwVersion < CARD_DERIVE_KEY_CURRENT_VERSION && pCardData->dwVersion == CARD_DATA_CURRENT_VERSION) return ERROR_REVISION_MISMATCH;*/ vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; /* check if the agreement index is ok */ if (pAgreementInfo->bSecretAgreementIndex >= vs->allocatedAgreements) { @@ -4643,7 +5544,7 @@ szAlgorithm = BCRYPT_SHA1_ALGORITHM; } - /* check the values with the KDF choosen */ + /* check the values with the KDF chosen */ if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_HASH) == 0) { } else if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_HMAC) == 0) { @@ -4712,6 +5613,8 @@ if (dwFlags) return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; if (bSecretAgreementIndex >= vs->allocatedAgreements) { return SCARD_E_INVALID_PARAMETER; @@ -4750,6 +5653,7 @@ __out_opt PDWORD pcbSessionPin, __out_opt PDWORD pcAttemptsRemaining) { + DWORD dwret; VENDOR_SPECIFIC *vs; struct sc_pkcs15_object *pin_obj = NULL; struct sc_pkcs15_auth_info *auth_info = NULL; @@ -4765,17 +5669,25 @@ if (!pCardData) return SCARD_E_INVALID_PARAMETER; + dwret = check_card_reader_status(pCardData, "CardAuthenticateEx"); + if (dwret != SCARD_S_SUCCESS) + return dwret; + logprintf(pCardData, 2, "CardAuthenticateEx: PinId=%u, dwFlags=0x%08X, cbPinData=%lu, Attempts %s\n", (unsigned int)PinId, (unsigned int)dwFlags, (unsigned long)cbPinData, pcAttemptsRemaining ? "YES" : "NO"); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; - r = check_reader_status(pCardData); + if (PinId >= MD_MAX_PINS) + return SCARD_E_INVALID_PARAMETER; - if ((vs->p15card) == NULL) - return SCARD_F_INTERNAL_ERROR; + pin_obj = vs->pin_objs[PinId]; + if (!pin_obj) + return SCARD_E_INVALID_PARAMETER; #if 0 /* TODO do we need to return SCARD_E_UNSUPPORTED_FEATURE if the card @@ -4791,6 +5703,10 @@ if (dwFlags & ~(CARD_AUTHENTICATE_GENERATE_SESSION_PIN | CARD_AUTHENTICATE_SESSION_PIN | CARD_PIN_SILENT_CONTEXT)) return SCARD_E_INVALID_PARAMETER; + if (dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN && + (ppbSessionPin == NULL || pcbSessionPin == NULL)) + return SCARD_E_INVALID_PARAMETER; + /* using a pin pad */ if (NULL == pbPinData) { if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD @@ -4802,20 +5718,9 @@ } } - if (PinId != ROLE_USER) - return SCARD_E_INVALID_PARAMETER; - if(pcAttemptsRemaining) (*pcAttemptsRemaining) = (DWORD) -1; - r = md_get_pin_by_role(pCardData, PinId, &pin_obj); - if (r != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object"); - return r; - } - - if (!pin_obj) - return SCARD_F_INTERNAL_ERROR; auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; /* save the pin type */ auth_method = auth_info->auth_method; @@ -4834,41 +5739,56 @@ cbPinData = 0; } else { /* seems we have a real session pin, set the pin type accordingly */ - logprintf(pCardData, 2, "use real session pin with %d bytes", cbPinData); + logprintf(pCardData, 2, + "use real session pin with %lu bytes", + (unsigned long)cbPinData); auth_info->auth_method = SC_AC_SESSION; } } /* set the session pin according to the minidriver specification */ if (dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN) { + size_t session_pin_len = SC_MAX_PIN_SIZE; + logprintf(pCardData, 2, "generating session pin"); - if (ppbSessionPin) *ppbSessionPin = pCardData->pfnCspAlloc(SC_MAX_PIN_SIZE); - if (ppbSessionPin) *pcbSessionPin = SC_MAX_PIN_SIZE; - r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_GET_SESSION_PIN, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, - ppbSessionPin && *ppbSessionPin ? *ppbSessionPin : NULL, pcbSessionPin, DisplayPinpadUI); + *ppbSessionPin = pCardData->pfnCspAlloc(SC_MAX_PIN_SIZE); + r = md_dialog_perform_pin_operation(pCardData, + SC_PIN_CMD_GET_SESSION_PIN, + vs->p15card, pin_obj, + (const u8 *) pbPinData, + cbPinData, + *ppbSessionPin, + *ppbSessionPin != NULL ? + &session_pin_len : NULL, + DisplayPinpadUI, PinId); if (r) { - if (ppbSessionPin) { + if (*ppbSessionPin != NULL) { pCardData->pfnCspFree(*ppbSessionPin); *ppbSessionPin = NULL; } - if (pcbSessionPin) *pcbSessionPin = 0; + *pcbSessionPin = 0; logprintf(pCardData, 2, "generating session pin failed"); } else { - if (pcbSessionPin && *pcbSessionPin) { - logprintf(pCardData, 2, "generated session pin with %d bytes", *pcbSessionPin); + if (*ppbSessionPin != NULL && session_pin_len > 0) { + logprintf(pCardData, 2, + "generated session pin with %"SC_FORMAT_LEN_SIZE_T"u bytes", + session_pin_len); + + *pcbSessionPin = session_pin_len; } else { logprintf(pCardData, 2, "session pin not supported"); - if (ppbSessionPin) { + if (*ppbSessionPin != NULL) { pCardData->pfnCspFree(*ppbSessionPin); *ppbSessionPin = NULL; } + *pcbSessionPin = 0; } } } else { if (pcbSessionPin) *pcbSessionPin = 0; if (ppbSessionPin) *ppbSessionPin = NULL; logprintf(pCardData, 2, "standard pin verification"); - r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_VERIFY, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, NULL, NULL, DisplayPinpadUI); + r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_VERIFY, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, NULL, NULL, DisplayPinpadUI, PinId); } /* restore the pin type */ @@ -4891,16 +5811,16 @@ logprintf(pCardData, 2, "Pin code correct.\n"); /* set the session pin according to the minidriver specification */ - if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN - && pcbSessionPin && *pcbSessionPin == 0 + if (dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN + && *pcbSessionPin == 0 && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { /* If we could not generate a real session PIN, set it to a special * value for pinpad authentication to force a new pinpad authentication */ - *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); - if (ppbSessionPin) { - *ppbSessionPin = pCardData->pfnCspAlloc(sizeof(MAGIC_SESSION_PIN)); - if (ppbSessionPin) memcpy(*ppbSessionPin, MAGIC_SESSION_PIN, sizeof(MAGIC_SESSION_PIN)); + *ppbSessionPin = pCardData->pfnCspAlloc(sizeof(MAGIC_SESSION_PIN)); + if (*ppbSessionPin != NULL) { + memcpy(*ppbSessionPin, MAGIC_SESSION_PIN, sizeof(MAGIC_SESSION_PIN)); + *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); } } @@ -4919,12 +5839,13 @@ __in DWORD cRetryCount, __out_opt PDWORD pcAttemptsRemaining) { + DWORD dwret; VENDOR_SPECIFIC *vs = NULL; - DWORD dw_rv; struct sc_pkcs15_object *pin_obj = NULL; int rv; struct sc_pkcs15_auth_info *auth_info; BOOL DisplayPinpadUI = FALSE; + size_t target_len = cbTargetData; logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -4933,6 +5854,15 @@ if (!pCardData) return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_reader_status(pCardData, "CardChangeAuthenticatorEx"); + if (dwret != SCARD_S_SUCCESS) + return dwret; + + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + if (!(dwFlags & PIN_CHANGE_FLAG_UNBLOCK) && !(dwFlags & PIN_CHANGE_FLAG_CHANGEPIN)){ logprintf(pCardData, 1, "Unknown flag\n"); return SCARD_E_INVALID_PARAMETER; @@ -4941,12 +5871,11 @@ return SCARD_E_INVALID_PARAMETER; if (dwFlags & PIN_CHANGE_FLAG_UNBLOCK && dwAuthenticatingPinId == dwTargetPinId) return SCARD_E_INVALID_PARAMETER; - if (dwAuthenticatingPinId != ROLE_USER && dwAuthenticatingPinId != ROLE_ADMIN) + if (dwAuthenticatingPinId >= MD_MAX_PINS || dwTargetPinId >= MD_MAX_PINS) return SCARD_E_INVALID_PARAMETER; - if (dwTargetPinId != ROLE_USER && dwTargetPinId != ROLE_ADMIN) { - logprintf(pCardData, 1, "Only ROLE_USER or ROLE_ADMIN is supported\n"); + if (!vs->pin_objs[dwAuthenticatingPinId] || !vs->pin_objs[dwTargetPinId]) return SCARD_E_INVALID_PARAMETER; - } + /* according to the spec: cRetryCount MUST be zero */ if (cRetryCount) return SCARD_E_INVALID_PARAMETER; @@ -4958,11 +5887,6 @@ (unsigned int)dwTargetPinId, (unsigned long)cbTargetData, pcAttemptsRemaining ? "YES" : "NO"); - - check_reader_status(pCardData); - - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { if (pbAuthenticatingPinData == NULL || cbAuthenticatingPinData == 0) { @@ -4983,20 +5907,22 @@ } } - dw_rv = md_get_pin_by_role(pCardData, dwTargetPinId, &pin_obj); - if (dw_rv != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object %s", (dwTargetPinId==ROLE_ADMIN?"admin":"user")); - return dw_rv; - } - if (!pin_obj) - return SCARD_F_INTERNAL_ERROR; + pin_obj = vs->pin_objs[dwTargetPinId]; if(pcAttemptsRemaining) (*pcAttemptsRemaining) = (DWORD) -1; - rv = md_dialog_perform_pin_operation(pCardData, (dwFlags & PIN_CHANGE_FLAG_UNBLOCK ? SC_PIN_CMD_UNBLOCK:SC_PIN_CMD_CHANGE), - vs->p15card, pin_obj, (const u8 *) pbAuthenticatingPinData, cbAuthenticatingPinData, pbTargetData, &cbTargetData, DisplayPinpadUI); - + /* FIXME: this does not enforce dwAuthenticatingPinId */ + rv = md_dialog_perform_pin_operation(pCardData, + (dwFlags & PIN_CHANGE_FLAG_UNBLOCK ? + SC_PIN_CMD_UNBLOCK : + SC_PIN_CMD_CHANGE), + vs->p15card, pin_obj, + (const u8 *) pbAuthenticatingPinData, + cbAuthenticatingPinData, + pbTargetData, &target_len, + DisplayPinpadUI, dwTargetPinId); + if (rv) { logprintf(pCardData, 2, "Failed to %s %s PIN: '%s' (%i)\n", (dwFlags & PIN_CHANGE_FLAG_CHANGEPIN?"change":"unblock"), @@ -5040,6 +5966,7 @@ __out PDWORD pdwDataLen, __in DWORD dwFlags) { + DWORD dwret; VENDOR_SPECIFIC *vs = NULL; struct md_pkcs15_container *cont = NULL; @@ -5048,9 +5975,13 @@ (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetContainerProperty\n"); - check_reader_status(pCardData); + if (!pCardData) + return SCARD_E_INVALID_PARAMETER; + + dwret = check_card_status(pCardData, "CardGetContainerProperty"); + if (dwret != SCARD_S_SUCCESS) + return dwret; - if (!pCardData) return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 2, "CardGetContainerProperty bContainerIndex=%u, wszProperty=%S, cbData=%lu, dwFlags=0x%08X\n", (unsigned int)bContainerIndex, NULLWSTR(wszProperty), @@ -5064,8 +5995,11 @@ if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) return SCARD_E_NO_KEY_CONTAINER; - /* the test for the existence of containers is redondant with the one made in CardGetContainerInfo but CCP_PIN_IDENTIFIER does not do it */ + /* the test for the existence of containers is redundant with the one made in CardGetContainerInfo but CCP_PIN_IDENTIFIER does not do it */ vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + cont = &vs->p15_containers[bContainerIndex]; if (!cont->prkey_obj) { @@ -5091,7 +6025,34 @@ *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) return ERROR_INSUFFICIENT_BUFFER; - *p = ROLE_USER; + + if (cont->prkey_obj->auth_id.len == 0) + *p = ROLE_EVERYONE; + else { + size_t pinidx; + for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { + struct sc_pkcs15_auth_info *pin_info; + + if (!vs->pin_objs[pinidx]) + continue; + + pin_info = + (struct sc_pkcs15_auth_info *)vs->pin_objs[pinidx]->data; + + if (sc_pkcs15_compare_id(&cont->prkey_obj->auth_id, + &pin_info->auth_id)) + break; + } + + if (pinidx >= MD_MAX_PINS) { + logprintf(pCardData, 2, + "Could not find container %i PIN, returning no PIN needed, might not work properly\n", + bContainerIndex); + *p = ROLE_EVERYONE; + } else + *p = (PIN_ID)pinidx; + } + logprintf(pCardData, 2, "Return Pin id %u\n", (unsigned int)*p); return SCARD_S_SUCCESS; @@ -5138,9 +6099,13 @@ if (!pbData || !pdwDataLen) return SCARD_E_INVALID_PARAMETER; - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + dwret = check_card_reader_status(pCardData, "CardGetProperty"); + if (dwret != SCARD_S_SUCCESS) + return dwret; - check_reader_status(pCardData); + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; if (wcscmp(CP_CARD_FREE_SPACE,wszProperty) == 0) { PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo = (PCARD_FREE_SPACE_INFO )pbData; @@ -5249,22 +6214,17 @@ if (p->dwVersion != PIN_INFO_CURRENT_VERSION) return ERROR_REVISION_MISMATCH; + if (dwFlags >= MD_MAX_PINS) + return SCARD_E_INVALID_PARAMETER; + + if (!vs->pin_objs[dwFlags]) + return SCARD_E_INVALID_PARAMETER; + 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: - logprintf(pCardData, 2, - "returning info on PIN ROLE_USER ( Auth ) [%lu]\n", - (unsigned long)dwFlags); - p->PinPurpose = DigitalSignaturePin; - p->PinCachePolicy.dwVersion = PIN_CACHE_POLICY_CURRENT_VERSION; - p->PinCachePolicy.dwPinCachePolicyInfo = 0; - p->PinCachePolicy.PinCachePolicyType = PinCacheNormal; - p->dwChangePermission = CREATE_PIN_SET(ROLE_USER); - p->dwUnblockPermission = CREATE_PIN_SET(ROLE_ADMIN); - break; case ROLE_ADMIN: logprintf(pCardData, 2, "returning info on PIN ROLE_ADMIN ( Unblock ) [%lu]\n", @@ -5277,19 +6237,40 @@ p->dwUnblockPermission = 0; break; default: - logprintf(pCardData, 0, - "Invalid Pin number %lu requested\n", + logprintf(pCardData, 2, + "returning info on normal PIN [%lu]\n", (unsigned long)dwFlags); - return SCARD_E_INVALID_PARAMETER; + + if (dwFlags == ROLE_USER) + p->PinPurpose = PrimaryCardPin; + else if (dwFlags == MD_ROLE_USER_SIGN) + p->PinPurpose = DigitalSignaturePin; + else + p->PinPurpose = AuthenticationPin; + + p->PinCachePolicy.dwVersion = PIN_CACHE_POLICY_CURRENT_VERSION; + p->PinCachePolicy.dwPinCachePolicyInfo = 0; + p->PinCachePolicy.PinCachePolicyType = PinCacheNormal; + p->dwChangePermission = CREATE_PIN_SET(dwFlags); + p->dwUnblockPermission = CREATE_PIN_SET(ROLE_ADMIN); + break; } } else if (wcscmp(CP_CARD_LIST_PINS,wszProperty) == 0) { PPIN_SET p = (PPIN_SET) pbData; + size_t pinidx; if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) return ERROR_INSUFFICIENT_BUFFER; - SET_PIN(*p, ROLE_USER); + + memset(p, 0, sizeof(*p)); + for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { + if (!vs->pin_objs[pinidx]) + continue; + + SET_PIN(*p, (PIN_ID)pinidx); + } } else if (wcscmp(CP_CARD_AUTHENTICATED_STATE,wszProperty) == 0) { PPIN_SET p = (PPIN_SET) pbData; @@ -5304,8 +6285,12 @@ else if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY,wszProperty) == 0) { DWORD *p = (DWORD *)pbData; - if (dwFlags != ROLE_USER) + if (dwFlags >= MD_MAX_PINS) return SCARD_E_INVALID_PARAMETER; + + if (!vs->pin_objs[dwFlags]) + return SCARD_E_INVALID_PARAMETER; + if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) @@ -5371,6 +6356,8 @@ (unsigned long)dwFlags); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; if (!wszProperty) return SCARD_E_INVALID_PARAMETER; @@ -5678,51 +6665,23 @@ return SCARD_E_UNSUPPORTED_FEATURE; } -/** The CardCreateContainerEx function creates a new key container that the -container index identifies and the bContainerIndex parameter specifies. The function -associates the key container with the PIN that the PinId parameter specified. -This function is useful if the card-edge does not allow for changing the key attributes -after the key container is created. This function replaces the need to call -CardSetContainerProperty to set the CCP_PIN_IDENTIFIER property CardCreateContainer -is called. -The caller of this function can provide the key material that the card imports. -This is useful in those situations in which the card either does not support internal -key generation or the caller requests that the key be archived in the card.*/ - -DWORD WINAPI CardCreateContainerEx( - __in PCARD_DATA pCardData, - __in BYTE bContainerIndex, - __in DWORD dwFlags, - __in DWORD dwKeySpec, - __in DWORD dwKeySize, - __in PBYTE pbKeyData, - __in PIN_ID PinId -) -{ - if (PinId == ROLE_ADMIN) - return SCARD_W_SECURITY_VIOLATION; - if (PinId != ROLE_USER) - return SCARD_E_INVALID_PARAMETER; - /* basically CardCreateContainerEx is CardCreateContainer + the PinId */ - return CardCreateContainer(pCardData, bContainerIndex, dwFlags, dwKeySpec, dwKeySize, pbKeyData); -} - DWORD WINAPI CardAcquireContext(__inout PCARD_DATA pCardData, __in DWORD dwFlags) { VENDOR_SPECIFIC *vs; DWORD dwret, suppliedVersion = 0; + CRITICAL_SECTION hScard_lock; if (!pCardData) return SCARD_E_INVALID_PARAMETER; - if (dwFlags) + if (dwFlags & ~CARD_SECURE_KEY_INJECTION_NO_CARD_MODE) return SCARD_E_INVALID_PARAMETER; if (!(dwFlags & CARD_SECURE_KEY_INJECTION_NO_CARD_MODE)) { if( pCardData->hSCardCtx == 0) { - logprintf(pCardData, 0, "Invalide handle.\n"); + logprintf(pCardData, 0, "Invalid handle.\n"); return SCARD_E_INVALID_HANDLE; } if( pCardData->hScard == 0) { - logprintf(pCardData, 0, "Invalide handle.\n"); + logprintf(pCardData, 0, "Invalid handle.\n"); return SCARD_E_INVALID_HANDLE; } } @@ -5736,7 +6695,7 @@ return SCARD_E_INVALID_PARAMETER; if ( pCardData->pwszCardName == NULL ) return SCARD_E_INVALID_PARAMETER; - /* <2 lenght or >=0x22 are not ISO compliant */ + /* <2 length or >=0x22 are not ISO compliant */ if (pCardData->cbAtr >= 0x22 || pCardData->cbAtr <= 0x2) return SCARD_E_INVALID_PARAMETER; /* ATR beginning by 0x00 or 0xFF are not ISO compliant */ @@ -5760,6 +6719,9 @@ return SCARD_E_NO_MEMORY; memset(vs, 0, sizeof(VENDOR_SPECIFIC)); + InitializeCriticalSection(&vs->hScard_lock); + lock(pCardData); + logprintf(pCardData, 1, "==================================================================\n"); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -5781,12 +6743,8 @@ (unsigned long)pCardData->dwVersion); dwret = md_create_context(pCardData, vs); - if (dwret != SCARD_S_SUCCESS) { - pCardData->pfnCspFree(pCardData->pvVendorSpecific); - pCardData->pvVendorSpecific = NULL; - return dwret; - } - md_static_data.flags &= ~MD_STATIC_FLAG_CONTEXT_DELETED; + if (dwret != SCARD_S_SUCCESS) + goto ret_free; pCardData->pfnCardDeleteContext = CardDeleteContext; pCardData->pfnCardQueryCapabilities = CardQueryCapabilities; @@ -5816,18 +6774,12 @@ pCardData->pfnCardConstructDHAgreement = CardConstructDHAgreement; dwret = associate_card(pCardData); - if (dwret != SCARD_S_SUCCESS) { - pCardData->pfnCspFree(pCardData->pvVendorSpecific); - pCardData->pvVendorSpecific = NULL; - return dwret; - } + if (dwret != SCARD_S_SUCCESS) + goto ret_release; dwret = md_fs_init(pCardData); - if (dwret != SCARD_S_SUCCESS) { - pCardData->pfnCspFree(pCardData->pvVendorSpecific); - pCardData->pvVendorSpecific = NULL; - return dwret; - } + if (dwret != SCARD_S_SUCCESS) + goto ret_disassoc; logprintf(pCardData, 1, "OpenSC init done.\n"); logprintf(pCardData, 1, "Supplied version %lu - version used %lu.\n", @@ -5864,20 +6816,40 @@ } } + unlock(pCardData); + return SCARD_S_SUCCESS; + +ret_disassoc: + disassociate_card(pCardData); + +ret_release: + sc_release_context(vs->ctx); + +ret_free: + hScard_lock = vs->hScard_lock; + pCardData->pfnCspFree(pCardData->pvVendorSpecific); + pCardData->pvVendorSpecific = NULL; + LeaveCriticalSection(&hScard_lock); + DeleteCriticalSection(&hScard_lock); + return dwret; } -static int associate_card(PCARD_DATA pCardData) +static DWORD associate_card(PCARD_DATA pCardData) { VENDOR_SPECIFIC *vs; - DWORD dw; int r; + struct sc_app_info *app_generic; + struct sc_aid *aid; logprintf(pCardData, 1, "associate_card\n"); if (!pCardData) return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) + return SCARD_E_INVALID_PARAMETER; + /* * set the addresses of the reader and card handles * Our pcsc code will use these when we call sc_ctx_use_reader @@ -5886,75 +6858,66 @@ vs->hSCardCtx = pCardData->hSCardCtx; vs->hScard = pCardData->hScard; - /** - * Check if a linked context has been deleted - if so, repair shared data. - * Multithreaded issue - TODO: proper multithreaded handling - */ - if (md_static_data.flags & MD_STATIC_FLAG_CONTEXT_DELETED) - { - r = sc_context_repair(&(vs->ctx)); - logprintf(pCardData, 2, "sc_context_repair called - result = %d, %s\n", r, sc_strerror(r)); - md_static_data.flags &= ~MD_STATIC_FLAG_CONTEXT_DELETED; - } - /* set the provided reader and card handles into ctx */ - logprintf(pCardData, 5, "sc_ctx_use_reader %d\n", sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard)); + r = sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard); + if (r != SC_SUCCESS) { + logprintf(pCardData, 0, "sc_ctx_use_reader() failed with %d\n", r); + return SCARD_E_COMM_DATA_LOST; + } /* should be only one reader */ logprintf(pCardData, 5, "sc_ctx_get_reader_count(ctx): %d\n", sc_ctx_get_reader_count(vs->ctx)); vs->reader = sc_ctx_get_reader(vs->ctx, 0); - if(vs->reader) { - struct sc_app_info *app_generic = NULL; - struct sc_aid *aid = NULL; - - r = sc_connect_card(vs->reader, &(vs->card)); - if(r) { - logprintf(pCardData, 0, "Cannot connect card in reader '%s'\n", NULLSTR(vs->reader->name)); - return SCARD_E_UNKNOWN_CARD; - } - logprintf(pCardData, 3, "Connected card in '%s'\n", NULLSTR(vs->reader->name)); - - app_generic = sc_pkcs15_get_application_by_type(vs->card, "generic"); - if (app_generic) - logprintf(pCardData, 3, "Use generic application '%s'\n", app_generic->label); - aid = app_generic ? &app_generic->aid : NULL; - - r = sc_pkcs15_bind(vs->card, aid, &(vs->p15card)); - logprintf(pCardData, 2, "PKCS#15 initialization result: %d, %s\n", r, sc_strerror(r)); - } + if (!vs->reader) + return SCARD_E_COMM_DATA_LOST; - if(vs->card == NULL || vs->p15card == NULL) { - logprintf(pCardData, 0, "Card unknown.\n"); + r = sc_connect_card(vs->reader, &(vs->card)); + if (r != SC_SUCCESS) { + logprintf(pCardData, 0, "Cannot connect card in reader '%s'\n", NULLSTR(vs->reader->name)); return SCARD_E_UNKNOWN_CARD; } + logprintf(pCardData, 3, "Connected card in '%s'\n", NULLSTR(vs->reader->name)); - dw = md_get_pin_by_role(pCardData, ROLE_USER, &vs->obj_user_pin); - if (dw != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object"); - return dw; + app_generic = sc_pkcs15_get_application_by_type(vs->card, "generic"); + if (app_generic) + logprintf(pCardData, 3, "Use generic application '%s'\n", app_generic->label); + aid = app_generic ? &app_generic->aid : NULL; + + r = sc_pkcs15_bind(vs->card, aid, &(vs->p15card)); + logprintf(pCardData, 2, "PKCS#15 initialization result: %d, %s\n", r, sc_strerror(r)); + if (r != SC_SUCCESS) { + logprintf(pCardData, 0, "PKCS#15 init failed.\n"); + sc_disconnect_card(vs->card); + return SCARD_E_UNKNOWN_CARD; } - dw = md_get_pin_by_role(pCardData, ROLE_USER, &vs->obj_sopin); - if (dw != SCARD_S_SUCCESS) - logprintf(pCardData, 2, "Cannot get ADMIN PIN object -- ignored"); + vs->initialized = TRUE; return SCARD_S_SUCCESS; - } -static int disassociate_card(PCARD_DATA pCardData) +static void disassociate_card(PCARD_DATA pCardData) { VENDOR_SPECIFIC *vs; + if (!pCardData) { + logprintf(pCardData, 1, + "disassociate_card called without card data\n"); + return; + } + logprintf(pCardData, 1, "disassociate_card\n"); - if (!pCardData) - return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + if (!vs) { + logprintf(pCardData, 1, + "disassociate_card called without vendor specific data\n"); + return; + } - vs->obj_user_pin = NULL; - vs->obj_sopin = NULL; + memset(vs->pin_objs, 0, sizeof(vs->pin_objs)); + memset(vs->p15_containers, 0, sizeof(vs->p15_containers)); if(vs->p15card) { logprintf(pCardData, 6, "sc_pkcs15_unbind\n"); @@ -5972,8 +6935,7 @@ vs->hSCardCtx = -1; vs->hScard = -1; - - return SCARD_S_SUCCESS; + vs->initialized = FALSE; } @@ -6011,10 +6973,11 @@ { case DLL_PROCESS_ATTACH: g_inst = hinstDLL; - md_static_data.attach_check = MD_STATIC_PROCESS_ATTACHED; + sc_notify_instance = hinstDLL; + sc_notify_init(); break; case DLL_PROCESS_DETACH: - md_static_data.attach_check = 0; + sc_notify_close(); break; } return TRUE; @@ -6024,4 +6987,3 @@ #pragma managed(pop) #endif #endif - diff -Nru opensc-0.17.0/src/minidriver/minidriver-feitian.reg opensc-0.19.0/src/minidriver/minidriver-feitian.reg --- opensc-0.17.0/src/minidriver/minidriver-feitian.reg 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/minidriver-feitian.reg 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\ePass2003] -"ATR"=hex:3b,9f,95,81,31,fe,9f,00,66,46,53,05,01,00,11,71,df,00,00,03,6a,82,f8 -"ATRMask"=hex,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" - -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards\ePass2003] -"ATR"=hex:3b,9f,95,81,31,fe,9f,00,66,46,53,05,01,00,11,71,df,00,00,03,6a,82,f8 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,00,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" - - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\FTCOS/PK-01C] -"ATR"=hex:3b,9f,95,81,31,fe,9f,00,65,46,53,05,00,06,71,df,00,00,00,00,00,00,00 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,00,ff,ff,ff,ff,ff,ff,00,00,00,00 -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" - -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards\FTCOS/PK-01C] -"ATR"=hex:3b,9f,95,81,31,fe,9f,00,65,46,53,05,00,06,71,df,00,00,00,00,00,00,00 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,00,ff,ff,ff,ff,ff,ff,00,00,00,00 -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" diff -Nru opensc-0.17.0/src/minidriver/minidriver-italian-cns.reg opensc-0.19.0/src/minidriver/minidriver-italian-cns.reg --- opensc-0.17.0/src/minidriver/minidriver-italian-cns.reg 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/minidriver-italian-cns.reg 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards\CPS] -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" -"ATR"=hex:3b,ff,18,00,ff,c1,0a,31,fe,55,00,6b,05,08,c8,0c,01,11,01,43,4e,53,10,\ - 31,80,05 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\ - ff,ff,ff,ff,ff - -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards\CPS-Athena] -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" -"ATR"=hex:3b,df,18,00,81,31,fe,7d,00,6b,02,0c,01,82,01,11,01,43,4e,53,10,31,80,fc -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\CPS] -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" -"ATR"=hex:3b,ff,18,00,ff,c1,0a,31,fe,55,00,6b,05,08,c8,0c,01,11,01,43,4e,53,10,\ - 31,80,05 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\ - ff,ff,ff,ff,ff - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\CPS-Athena] -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" -"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider" -"80000001"="opensc-minidriver.dll" -"ATR"=hex:3b,df,18,00,81,31,fe,7d,00,6b,02,0c,01,82,01,11,01,43,4e,53,10,31,80,fc -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff Binary files /tmp/tmp8cIdBX/DwE453RpuS/opensc-0.17.0/src/minidriver/minidriver-sc-hsm.reg and /tmp/tmp8cIdBX/coIhbhAT2o/opensc-0.19.0/src/minidriver/minidriver-sc-hsm.reg differ diff -Nru opensc-0.17.0/src/minidriver/minidriver-westcos.reg opensc-0.19.0/src/minidriver/minidriver-westcos.reg --- opensc-0.17.0/src/minidriver/minidriver-westcos.reg 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/minidriver-westcos.reg 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\CEV WESTCOS] -"80000001"="opensc-minidriver.dll" -"ATR"=hex:3f,69,00,00,00,64,01,00,00,00,80,90,00 -"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,00,00,00,f0,ff,ff -"Crypto Provider"="Microsoft Base Smart Card Crypto Provider" diff -Nru opensc-0.17.0/src/minidriver/opensc-minidriver.dll.manifest opensc-0.19.0/src/minidriver/opensc-minidriver.dll.manifest --- opensc-0.17.0/src/minidriver/opensc-minidriver.dll.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/minidriver/opensc-minidriver.dll.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/minidriver/versioninfo-minidriver.rc.in opensc-0.19.0/src/minidriver/versioninfo-minidriver.rc.in --- opensc-0.17.0/src/minidriver/versioninfo-minidriver.rc.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/minidriver/versioninfo-minidriver.rc.in 2018-09-13 11:47:21.000000000 +0000 @@ -1,11 +1,14 @@ #include #define IDC_STATIC -1 -/* defined twice: in versioninfo-minidriver.rc.in and in minidriver.c */ -#define IDD_PINPAD 101 -#define IDI_LOGO 102 -#define IDC_PINPAD_TEXT 1001 -#define IDC_PINPAD_ICON 1000 +/* defined twice: in resource file and in source code */ +#define IDI_SMARTCARD 102 + +#ifndef __MINGW32__ +IDI_SMARTCARD ICON "..\\..\\win32\\DDORes.dll_14_2302.ico" +#else +IDI_SMARTCARD ICON "../../win32/DDORes.dll_14_2302.ico" +#endif VS_VERSION_INFO VERSIONINFO FILEVERSION @OPENSC_VERSION_MAJOR@,@OPENSC_VERSION_MINOR@,@OPENSC_VERSION_FIX@,@OPENSC_VERSION_REVISION@ @@ -42,19 +45,3 @@ VALUE "Translation", 0x409, 1200 END END - -IDD_PINPAD DIALOGEX 0, 0, 309, 71 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION -CAPTION "PIN Entry Required" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Please enter PIN on PINPAD",IDC_STATIC,46,9,256,31 - ICON "",IDC_PINPAD_ICON,6,11,20,20 - LTEXT "This window will be closed automatically after the PIN has been submitted on the PINPAD or if the PINPAD timeout occurs (in general 30 seconds).",IDC_STATIC,7,46,298,19 -END - -#ifndef __MINGW32__ -IDI_LOGO ICON "..\\..\\win32\\OpenSC.ico" -#else -IDI_LOGO ICON "../../win32/OpenSC.ico" -#endif diff -Nru opensc-0.17.0/src/pkcs11/framework-pkcs15.c opensc-0.19.0/src/pkcs11/framework-pkcs15.c --- opensc-0.17.0/src/pkcs11/framework-pkcs15.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/framework-pkcs15.c 2018-09-13 11:47:21.000000000 +0000 @@ -25,6 +25,7 @@ #include "libopensc/internal.h" #include "libopensc/asn1.h" #include "libopensc/cardctl.h" +#include "ui/notify.h" #include "common/compat_strnlen.h" #ifdef ENABLE_OPENSSL @@ -174,6 +175,7 @@ const CK_BYTE gostr3411_94_cryptopro_paramset_encoded_oid[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 }; const unsigned int gostr3411_94_cryptopro_paramset_oid[] = {1, 2, 643, 2, 2, 30, 1, (unsigned int)-1}; +#ifdef USE_PKCS15_INIT static const struct { const CK_BYTE *encoded_oid; const unsigned int encoded_oid_size; @@ -185,6 +187,7 @@ &gostr3411_94_cryptopro_paramset_oid[0], sizeof(gostr3411_94_cryptopro_paramset_oid)} }; +#endif static int __pkcs15_release_object(struct pkcs15_any_object *); static CK_RV register_mechanisms(struct sc_pkcs11_card *p11card); @@ -329,6 +332,12 @@ } } + if (idx == 0) { + /* send a notification only for the first application that's bound */ + sc_notify_id(p11card->card->ctx, &p11card->reader->atr, fw_data->p15_card, + NOTIFY_CARD_INSERTED); + } + return CKR_OK; } @@ -356,8 +365,20 @@ unlock_card(fw_data); - if (fw_data->p15_card) + if (fw_data->p15_card) { + if (idx == 0) { + int rc = sc_detect_card_presence(fw_data->p15_card->card->reader); + if (rc <= 0 || rc & SC_READER_CARD_CHANGED) { + /* send a notification only if the card was removed/changed + * and only for the first application that's unbound */ + sc_notify_id(fw_data->p15_card->card->ctx, + &fw_data->p15_card->card->reader->atr, + fw_data->p15_card, + NOTIFY_CARD_REMOVED); + } + } rv = sc_pkcs15_unbind(fw_data->p15_card); + } fw_data->p15_card = NULL; free(fw_data); @@ -604,7 +625,8 @@ cert->cert_data->subject, cert->cert_data->subject_len, &cn_oid, &cn_name, &cn_len); if (rv == SC_SUCCESS) { - sc_log(context, "pkcs15_cert_extract_label(): Name from DN is %s", cn_name); + sc_log(context, "pkcs15_cert_extract_label(): Name from DN is %.*s", + (unsigned int) cn_len, cn_name); cn_len = MIN(cn_len, SC_PKCS15_MAX_LABEL_SIZE-1); memcpy(cert->cert_p15obj->label, cn_name, cn_len); cert->cert_p15obj->label[cn_len] = '\0'; @@ -718,7 +740,7 @@ } else if (!(pubkey->emulated && (fw_data->p15_card->flags & SC_PKCS15_CARD_FLAG_EMULATED))) { sc_pkcs15_free_pubkey(p15_key); } - if (object->pub_data) { + if (object && object->pub_data) { if ((object->pub_data->alg_id)&&(object->pub_data->algorithm == SC_ALGORITHM_GOSTR3410)) object->pub_data->alg_id->params = &((object->pub_data->u).gostr3410.params); } @@ -734,7 +756,7 @@ __pkcs15_create_prkey_object(struct pkcs15_fw_data *fw_data, struct sc_pkcs15_object *prkey, struct pkcs15_any_object **prkey_object) { - struct pkcs15_prkey_object *object; + struct pkcs15_prkey_object *object = NULL; int rv; rv = __pkcs15_create_object(fw_data, (struct pkcs15_any_object **) &object, @@ -959,7 +981,7 @@ unsigned int i; struct pkcs15_fw_data *card_fw_data; CK_OBJECT_HANDLE handle = - (CK_OBJECT_HANDLE)obj; /* cast pointer to long, will truncate on Win64 */ + (CK_OBJECT_HANDLE)(uintptr_t)obj; /* cast pointer to long, will truncate on Win64 */ if (obj == NULL || slot == NULL) return; @@ -1022,8 +1044,9 @@ { struct pkcs15_slot_data *fw_data; struct sc_pkcs15_auth_info *pin_info = NULL; - char label[64]; + char label[(sizeof auth->label) + 10]; + sc_log(context, "Called"); pkcs15_init_token_info(p15card, &slot->token_info); slot->token_info.flags |= CKF_TOKEN_INITIALIZED; if (auth != NULL) @@ -1048,9 +1071,12 @@ pin_info = NULL; } else { - if (auth->label[0]) - snprintf(label, sizeof(label), "%.*s (%s)", (int) sizeof auth->label, auth->label, p15card->tokeninfo->label); + if (auth->label[0] && strncmp(auth->label, "PIN", 4) != 0) + snprintf(label, sizeof(label), "%.*s (%s)", + (int) sizeof(auth->label), auth->label, + p15card->tokeninfo->label); else + /* The PIN label is empty or says just non-useful "PIN" */ snprintf(label, sizeof(label), "%s", p15card->tokeninfo->label); slot->token_info.flags |= CKF_LOGIN_REQUIRED; } @@ -1211,6 +1237,7 @@ struct sc_pkcs15_object *out = NULL; int rv = SC_ERROR_OBJECT_NOT_FOUND; + /* please keep me in sync with md_get_pin_by_role() in minidriver */ if (!strcmp(name, "UserPIN")) { /* Try to get 'global' PIN; if no, get the 'local' one */ rv = sc_pkcs15_find_pin_by_flags(p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL, @@ -1300,7 +1327,7 @@ pkcs15_add_object(slot, obj, NULL); } else { - sc_log(context, "Slot:%p Object %d skeeped", slot, i); + sc_log(context, "Slot:%p Object %d skipped", slot, i); continue; } @@ -1339,7 +1366,7 @@ if (obj->p15_object->flags & SC_PKCS15_CO_FLAG_PRIVATE) continue; /* PKCS#15 4.1.3 is a little vague, but implies if not PRIVATE it is readable - * even if there is an auth_id to allow writting for example. + * even if there is an auth_id to allow writing for example. * See bug issue #291 * treat pubkey and cert as readable.a */ @@ -1591,7 +1618,16 @@ } } - rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + if (userType == CKU_CONTEXT_SPECIFIC) { + int auth_meth_saved = pin_info->auth_method; + + sc_log(context, "Setting SC_AC_CONTEXT_SPECIFIC"); + pin_info->auth_method = SC_AC_CONTEXT_SPECIFIC; + rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + pin_info->auth_method = auth_meth_saved; + } else + rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + sc_log(context, "PKCS15 verify PIN returned %d", rc); if (rc != SC_SUCCESS) @@ -1770,14 +1806,13 @@ { struct sc_pkcs11_card *p11card = slot->p11card; struct sc_cardctl_pkcs11_init_token args; - scconf_block *atrblock = NULL; + scconf_block *conf_block = NULL; int rc, enable_InitToken = 0; CK_RV rv; sc_log(context, "Get 'enable-InitToken' card configuration option"); - atrblock = sc_match_atr_block(p11card->card->ctx, NULL, &p11card->reader->atr); - if (atrblock) - enable_InitToken = scconf_get_bool(atrblock, "pkcs11_enable_InitToken", 0); + conf_block = sc_get_conf_block(p11card->card->ctx, "framework", "pkcs15", 1); + enable_InitToken = scconf_get_bool(conf_block, "pkcs11_enable_InitToken", 0); memset(&args, 0, sizeof(args)); args.so_pin = pPin; @@ -1821,7 +1856,7 @@ if (p15card) { sc_log(context, "pkcs15init erase card"); - rc = sc_pkcs15init_erase_card(p15card, profile, NULL); + sc_pkcs15init_erase_card(p15card, profile, NULL); sc_log(context, "pkcs15init unbind"); sc_pkcs15init_unbind(profile); @@ -2253,11 +2288,11 @@ key_obj->flags = 2; /* TODO not sure what these mean */ - skey_info = calloc(1, sizeof(sc_pkcs15_skey_info_t)); + skey_info = calloc(1, sizeof(sc_pkcs15_skey_info_t)); if (skey_info == NULL) { rv = CKR_HOST_MEMORY; goto out; - } + } key_obj->data = skey_info; skey_info->usage = args.usage; skey_info->native = 0; /* card can not use this */ @@ -2265,8 +2300,8 @@ skey_info->key_type = key_type; /* PKCS#11 CKK_* */ skey_info->data.value = args.key.data; skey_info->data.len = args.key.data_len; - skey_info->value_len = args.value_len; /* callers prefered length */ - + skey_info->value_len = args.value_len; /* callers preferred length */ + args.key.data = NULL; } else { #if 1 @@ -2290,6 +2325,7 @@ rv = CKR_OK; out: + free(args.key.data); /* if allocated */ free(key_obj); return rv; } @@ -2335,7 +2371,6 @@ return CKR_ATTRIBUTE_VALUE_INVALID; } - rv = CKR_OK; while (ulCount--) { CK_ATTRIBUTE_PTR attr = pTemplate++; sc_pkcs15_bignum_t *bn = NULL; @@ -2429,7 +2464,6 @@ if (cert_type != CKC_X_509) return CKR_ATTRIBUTE_VALUE_INVALID; - rv = CKR_OK; while (ulCount--) { CK_ATTRIBUTE_PTR attr = pTemplate++; @@ -2438,7 +2472,7 @@ case CKA_CLASS: break; case CKA_PRIVATE: - rv = attr_extract(attr, &bValue, NULL); + attr_extract(attr, &bValue, NULL); if (bValue) { rv = CKR_TEMPLATE_INCONSISTENT; goto out; @@ -2505,7 +2539,6 @@ if (!fw_data) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_CreateObject"); - rv = CKR_OK; while (ulCount--) { CK_ATTRIBUTE_PTR attr = pTemplate++; @@ -2514,7 +2547,7 @@ case CKA_CLASS: break; case CKA_PRIVATE: - rv = attr_extract(attr, &bValue, NULL); + attr_extract(attr, &bValue, NULL); if (bValue) { pin = slot_data_auth_info(slot->fw_data); if (pin == NULL) { @@ -2606,7 +2639,7 @@ /* TODO The previous code does not check for CKA_TOKEN=TRUE * PKCS#11 CreatObject examples always have it, but * PKCS#11 says the default is false. - * for backward compatability, will default to TRUE + * for backward compatibility, will default to TRUE */ /* Dont need profile id creating session only objects */ if (_token == TRUE) { @@ -3018,7 +3051,7 @@ return sc_to_cryptoki_error(rv, "C_DestroyObject"); /* Oppose to pkcs15_add_object */ - --any_obj->refcount; /* correct refcont */ + --any_obj->refcount; /* correct refcount */ list_delete(&session->slot->objects, any_obj); /* Delete object in pkcs15 */ rv = __pkcs15_delete_object(fw_data, any_obj); @@ -3102,7 +3135,7 @@ rv = sc_pkcs15init_delete_object(fw_data->p15_card, profile, obj->base.p15_object); if (rv >= 0) { /* Oppose to pkcs15_add_object */ - --any_obj->refcount; /* correct refcont */ + --any_obj->refcount; /* correct refcount */ list_delete(&session->slot->objects, any_obj); /* Delete object in pkcs15 */ rv = __pkcs15_delete_object(fw_data, any_obj); @@ -3300,14 +3333,15 @@ *(CK_CERTIFICATE_TYPE*)attr->pValue = CKC_X_509; break; case CKA_ID: - if (cert->cert_info->authority && sc_pkcs11_conf.zero_ckaid_for_ca_certs) { +#ifdef ZERO_CKAID_FOR_CA_CERTS + if (cert->cert_info->authority) { check_attribute_buffer(attr, 1); *(unsigned char*)attr->pValue = 0; + break; } - else { - check_attribute_buffer(attr, cert->cert_info->id.len); - memcpy(attr->pValue, cert->cert_info->id.value, cert->cert_info->id.len); - } +#endif + check_attribute_buffer(attr, cert->cert_info->id.len); + memcpy(attr->pValue, cert->cert_info->id.value, cert->cert_info->id.len); break; case CKA_TRUSTED: check_attribute_buffer(attr, sizeof(CK_BBOOL)); @@ -3646,6 +3680,58 @@ } + +static CK_RV +pkcs15_prkey_check_pss_param(CK_MECHANISM_PTR pMechanism, CK_ULONG hlen) +{ + CK_RSA_PKCS_PSS_PARAMS *pss_param; + + if (pMechanism->pParameter == NULL) + return CKR_OK; // Support applications that don't provide CK_RSA_PKCS_PSS_PARAMS + + if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) + return CKR_MECHANISM_PARAM_INVALID; + + pss_param = (CK_RSA_PKCS_PSS_PARAMS *)pMechanism->pParameter; + + // Hash parameter must match mechanisms or length of data supplied for CKM_RSA_PKCS_PSS + switch(pss_param->hashAlg) { + case CKM_SHA_1: + if (hlen != 20) + return CKR_MECHANISM_PARAM_INVALID; + break; + case CKM_SHA256: + if (hlen != 32) + return CKR_MECHANISM_PARAM_INVALID; + break; + default: + return CKR_MECHANISM_PARAM_INVALID; + } + + // SmartCards typically only support MGFs based on the same hash as the + // message digest + switch(pss_param->mgf) { + case CKG_MGF1_SHA1: + if (hlen != 20) + return CKR_MECHANISM_PARAM_INVALID; + break; + case CKG_MGF1_SHA256: + if (hlen != 32) + return CKR_MECHANISM_PARAM_INVALID; + break; + default: + return CKR_MECHANISM_PARAM_INVALID; + } + + // SmartCards typically support only a salt length equal to the hash length + if (pss_param->sLen != hlen) + return CKR_MECHANISM_PARAM_INVALID; + + return CKR_OK; +} + + + static CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData, @@ -3694,6 +3780,30 @@ case CKM_SHA512_RSA_PKCS: flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA512; break; + case CKM_RSA_PKCS_PSS: + rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); + + if (rv != CKR_OK) + return rv; + + flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_NONE; + break; + case CKM_SHA1_RSA_PKCS_PSS: + rv = pkcs15_prkey_check_pss_param(pMechanism, 20); + + if (rv != CKR_OK) + return rv; + + flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA1; + break; + case CKM_SHA256_RSA_PKCS_PSS: + rv = pkcs15_prkey_check_pss_param(pMechanism, 32); + + if (rv != CKR_OK) + return rv; + + flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA256; + break; case CKM_RIPEMD160_RSA_PKCS: flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_RIPEMD160; break; @@ -3729,7 +3839,7 @@ if (rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path) { /* If private key PKCS#15 object do not have 'path' attribute, * and if PKCS#11 login session is not locked, - * the compute signature could fail because of concurent access to the card + * the compute signature could fail because of concurrent access to the card * by other application that could change the current DF. * In this particular case try to 'reselect' application DF. */ @@ -4602,7 +4712,18 @@ if (rc != SC_SUCCESS) return sc_to_cryptoki_error(rc, NULL); - check_attribute_buffer(attr, value_len); + if (attr->pValue == NULL_PTR) { + attr->ulValueLen = value_len; + free(value); + return CKR_OK; + } + if (attr->ulValueLen < value_len) { + attr->ulValueLen = value_len; + free(value); + return CKR_BUFFER_TOO_SMALL; + } + attr->ulValueLen = value_len; + memcpy(attr->pValue, value, value_len); free(value); return CKR_OK; @@ -4890,7 +5011,7 @@ #ifdef ENABLE_OPENSSL /* all our software hashes are in OpenSSL */ - /* Only if card did not lists the hashs, will we + /* Only if card did not list the hashes, will we * help it a little, by adding all the OpenSSL hashes * that have PKCS#11 mechanisms. */ @@ -4950,6 +5071,26 @@ /* TODO support other padding mechanisms */ + if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) { + mech_info.flags &= ~(CKF_DECRYPT|CKF_VERIFY); + + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL); + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { + rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { + rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt); + if (rc != CKR_OK) + return rc; + } + } + if (rsa_flags & SC_ALGORITHM_ONBOARD_KEY_GEN) { mech_info.flags = CKF_GENERATE_KEY_PAIR; mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info, CKK_RSA, NULL, NULL); diff -Nru opensc-0.17.0/src/pkcs11/Makefile.am opensc-0.19.0/src/pkcs11/Makefile.am --- opensc-0.17.0/src/pkcs11/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,7 @@ include $(top_srcdir)/win32/ltrc.inc MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-pkcs11.rc $(srcdir)/versioninfo-pkcs11-spy.rc -EXTRA_DIST = Makefile.mak versioninfo-pkcs11.rc.in versioninfo-pkcs11-spy.rc.in opensc-pkcs11.pc.in +EXTRA_DIST = Makefile.mak versioninfo-pkcs11.rc.in versioninfo-pkcs11-spy.rc.in opensc-pkcs11.pc.in opensc-pkcs11.dll.manifest onepin-opensc-pkcs11.dll.manifest lib_LTLIBRARIES = opensc-pkcs11.la pkcs11-spy.la onepin-opensc-pkcs11.la diff -Nru opensc-0.17.0/src/pkcs11/Makefile.mak opensc-0.19.0/src/pkcs11/Makefile.mak --- opensc-0.17.0/src/pkcs11/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -9,7 +9,16 @@ debug.obj pkcs11-display.obj versioninfo-pkcs11.res OBJECTS3 = pkcs11-spy.obj pkcs11-display.obj versioninfo-pkcs11-spy.res -LIBS = $(TOPDIR)\src\libopensc\opensc_a.lib $(TOPDIR)\src\pkcs15init\pkcs15init.lib +LIBS = $(TOPDIR)\src\libopensc\opensc_a.lib \ + $(TOPDIR)\src\pkcs15init\pkcs15init.lib \ + $(TOPDIR)\src\scconf\scconf.lib \ + $(TOPDIR)\src\common\common.lib \ + $(TOPDIR)\src\common\libscdl.lib \ + $(TOPDIR)\src\ui\strings.lib \ + $(TOPDIR)\src\ui\notify.lib \ + $(TOPDIR)\src\sm\libsmiso.lib \ + $(TOPDIR)\src\sm\libsmeac.lib \ + $(TOPDIR)\src\pkcs15init\pkcs15init.lib LIBS3 = $(TOPDIR)\src\common\libpkcs11.lib $(TOPDIR)\src\common\libscdl.lib $(TOPDIR)\src\common\common.lib all: $(TARGET1) $(TARGET2) $(TARGET3) @@ -17,15 +26,15 @@ !INCLUDE $(TOPDIR)\win32\Make.rules.mak $(TARGET1): $(OBJECTS) $(LIBS) - link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.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) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.lib if EXIST $(TARGET2).manifest mt -manifest $(TARGET2).manifest -outputresource:$(TARGET2);2 $(TARGET3): $(OBJECTS3) $(LIBS3) - link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib advapi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENSSL_LIB) gdi32.lib advapi32.lib if EXIST $(TARGET3).manifest mt -manifest $(TARGET3).manifest -outputresource:$(TARGET3);2 diff -Nru opensc-0.17.0/src/pkcs11/mechanism.c opensc-0.19.0/src/pkcs11/mechanism.c --- opensc-0.17.0/src/pkcs11/mechanism.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/mechanism.c 2018-09-13 11:47:21.000000000 +0000 @@ -847,7 +847,7 @@ /* Get the size of the data to be returned * If the card could derive a key an leave it on the card * then no data is returned. - * If the card returns the data, we will store it in the sercet key CKA_VALUE + * If the card returns the data, we will store it in the secret key CKA_VALUE */ ulDataLen = 0; @@ -867,7 +867,7 @@ goto out; } - /* Now do the actuall derivation */ + /* Now do the actual derivation */ rv = operation->type->derive(operation, basekey, pMechanism->pParameter, pMechanism->ulParameterLen, @@ -1041,6 +1041,7 @@ sc_pkcs11_mechanism_type_t *hash_type, *new_type; struct hash_signature_info *info; CK_MECHANISM_INFO mech_info = sign_type->mech_info; + CK_RV rv; if (!(hash_type = sc_pkcs11_find_mechanism(p11card, hash_mech, CKF_DIGEST))) return CKR_MECHANISM_INVALID; @@ -1059,8 +1060,16 @@ info->hash_mech = hash_mech; new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info, free_info); - - if (!new_type) + if (!new_type) { + free_info(info); return CKR_HOST_MEMORY; - return sc_pkcs11_register_mechanism(p11card, new_type); + } + + rv = sc_pkcs11_register_mechanism(p11card, new_type); + if (CKR_OK != rv) { + new_type->free_mech_data(new_type->mech_data); + free(new_type); + } + + return rv; } diff -Nru opensc-0.17.0/src/pkcs11/misc.c opensc-0.19.0/src/pkcs11/misc.c --- opensc-0.17.0/src/pkcs11/misc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/misc.c 2018-09-13 11:47:21.000000000 +0000 @@ -187,7 +187,7 @@ } if (pPin && ulPinLen) { - login->pPin = sc_mem_alloc_secure(context, (sizeof *pPin)*ulPinLen); + login->pPin = calloc((sizeof *pPin), ulPinLen); if (login->pPin == NULL) { goto err; } @@ -452,13 +452,11 @@ } else { conf->slots_per_card = 4; } - conf->hide_empty_tokens = 1; conf->atomic = 0; conf->lock_login = 0; conf->init_sloppy = 1; conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_NOT_ALLOWED; conf->create_puk_slot = 0; - conf->zero_ckaid_for_ca_certs = 0; conf->create_slots_flags = SC_PKCS11_SLOT_CREATE_ALL; conf_block = sc_get_conf_block(ctx, "pkcs11", NULL, 1); @@ -468,7 +466,6 @@ /* contains the defaults, if there is a "pkcs11" config block */ conf->max_virtual_slots = scconf_get_int(conf_block, "max_virtual_slots", conf->max_virtual_slots); conf->slots_per_card = scconf_get_int(conf_block, "slots_per_card", conf->slots_per_card); - conf->hide_empty_tokens = scconf_get_bool(conf_block, "hide_empty_tokens", conf->hide_empty_tokens); conf->atomic = scconf_get_bool(conf_block, "atomic", conf->atomic); if (conf->atomic) conf->lock_login = 1; @@ -484,7 +481,6 @@ conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_SO_LOGGED_INITPIN; conf->create_puk_slot = scconf_get_bool(conf_block, "create_puk_slot", conf->create_puk_slot); - conf->zero_ckaid_for_ca_certs = scconf_get_bool(conf_block, "zero_ckaid_for_ca_certs", conf->zero_ckaid_for_ca_certs); create_slots_for_pins = (char *)scconf_get_str(conf_block, "create_slots_for_pins", "all"); conf->create_slots_flags = 0; @@ -499,12 +495,12 @@ conf->create_slots_flags |= SC_PKCS11_SLOT_CREATE_ALL; op = strtok(NULL, " ,"); } - free(tmp); + free(tmp); sc_log(ctx, "PKCS#11 options: max_virtual_slots=%d slots_per_card=%d " - "hide_empty_tokens=%d lock_login=%d atomic=%d pin_unblock_style=%d " - "zero_ckaid_for_ca_certs=%d create_slots_flags=0x%X", + "lock_login=%d atomic=%d pin_unblock_style=%d " + "create_slots_flags=0x%X", conf->max_virtual_slots, conf->slots_per_card, - conf->hide_empty_tokens, conf->lock_login, conf->atomic, conf->pin_unblock_style, - conf->zero_ckaid_for_ca_certs, conf->create_slots_flags); + conf->lock_login, conf->atomic, conf->pin_unblock_style, + conf->create_slots_flags); } diff -Nru opensc-0.17.0/src/pkcs11/onepin-opensc-pkcs11.dll.manifest opensc-0.19.0/src/pkcs11/onepin-opensc-pkcs11.dll.manifest --- opensc-0.17.0/src/pkcs11/onepin-opensc-pkcs11.dll.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/onepin-opensc-pkcs11.dll.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/pkcs11/opensc-pkcs11.dll.manifest opensc-0.19.0/src/pkcs11/opensc-pkcs11.dll.manifest --- opensc-0.17.0/src/pkcs11/opensc-pkcs11.dll.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/opensc-pkcs11.dll.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/pkcs11/openssl.c opensc-0.19.0/src/pkcs11/openssl.c --- opensc-0.17.0/src/pkcs11/openssl.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/openssl.c 2018-09-13 11:47:21.000000000 +0000 @@ -28,6 +28,7 @@ #include #include #include +#include #if OPENSSL_VERSION_NUMBER >= 0x10000000L #include #include /* for OPENSSL_NO_* */ @@ -329,7 +330,7 @@ EVP_PKEY_CTX *pkey_ctx = NULL; EC_POINT *P; BIGNUM *X, *Y; - ASN1_OCTET_STRING *octet; + ASN1_OCTET_STRING *octet = NULL; const EC_GROUP *group = NULL; char paramset[2] = "A"; int r = -1, ret_vrf = 0; diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-display.c opensc-0.19.0/src/pkcs11/pkcs11-display.c --- opensc-0.17.0/src/pkcs11/pkcs11-display.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-display.c 2018-09-13 11:47:21.000000000 +0000 @@ -521,6 +521,14 @@ { CKM_VENDOR_DEFINED , "CKM_VENDOR_DEFINED " } }; +static enum_specs ck_mgf_s[] = { + { CKG_MGF1_SHA1 , "CKG_MGF1_SHA1 " }, + { CKG_MGF1_SHA224, "CKG_MGF1_SHA224" }, + { CKG_MGF1_SHA256, "CKG_MGF1_SHA256" }, + { CKG_MGF1_SHA384, "CKG_MGF1_SHA384" }, + { CKG_MGF1_SHA512, "CKG_MGF1_SHA512" }, +}; + static enum_specs ck_err_s[] = { { CKR_OK, "CKR_OK" }, { CKR_CANCEL, "CKR_CANCEL" }, @@ -630,6 +638,7 @@ { KEY_T, ck_key_s, sizeof(ck_key_s) / SZ_SPECS, "CK_KEY_TYPE" }, { CRT_T, ck_crt_s, sizeof(ck_crt_s) / SZ_SPECS, "CK_CERTIFICATE_TYPE" }, { MEC_T, ck_mec_s, sizeof(ck_mec_s) / SZ_SPECS, "CK_MECHANISM_TYPE" }, + { MGF_T, ck_mgf_s, sizeof(ck_mgf_s) / SZ_SPECS, "CK_RSA_PKCS_MGF_TYPE"}, { USR_T, ck_usr_s, sizeof(ck_usr_s) / SZ_SPECS, "CK_USER_TYPE" }, { STA_T, ck_sta_s, sizeof(ck_sta_s) / SZ_SPECS, "CK_STATE" }, { RV_T, ck_err_s, sizeof(ck_err_s) / SZ_SPECS, "CK_RV" }, diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-display.h opensc-0.19.0/src/pkcs11/pkcs11-display.h --- opensc-0.17.0/src/pkcs11/pkcs11-display.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-display.h 2018-09-13 11:47:21.000000000 +0000 @@ -56,6 +56,7 @@ KEY_T, CRT_T, MEC_T, + MGF_T, USR_T, STA_T, RV_T diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-global.c opensc-0.19.0/src/pkcs11/pkcs11-global.c --- opensc-0.17.0/src/pkcs11/pkcs11-global.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-global.c 2018-09-13 11:47:21.000000000 +0000 @@ -35,6 +35,7 @@ #endif /* PKCS11_THREAD_LOCKING */ #include "sc-pkcs11.h" +#include "ui/notify.h" #ifndef MODULE_APP_NAME #define MODULE_APP_NAME "opensc-pkcs11" @@ -237,6 +238,8 @@ return CKR_CRYPTOKI_ALREADY_INITIALIZED; } + sc_notify_init(); + rv = sc_pkcs11_init_lock((CK_C_INITIALIZE_ARGS_PTR) pInitArgs); if (rv != CKR_OK) goto out; @@ -264,7 +267,6 @@ list_attributes_seeker(&sessions, session_list_seeker); /* List of slots */ - list_init(&virtual_slots); if (0 != list_init(&virtual_slots)) { rv = CKR_HOST_MEMORY; goto out; @@ -301,6 +303,8 @@ if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD; + sc_notify_close(); + if (context == NULL) return CKR_CRYPTOKI_NOT_INITIALIZED; @@ -753,7 +757,7 @@ /* Shall be used in threaded environment, must use operating system locking */ global_locking = default_mutex_funcs; } else if (applock && !oslock) { - /* Shall be used in threaded envirnoment, must use app provided locking */ + /* Shall be used in threaded environment, must use app provided locking */ global_locking = args; } else if (!applock && !oslock) { /* Shall not be used in threaded environment, use operating system locking */ diff -Nru opensc-0.17.0/src/pkcs11/pkcs11.h opensc-0.19.0/src/pkcs11/pkcs11.h --- opensc-0.17.0/src/pkcs11/pkcs11.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11.h 2018-09-13 11:47:21.000000000 +0000 @@ -153,6 +153,8 @@ #define ck_mechanism_type_t CK_MECHANISM_TYPE +#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE + #define ck_mechanism _CK_MECHANISM #define parameter pParameter #define parameter_len ulParameterLen @@ -478,6 +480,8 @@ typedef unsigned long ck_mechanism_type_t; +typedef unsigned long int ck_rsa_pkcs_mgf_type_t; + #define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) #define CKM_RSA_PKCS (1UL) #define CKM_RSA_9796 (2UL) @@ -508,6 +512,8 @@ #define CKM_SHA256_RSA_PKCS_PSS (0x43UL) #define CKM_SHA384_RSA_PKCS_PSS (0x44UL) #define CKM_SHA512_RSA_PKCS_PSS (0x45UL) +#define CKM_SHA224_RSA_PKCS (0x46UL) +#define CKM_SHA224_RSA_PKCS_PSS (0x47UL) #define CKM_RC2_KEY_GEN (0x100UL) #define CKM_RC2_ECB (0x101UL) #define CKM_RC2_CBC (0x102UL) @@ -553,6 +559,9 @@ #define CKM_SHA256 (0x250UL) #define CKM_SHA256_HMAC (0x251UL) #define CKM_SHA256_HMAC_GENERAL (0x252UL) +#define CKM_SHA224 (0x255UL) +#define CKM_SHA224_HMAC (0x256UL) +#define CKM_SHA224_HMAC_GENERAL (0x257UL) #define CKM_SHA384 (0x260UL) #define CKM_SHA384_HMAC (0x261UL) #define CKM_SHA384_HMAC_GENERAL (0x262UL) @@ -755,6 +764,29 @@ unsigned char * pPublicData; } CK_ECDH1_DERIVE_PARAMS; +typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE; + +typedef struct CK_RSA_PKCS_OAEP_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_RSA_PKCS_OAEP_SOURCE_TYPE source; + void *pSourceData; + unsigned long ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef struct CK_RSA_PKCS_PSS_PARAMS { + ck_mechanism_type_t hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + unsigned long sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +#define CKG_MGF1_SHA1 (0x00000001UL) +#define CKG_MGF1_SHA224 (0x00000005UL) +#define CKG_MGF1_SHA256 (0x00000002UL) +#define CKG_MGF1_SHA384 (0x00000003UL) +#define CKG_MGF1_SHA512 (0x00000004UL) + +#define CKZ_DATA_SPECIFIED (0x00000001UL) typedef unsigned long ck_rv_t; @@ -820,7 +852,7 @@ unsigned char *operation_state, unsigned long operation_state_len, ck_object_handle_t encryption_key, - ck_object_handle_t authentiation_key)); + ck_object_handle_t authentication_key)); _CK_DECLARE_FUNCTION (C_Login, (ck_session_handle_t session, ck_user_type_t user_type, unsigned char *pin, unsigned long pin_len)); @@ -1292,6 +1324,8 @@ typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; +typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR; + typedef struct ck_mechanism CK_MECHANISM; typedef struct ck_mechanism *CK_MECHANISM_PTR; @@ -1362,6 +1396,8 @@ #undef ck_mechanism_type_t +#undef ck_rsa_pkcs_mgf_type_t + #undef ck_mechanism #undef parameter #undef parameter_len diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-object.c opensc-0.19.0/src/pkcs11/pkcs11-object.c --- opensc-0.17.0/src/pkcs11/pkcs11-object.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-object.c 2018-09-13 11:47:21.000000000 +0000 @@ -1152,6 +1152,7 @@ } sc_pkcs11_unlock(); + sc_log(context, "C_GenerateRandom() = %s", lookup_enum ( RV_T, rv )); return rv; } diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-opensc.h opensc-0.19.0/src/pkcs11/pkcs11-opensc.h --- opensc-0.17.0/src/pkcs11/pkcs11-opensc.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-opensc.h 2018-09-13 11:47:21.000000000 +0000 @@ -3,12 +3,21 @@ /* OpenSC specific extensions */ /* + * define OpenSC specific Vendor Defined extensions + * to make unique OpenSC flags, attributes, mechanisms, etc. + * + * Netscape used NSSCK_VENDOR_NSS 0x4E534350 "NSCP" + */ + +#define SC_VENDOR_DEFINED 0x4F534300 /* OSC */ + +/* * In PKCS#11 there is no CKA_ attribute dedicated to the NON-REPUDIATION flag. - * We need this flag in PKCS#15/libopensc to make dinstinction between + * We need this flag in PKCS#15/libopensc to make distinction between * 'signature' and 'qualified signature' key slots. */ -#define CKA_OPENSC_NON_REPUDIATION (CKA_VENDOR_DEFINED | 1UL) +#define CKA_OPENSC_NON_REPUDIATION (CKA_VENDOR_DEFINED | SC_VENDOR_DEFINED | 1UL) -#define CKA_SPKI (CKA_VENDOR_DEFINED | 2UL) +#define CKA_SPKI (CKA_VENDOR_DEFINED | SC_VENDOR_DEFINED | 2UL) #endif diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-session.c opensc-0.19.0/src/pkcs11/pkcs11-session.c --- opensc-0.17.0/src/pkcs11/pkcs11-session.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-session.c 2018-09-13 11:47:21.000000000 +0000 @@ -61,7 +61,7 @@ if (rv != CKR_OK) goto out; - /* Check that no conflictions sessions exist */ + /* Check that no conflicting sessions exist */ if (!(flags & CKF_RW_SESSION) && (slot->login_user == CKU_SO)) { rv = CKR_SESSION_READ_WRITE_SO_EXISTS; goto out; diff -Nru opensc-0.17.0/src/pkcs11/pkcs11-spy.c opensc-0.19.0/src/pkcs11/pkcs11-spy.c --- opensc-0.17.0/src/pkcs11/pkcs11-spy.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/pkcs11-spy.c 2018-09-13 11:47:21.000000000 +0000 @@ -50,7 +50,7 @@ /* Spy module output */ static FILE *spy_output = NULL; -/* Inits the spy. If successfull, po != NULL */ +/* Inits the spy. If successful, po != NULL */ static CK_RV init_spy(void) { @@ -153,7 +153,7 @@ #ifdef _WIN32 if (!spy_output) { - /* try for the machine version first, as we may be runing + /* try for the machine version first, as we may be running * without a user during login */ rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\PKCS11-Spy", 0, KEY_QUERY_VALUE, &hKey ); @@ -172,7 +172,7 @@ } } - if( (rc == ERROR_SUCCESS) && (temp_len < PATH_MAX) ) + if( (rc == ERROR_SUCCESS) && (temp_len < PATH_MAX) ) output = temp_path; RegCloseKey( hKey ); } @@ -188,7 +188,7 @@ module = getenv("PKCS11SPY"); #ifdef _WIN32 if (!module) { - /* try for the machine version first, as we may be runing + /* try for the machine version first, as we may be running * without a user during login */ rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\PKCS11-Spy", @@ -844,6 +844,26 @@ enter("C_DecryptInit"); spy_dump_ulong_in("hSession", hSession); fprintf(spy_output, "pMechanism->type=%s\n", lookup_enum(MEC_T, pMechanism->mechanism)); + switch (pMechanism->mechanism) { + case CKM_RSA_PKCS_OAEP: + if (pMechanism->pParameter != NULL) { + CK_RSA_PKCS_OAEP_PARAMS *param = + (CK_RSA_PKCS_OAEP_PARAMS *) pMechanism->pParameter; + fprintf(spy_output, "pMechanism->pParameter->hashAlg=%s\n", + lookup_enum(MEC_T, param->hashAlg)); + fprintf(spy_output, "pMechanism->pParameter->mgf=%s\n", + lookup_enum(MGF_T, param->mgf)); + fprintf(spy_output, "pMechanism->pParameter->source=%lu\n", param->source); + spy_dump_string_out("pSourceData[ulSourceDalaLen]", + param->pSourceData, param->ulSourceDataLen); + } else { + fprintf(spy_output, "Parameters block for %s is empty...\n", + lookup_enum(MEC_T, pMechanism->mechanism)); + } + break; + default: + break; + } spy_dump_ulong_in("hKey", hKey); rv = po->C_DecryptInit(hSession, pMechanism, hKey); return retne(rv); @@ -969,6 +989,27 @@ enter("C_SignInit"); spy_dump_ulong_in("hSession", hSession); fprintf(spy_output, "pMechanism->type=%s\n", lookup_enum(MEC_T, pMechanism->mechanism)); + switch (pMechanism->mechanism) { + case CKM_RSA_PKCS_PSS: + case CKM_SHA1_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS_PSS: + case CKM_SHA384_RSA_PKCS_PSS: + case CKM_SHA512_RSA_PKCS_PSS: + if (pMechanism->pParameter != NULL) { + CK_RSA_PKCS_PSS_PARAMS *param = + (CK_RSA_PKCS_PSS_PARAMS *) pMechanism->pParameter; + fprintf(spy_output, "pMechanism->pParameter->hashAlg=%s\n", + lookup_enum(MEC_T, param->hashAlg)); + fprintf(spy_output, "pMechanism->pParameter->mgf=%s\n", + lookup_enum(MGF_T, param->mgf)); + fprintf(spy_output, "pMechanism->pParameter->sLen=%lu\n", + param->sLen); + } else { + fprintf(spy_output, "Parameters block for %s is empty...\n", + lookup_enum(MEC_T, pMechanism->mechanism)); + } + break; + } spy_dump_ulong_in("hKey", hKey); rv = po->C_SignInit(hSession, pMechanism, hKey); return retne(rv); diff -Nru opensc-0.17.0/src/pkcs11/sc-pkcs11.h opensc-0.19.0/src/pkcs11/sc-pkcs11.h --- opensc-0.17.0/src/pkcs11/sc-pkcs11.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/sc-pkcs11.h 2018-09-13 11:47:21.000000000 +0000 @@ -36,12 +36,6 @@ extern "C" { #endif -#if defined(_WIN32) || defined(USE_CYGWIN) -#define PKCS11_DEFAULT_MODULE_NAME "opensc-pkcs11.dll" -#else -#define PKCS11_DEFAULT_MODULE_NAME "opensc-pkcs11.so" -#endif - #define SC_PKCS11_PIN_UNBLOCK_NOT_ALLOWED 0 #define SC_PKCS11_PIN_UNBLOCK_UNLOGGED_SETPIN 1 #define SC_PKCS11_PIN_UNBLOCK_SCONTEXT_SETPIN 2 @@ -77,13 +71,11 @@ unsigned int plug_and_play; unsigned int max_virtual_slots; unsigned int slots_per_card; - unsigned char hide_empty_tokens; unsigned char lock_login; unsigned char atomic; unsigned char init_sloppy; unsigned int pin_unblock_style; unsigned int create_puk_slot; - unsigned int zero_ckaid_for_ca_certs; unsigned int create_slots_flags; unsigned char ignore_pin_length; }; @@ -164,7 +156,7 @@ CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG); /* - * In future: functions to create new objects (ie. certificates, private keys) + * In future: functions to create new objects (i.e. certificates, private keys) */ CK_RV (*init_token)(struct sc_pkcs11_slot *, void *, CK_UTF8CHAR_PTR, CK_ULONG, @@ -225,7 +217,7 @@ sc_timestamp_t slot_state_expires; int fw_data_idx; /* Index of framework data */ - struct sc_app_info *app_info; /* Application assosiated to slot */ + struct sc_app_info *app_info; /* Application associated to slot */ list_t logins; /* tracks all calls to C_Login if atomic operations are requested */ int flags; }; diff -Nru opensc-0.17.0/src/pkcs11/slot.c opensc-0.19.0/src/pkcs11/slot.c --- opensc-0.17.0/src/pkcs11/slot.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs11/slot.c 2018-09-13 11:47:21.000000000 +0000 @@ -155,21 +155,6 @@ unsigned int i; CK_RV rv; - scconf_block *conf_block = NULL; - const scconf_list *list = NULL; - - conf_block = sc_get_conf_block(context, "pkcs11", NULL, 1); - if (conf_block != NULL) { - list = scconf_find_list(conf_block, "ignored_readers"); - while (list != NULL) { - if (strstr(reader->name, list->data) != NULL) { - sc_log(context, "Ignoring reader \'%s\' because of \'%s\'\n", reader->name, list->data); - return CKR_OK; - } - list = list->next; - } - } - for (i = 0; i < sc_pkcs11_conf.slots_per_card; i++) { rv = create_slot(reader); if (rv != CKR_OK) @@ -225,13 +210,12 @@ CK_RV card_detect(sc_reader_t *reader) { struct sc_pkcs11_card *p11card = NULL; + int free_p11card = 0; int rc; CK_RV rv; unsigned int i; int j; - rv = CKR_OK; - sc_log(context, "%s: Detecting smart card", reader->name); /* Check if someone inserted a card */ again: @@ -273,15 +257,17 @@ p11card = (struct sc_pkcs11_card *)calloc(1, sizeof(struct sc_pkcs11_card)); if (!p11card) return CKR_HOST_MEMORY; + free_p11card = 1; p11card->reader = reader; } if (p11card->card == NULL) { sc_log(context, "%s: Connecting ... ", reader->name); rc = sc_connect_card(reader, &p11card->card); - if (rc != SC_SUCCESS) { + if (rc != SC_SUCCESS) { sc_log(context, "%s: SC connect card error %i", reader->name, rc); - return sc_to_cryptoki_error(rc, NULL); + rv = sc_to_cryptoki_error(rc, NULL); + goto fail; } /* escape commands are only guaranteed to be working with a card @@ -310,8 +296,10 @@ if (frameworks[i]->bind != NULL) break; /*TODO: only first framework is used: pkcs15init framework is not reachable here */ - if (frameworks[i] == NULL) - return CKR_GENERAL_ERROR; + if (frameworks[i] == NULL) { + rv = CKR_GENERAL_ERROR; + goto fail; + } p11card->framework = frameworks[i]; @@ -319,12 +307,17 @@ sc_log(context, "%s: Detected framework %d. Creating tokens.", reader->name, i); /* Bind 'generic' application or (emulated?) card without applications */ if (app_generic || !p11card->card->app_count) { - scconf_block *atrblock = NULL; + scconf_block *conf_block = NULL; int enable_InitToken = 0; - atrblock = sc_match_atr_block(p11card->card->ctx, NULL, &p11card->reader->atr); - if (atrblock) - enable_InitToken = scconf_get_bool(atrblock, "pkcs11_enable_InitToken", 0); + conf_block = sc_match_atr_block(p11card->card->ctx, NULL, + &p11card->reader->atr); + if (!conf_block) /* check default block */ + conf_block = sc_get_conf_block(context, + "framework", "pkcs15", 1); + + enable_InitToken = scconf_get_bool(conf_block, + "pkcs11_enable_InitToken", 0); sc_log(context, "%s: Try to bind 'generic' token.", reader->name); rv = frameworks[i]->bind(p11card, app_generic); @@ -336,7 +329,7 @@ sc_log(context, "%s: cannot bind 'generic' token: rv 0x%lX", reader->name, rv); - return rv; + goto fail; } sc_log(context, "%s: Creating 'generic' token.", reader->name); @@ -345,7 +338,7 @@ sc_log(context, "%s: create 'generic' token error 0x%lX", reader->name, rv); - return rv; + goto fail; } } @@ -371,13 +364,24 @@ sc_log(context, "%s: create %s token error 0x%lX", reader->name, app_name, rv); - return rv; + goto fail; } } } sc_log(context, "%s: Detection ended", reader->name); return CKR_OK; + +fail: + if (free_p11card) { + if (p11card->card != NULL) + sc_disconnect_card(p11card->card); + if (p11card->framework) + p11card->framework->unbind(p11card); + free(p11card); + } + + return rv; } diff -Nru opensc-0.17.0/src/pkcs15init/ias_adele_admin1.profile opensc-0.19.0/src/pkcs15init/ias_adele_admin1.profile --- opensc-0.17.0/src/pkcs15init/ias_adele_admin1.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/ias_adele_admin1.profile 2018-09-13 11:47:21.000000000 +0000 @@ -141,7 +141,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/ias_adele_admin2.profile opensc-0.19.0/src/pkcs15init/ias_adele_admin2.profile --- opensc-0.17.0/src/pkcs15init/ias_adele_admin2.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/ias_adele_admin2.profile 2018-09-13 11:47:21.000000000 +0000 @@ -10,7 +10,7 @@ pin-encoding = ascii-numeric; pin-pad-char = 0xFF; - # Delete or not the public key when inconporating the + # Delete or not the public key when incorporating the # corresponding certificate. keep-public-key = yes; # yes/no } @@ -138,7 +138,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/ias_adele_common.profile opensc-0.19.0/src/pkcs15init/ias_adele_common.profile --- opensc-0.17.0/src/pkcs15init/ias_adele_common.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/ias_adele_common.profile 2018-09-13 11:47:21.000000000 +0000 @@ -134,7 +134,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/iasecc_admin_eid.profile opensc-0.19.0/src/pkcs15init/iasecc_admin_eid.profile --- opensc-0.17.0/src/pkcs15init/iasecc_admin_eid.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/iasecc_admin_eid.profile 2018-09-13 11:47:21.000000000 +0000 @@ -54,7 +54,7 @@ reference = 2 } -# CHV5 used for Oberthur's specifique access condition "PIN or SOPIN" +# CHV5 used for Oberthur's specific access condition "PIN or SOPIN" # Any value for this pin can given, when the OpenSC tools are asking for. # Additional filesystem info. @@ -141,7 +141,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/iasecc_generic_oberthur.profile opensc-0.19.0/src/pkcs15init/iasecc_generic_oberthur.profile --- opensc-0.17.0/src/pkcs15init/iasecc_generic_oberthur.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/iasecc_generic_oberthur.profile 2018-09-13 11:47:21.000000000 +0000 @@ -136,7 +136,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/iasecc_generic_pki.profile opensc-0.19.0/src/pkcs15init/iasecc_generic_pki.profile --- opensc-0.17.0/src/pkcs15init/iasecc_generic_pki.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/iasecc_generic_pki.profile 2018-09-13 11:47:21.000000000 +0000 @@ -54,7 +54,7 @@ reference = 2 } -# CHV5 used for Oberthur's specifique access condition "PIN or SOPIN" +# CHV5 used for Oberthur's specific access condition "PIN or SOPIN" # Any value for this pin can given, when the OpenSC tools are asking for. # Additional filesystem info. @@ -139,7 +139,7 @@ # Private DES keys BSO private-des { size = 24; # 192 bits - # READ acl used insted of DECIPHER/ENCIPHER/CHECKSUM + # READ acl used instead of DECIPHER/ENCIPHER/CHECKSUM } # Private data diff -Nru opensc-0.17.0/src/pkcs15init/iasecc.profile opensc-0.19.0/src/pkcs15init/iasecc.profile --- opensc-0.17.0/src/pkcs15init/iasecc.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/iasecc.profile 2018-09-13 11:47:21.000000000 +0000 @@ -52,7 +52,7 @@ reference = 2 } -# CHV5 used for Oberthur's specifique access condition "PIN or SOPIN" +# CHV5 used for Oberthur's specific access condition "PIN or SOPIN" # Any value for this pin can given, when the OpenSC tools are asking for. # Additional filesystem info. diff -Nru opensc-0.17.0/src/pkcs15init/Makefile.am opensc-0.19.0/src/pkcs15init/Makefile.am --- opensc-0.17.0/src/pkcs15init/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -32,7 +32,7 @@ openpgp.profile sc-hsm.profile \ isoApplet.profile gids.profile -AM_CPPFLAGS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\" \ +AM_CPPFLAGS = -D'SC_PKCS15_PROFILE_DIRECTORY="$(pkgdatadir)"' \ -I$(top_srcdir)/src AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) diff -Nru opensc-0.17.0/src/pkcs15init/oberthur.profile opensc-0.19.0/src/pkcs15init/oberthur.profile --- opensc-0.17.0/src/pkcs15init/oberthur.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/oberthur.profile 2018-09-13 11:47:21.000000000 +0000 @@ -42,7 +42,7 @@ reference = 4 } -# CHV5 used for Oberthur's specifique access condition "PIN or SOPIN" +# CHV5 used for Oberthur's specific access condition "PIN or SOPIN" # Any value for this pin can given, when the OpenSC tools are asking for. # Additional filesystem info. @@ -84,7 +84,7 @@ file-id = 4000; type = internal-ef; size = 24; # 192 bits - # READ acl used insted of DECRYPT/ENCRYPT/CHECKSUM + # READ acl used instead of DECRYPT/ENCRYPT/CHECKSUM ACL = UPDATE=CHV1, READ=CHV1; } diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-asepcos.c opensc-0.19.0/src/pkcs15init/pkcs15-asepcos.c --- opensc-0.17.0/src/pkcs15init/pkcs15-asepcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-asepcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -101,7 +101,7 @@ * - use EF(DIR) to get the DF of the OpenSC * pkcs15 application. */ - /* Check wether a transport exists and verify it if present */ + /* Check whether a transport exists and verify it if present */ p15card->opts.use_pin_cache = 1; r = asepcos_check_verify_tpin(profile, p15card); @@ -137,7 +137,7 @@ sc_context_t *ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); - /* Check wether a transport exists and verify it if present */ + /* Check whether a transport exists and verify it if present */ r = asepcos_check_verify_tpin(profile, p15card); if (r != SC_SUCCESS) return r; @@ -367,7 +367,7 @@ r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_CREATE); sc_file_free(tfile); if (r != SC_SUCCESS) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unable to create PIN file, insufficent rights"); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "unable to create PIN file, insufficient rights"); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); } diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-authentic.c opensc-0.19.0/src/pkcs15init/pkcs15-authentic.c --- opensc-0.17.0/src/pkcs15init/pkcs15-authentic.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-authentic.c 2018-09-13 11:47:21.000000000 +0000 @@ -560,20 +560,20 @@ p15card->card->caps &= ~SC_CARD_CAP_USE_FCI_AC; rv = sc_pkcs15init_authenticate(profile, p15card, file_p_prvkey, SC_AC_OP_DELETE); p15card->card->caps = caps; - LOG_TEST_RET(ctx, rv, "SC_AC_OP_CRYPTO authentication failed for parent DF"); + LOG_TEST_GOTO_ERR(ctx, rv, "SC_AC_OP_CRYPTO authentication failed for parent DF"); rv = sc_card_ctl(card, SC_CARDCTL_AUTHENTIC_SDO_DELETE, sdo); - LOG_TEST_RET(ctx, rv, "SC_CARDCTL_AUTHENTIC_SDO_DELETE failed for private key"); + LOG_TEST_GOTO_ERR(ctx, rv, "SC_CARDCTL_AUTHENTIC_SDO_DELETE failed for private key"); rv = sc_card_ctl(card, SC_CARDCTL_AUTHENTIC_SDO_CREATE, sdo); } - LOG_TEST_RET(ctx, rv, "SC_CARDCTL_AUTHENTIC_SDO_CREATE failed"); + LOG_TEST_GOTO_ERR(ctx, rv, "SC_CARDCTL_AUTHENTIC_SDO_CREATE failed"); rv = authentic_pkcs15_fix_access(p15card, file_p_prvkey, object); - LOG_TEST_RET(ctx, rv, "cannot fix access rules for private key"); + LOG_TEST_GOTO_ERR(ctx, rv, "cannot fix access rules for private key"); rv = authentic_pkcs15_fix_usage(p15card, object); - LOG_TEST_RET(ctx, rv, "cannot fix access rules for private key"); + LOG_TEST_GOTO_ERR(ctx, rv, "cannot fix access rules for private key"); /* Here fix the key's supported algorithms, if these ones will be implemented * (see src/libopensc/pkcs15-prkey.c). @@ -583,8 +583,10 @@ sc_log(ctx, "sdo->file:%p", sdo->file); rv = sc_pkcs15_allocate_object_content(ctx, object, (unsigned char *)sdo, sizeof(struct sc_authentic_sdo)); - LOG_TEST_RET(ctx, rv, "Failed to allocate PrvKey SDO as object content"); + LOG_TEST_GOTO_ERR(ctx, rv, "Failed to allocate PrvKey SDO as object content"); +err: + free(sdo); LOG_FUNC_RETURN(ctx, rv); } @@ -636,7 +638,7 @@ LOG_TEST_RET(ctx, rv, "generate key failed"); pubkey->algorithm = SC_ALGORITHM_RSA; - //FIXME: allocate/copy/free to reduce memory likage + //FIXME: allocate/copy/free to reduce memory leakage pubkey->u.rsa.modulus = sdo->data.prvkey->u.rsa.modulus; pubkey->u.rsa.exponent = sdo->data.prvkey->u.rsa.exponent; sdo->data.prvkey = NULL; diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-cardos.c opensc-0.19.0/src/pkcs15init/pkcs15-cardos.c --- opensc-0.17.0/src/pkcs15init/pkcs15-cardos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-cardos.c 2018-09-13 11:47:21.000000000 +0000 @@ -139,7 +139,7 @@ return r; /* Create a default security environment for this DF. - * This SE autometically becomes the current SE when the + * This SE automatically becomes the current SE when the * DF is selected. */ if ((r = cardos_create_sec_env(profile, p15card->card, 0x01, 0x00)) < 0) return r; @@ -201,7 +201,7 @@ if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; - r = sc_select_file(card, &df->path, NULL); + r = sc_select_file(card, auth_info->attrs.pin.reference & 0x80 ? &df->path : sc_get_mf_path(), NULL); if (r < 0) return r; @@ -499,7 +499,7 @@ /* object address: class, id */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */ - tlv_add(&tlv, auth_info->attrs.pin.reference); + tlv_add(&tlv, auth_info->attrs.pin.reference & 0x7f); /* parameters */ tlv_next(&tlv, 0x85); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-cflex.c opensc-0.19.0/src/pkcs15init/pkcs15-cflex.c --- opensc-0.17.0/src/pkcs15init/pkcs15-cflex.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-cflex.c 2018-09-13 11:47:21.000000000 +0000 @@ -296,9 +296,9 @@ goto out; } - if (prkf->size < size) + if (prkf && prkf->size < size) prkf->size = size; - if (pukf->size < size + 4) + if (pukf && pukf->size < size + 4) pukf->size = size + 4; /* Now create the files */ @@ -385,7 +385,7 @@ { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; - sc_file_t *prkf, *pukf; + sc_file_t *prkf = NULL, *pukf = NULL; unsigned char keybuf[1024]; size_t size; int r; diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-entersafe.c opensc-0.19.0/src/pkcs15init/pkcs15-entersafe.c --- opensc-0.17.0/src/pkcs15init/pkcs15-entersafe.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-entersafe.c 2018-09-13 11:47:21.000000000 +0000 @@ -292,6 +292,8 @@ data.key_data.symmetric.key_len=16; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); + if (r < 0) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); /* Cache new PIN value. */ sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); @@ -316,7 +318,7 @@ } - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } static int entersafe_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-epass2003.c opensc-0.19.0/src/pkcs15init/pkcs15-epass2003.c --- opensc-0.17.0/src/pkcs15init/pkcs15-epass2003.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-epass2003.c 2018-09-13 11:47:21.000000000 +0000 @@ -51,7 +51,7 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_do_log(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,NULL,0,NULL, - "ePass2003 doesn't surpport SO-PIN and SO-PUK. You can unblock key with PUK. \n"); + "ePass2003 doesn't support SO-PIN and SO-PUK. You can unblock key with PUK. \n"); { /* MF */ struct sc_file *mf_file; struct sc_file *skey_file; @@ -122,6 +122,8 @@ "Get SKey info failed"); ret = sc_create_file(card, skey_file); sc_file_free(skey_file); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, + "Create SKey info failed"); ret = sc_profile_get_file(profile, "MAXPIN", &ef_file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, @@ -250,6 +252,8 @@ data.key_data.es_secret.key_len = pin_len; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); + if (r < 0) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); if (pin_obj) { /* Cache new PIN value. */ sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); @@ -312,6 +316,16 @@ num); while (1) { switch (type) { + case SC_PKCS15_TYPE_PRKEY_EC: + desc = "RSA private key"; + _template = "private-key"; + structure = SC_CARDCTL_OBERTHUR_KEY_EC_CRT; + break; + case SC_PKCS15_TYPE_PUBKEY_EC: + desc = "RSA public key"; + _template = "public-key"; + structure = SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC; + break; case SC_PKCS15_TYPE_PRKEY_RSA: desc = "RSA private key"; _template = "private-key"; @@ -434,7 +448,7 @@ sc_print_path(&(file->path))); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "private key_info path: %s", sc_print_path(&(key_info->path))); - r = sc_delete_file(p15card->card, &file->path); + sc_delete_file(p15card->card, &file->path); /* create */ r = sc_pkcs15init_create_file(profile, p15card, file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, @@ -497,11 +511,14 @@ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) + if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_EC) return SC_ERROR_NOT_SUPPORTED; + if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 0) + keybits = 256; //EC key length is 256 ... + /* allocate key object */ - r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, idx, &file); + r = cosm_new_file(profile, card, obj->type, idx, &file); //replace SC_PKCS15_TYPE_PRKEY_RSA with obj->type SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, "create key: failed to allocate new key object"); file->size = keybits; @@ -515,7 +532,7 @@ SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, "generate key: pkcs15init_authenticate(SC_AC_OP_DELETE) failed"); - r = sc_delete_file(p15card->card, &file->path); + sc_delete_file(p15card->card, &file->path); /* create */ r = sc_pkcs15init_create_file(profile, p15card, file); SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, @@ -525,11 +542,18 @@ "index %"SC_FORMAT_LEN_SIZE_T"u; keybits %"SC_FORMAT_LEN_SIZE_T"u\n", idx, keybits); if (keybits < 1024 || keybits > 2048 || (keybits % 0x20)) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, - "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", - keybits); - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; + if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 256) + { + sc_log(card->ctx, "current Alg is EC,Only support 256 ..\n"); + } + else + { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, + "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", + keybits); + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } } path = key_info->path; @@ -549,12 +573,23 @@ SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, "generate key: pkcs15init_authenticate(SC_AC_OP_CREATE) failed"); - if ((r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_RSA, idx, - &pukf)) < 0) { + if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA ) + { + + r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_EC, idx, &pukf); + } + else + { + + r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_RSA, idx, &pukf); + } + + if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "generate key: create temporary pukf failed\n"); goto err; } + pukf->size = keybits; pukf->id = pukf->path.value[pukf->path.len - 2] * 0x100 + pukf->path.value[pukf->path.len - 1]; diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-iasecc.c opensc-0.19.0/src/pkcs15init/pkcs15-iasecc.c --- opensc-0.17.0/src/pkcs15init/pkcs15-iasecc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-iasecc.c 2018-09-13 11:47:21.000000000 +0000 @@ -93,7 +93,7 @@ rv = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE); card->caps = caps; - LOG_TEST_RET(ctx, rv, "Cannnot authenticate SC_AC_OP_DELETE"); + LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE"); memset(&path, 0, sizeof(path)); path.type = SC_PATH_TYPE_FILE_ID; @@ -335,7 +335,8 @@ if (acl) { switch (acl->method) { case SC_AC_IDA: - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "'IDA' not actually supported"); + sc_log(ctx, "'IDA' not actually supported"); + return SC_ERROR_NOT_SUPPORTED; case SC_AC_SCB: if ((acl->key_ref & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH) { acl->method = SC_AC_SEN; @@ -373,7 +374,7 @@ /* Get ACLs from profile template */ rv = sc_profile_get_file(profile, template, &file); - LOG_TEST_RET(ctx, rv, "IasEcc: cannot instanciate private key file"); + LOG_TEST_RET(ctx, rv, "IasEcc: cannot instantiate private key file"); /* Convert PKCS15 ACLs to SE ACLs */ rv = iasecc_file_convert_acls(ctx, profile, file); @@ -472,7 +473,7 @@ sdo->docp.non_repudiation.value = calloc(1, 1); if (!sdo->docp.non_repudiation.value) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - sdo->docp.non_repudiation.tag = IASECC_DOCP_TAG_NON_REPUDATION; + sdo->docp.non_repudiation.tag = IASECC_DOCP_TAG_NON_REPUDIATION; sdo->docp.non_repudiation.size = 1; sdo->data.prv_key.compulsory.value = calloc(1, 1); @@ -495,7 +496,7 @@ If present, this attribute has to be the same in the 'GENERATE KEY' template data. */ if (!(key_info->access_flags & SC_PKCS15_PRKEY_ACCESS_LOCAL) && (key_info->usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) - sc_log(ctx, "Non fatal error: NON_REPUDATION can be used only for the localy generated keys"); + sc_log(ctx, "Non fatal error: NON_REPUDIATION can be used only for the locally generated keys"); if ((key_info->access_flags & SC_PKCS15_PRKEY_ACCESS_LOCAL) && (key_info->usage & SC_PKCS15_PRKEY_USAGE_SIGN) @@ -1136,7 +1137,7 @@ return SC_ERROR_INVALID_ARGUMENTS; } - /* TODO: Check if native IAS middleware accepts the meaningfull path value. */ + /* TODO: Check if native IAS middleware accepts the meaningful path value. */ rv = sc_profile_get_parent(profile, "private-key", &file); LOG_TEST_RET(ctx, rv, "IasEcc: cannot get private key parent file"); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-init.h opensc-0.19.0/src/pkcs15init/pkcs15-init.h --- opensc-0.17.0/src/pkcs15init/pkcs15-init.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-init.h 2018-09-13 11:47:21.000000000 +0000 @@ -367,7 +367,7 @@ struct sc_profile *, struct sc_pkcs15_object *); /* Replace an existing cert with a new one, which is assumed to be - * compatible with the correcsponding private key (e.g. the old and + * compatible with the corresponding private key (e.g. the old and * new cert should have the same public key). */ extern int sc_pkcs15init_update_certificate(struct sc_pkcs15_card *, diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-isoApplet.c opensc-0.19.0/src/pkcs15init/pkcs15-isoApplet.c --- opensc-0.17.0/src/pkcs15init/pkcs15-isoApplet.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-isoApplet.c 2018-09-13 11:47:21.000000000 +0000 @@ -345,7 +345,7 @@ * @param[in] pubkey The public key of the generated key pair * returned by the card. * - * @return SC_ERROR_INVALID_ARGURMENTS: Invalid key length. + * @return SC_ERROR_INVALID_ARGUMENTS: Invalid key length. * SC_ERROR_OUT_OF_MEMORY */ static int @@ -434,7 +434,7 @@ * @param[in/out] pubkey The public key of the generated key pair * returned by the card. * - * @return SC_ERROR_INVALID_ARGURMENTS: Invalid key length or curve. + * @return SC_ERROR_INVALID_ARGUMENTS: Invalid key length or curve. * SC_ERROR_OUT_OF_MEMORY * SC_ERROR_INCOMPATIBLE_KEY: The data returned by the card * was unexpected and can not be @@ -609,7 +609,7 @@ /* Authentication stuff. */ r = sc_profile_get_file_by_path(profile, &key_info->path, &privKeyFile); - if(!privKeyFile) + if(r < 0 || !privKeyFile) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); } @@ -692,7 +692,7 @@ /* Authentication stuff. */ r = sc_profile_get_file_by_path(profile, &key_info->path, &privKeyFile); - if(!privKeyFile) + if(r < 0 || !privKeyFile) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); } @@ -736,7 +736,7 @@ args.algorithm_ref = SC_ISOAPPLET_ALG_REF_EC_GEN; if(key->u.ec.params.der.len == 0 || key->u.ec.params.der.value == NULL) { r = sc_pkcs15_fix_ec_parameters(card->ctx, &key->u.ec.params); - LOG_TEST_RET(card->ctx, r, "EC key storing failed: Unkown curve."); + LOG_TEST_RET(card->ctx, r, "EC key storing failed: Unknown curve."); } r = isoApplet_get_curve(key->u.ec.params.der.value, key->u.ec.params.der.len, &curve); LOG_TEST_RET(card->ctx, r, "EC key generation failed: Unsupported curve"); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-lib.c opensc-0.19.0/src/pkcs15init/pkcs15-lib.c --- opensc-0.17.0/src/pkcs15init/pkcs15-lib.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-lib.c 2018-09-13 11:47:21.000000000 +0000 @@ -734,8 +734,8 @@ int rv; LOG_FUNC_CALLED(ctx); - if (card->app_count < 0) - sc_enum_apps(card); + if (card->app_count < 0 && SC_SUCCESS != sc_enum_apps(card)) + sc_log(ctx, "Could not enumerate apps"); if (aid) { sc_log(ctx, "finalize profile for AID %s", sc_dump_hex(aid->value, aid->len)); @@ -803,7 +803,7 @@ sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &puk_ainfo); r = sc_pkcs15init_qualify_pin(card, "SO PUK", args->so_puk_len, &puk_ainfo); - LOG_TEST_RET(ctx, r, "Failed to qulify SO PUK"); + LOG_TEST_RET(ctx, r, "Failed to qualify SO PUK"); if (!(pin_label = args->so_pin_label)) { if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) @@ -903,11 +903,16 @@ r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj); if (r >= 0) { r = sc_pkcs15init_update_dir(p15card, profile, app); - if (r >= 0) + if (r >= 0) { r = sc_pkcs15init_update_tokeninfo(p15card, profile); - /* FIXME: what to do if sc_pkcs15init_update_dir failed? */ + } else { + /* FIXME: what to do if sc_pkcs15init_update_dir failed? */ + free(app->label); + free(app); /* unused */ + } } else { + free(app->label); free(app); /* unused */ } @@ -2612,7 +2617,7 @@ if (id_out->len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); - /* Native ID style is not intrisic one */ + /* Native ID style is not intrinsic one */ if (id_style == SC_PKCS15INIT_ID_STYLE_NATIVE) LOG_FUNC_RETURN(ctx, SC_SUCCESS); @@ -2638,7 +2643,7 @@ LOG_FUNC_RETURN(ctx, SC_SUCCESS); } - /* Skip silently if key is not inintialized. */ + /* Skip silently if key is not initialized. */ if (pubkey->algorithm == SC_ALGORITHM_RSA && !pubkey->u.rsa.modulus.len) goto done; else if (pubkey->algorithm == SC_ALGORITHM_DSA && !pubkey->u.dsa.pub.data) @@ -3661,12 +3666,12 @@ if (path && path->len) { struct sc_path tmp_path = *path; int iter; - r = SC_ERROR_OBJECT_NOT_FOUND; - for (iter = tmp_path.len/2; iter >= 0 && r == SC_ERROR_OBJECT_NOT_FOUND; iter--, tmp_path.len -= 2) + for (iter = tmp_path.len/2; iter >= 0 && r == SC_ERROR_OBJECT_NOT_FOUND; iter--, tmp_path.len -= 2) { r = sc_pkcs15_find_pin_by_type_and_reference(p15card, tmp_path.len ? &tmp_path : NULL, type, reference, &pin_obj); + } } else { r = sc_pkcs15_find_pin_by_type_and_reference(p15card, NULL, type, reference, &pin_obj); @@ -3767,7 +3772,7 @@ * * In the latter case, there's a problem here if e.g. the SO PIN * defined by the profile is optional, and hasn't been set. - * On the orther hands, some cards do not return access conditions + * On the other hands, some cards do not return access conditions * in their response to SELECT FILE), so the latter case has been * used in most cards while the first case was added much later. */ @@ -3875,6 +3880,10 @@ int r; LOG_FUNC_CALLED(ctx); + if (!file) { + return SC_ERROR_INVALID_ARGUMENTS; + } + sc_log(ctx, "create file '%s'", sc_print_path(&file->path)); /* Select parent DF and verify PINs/key as necessary */ r = do_select_parent(profile, p15card, file, &parent); @@ -4211,7 +4220,7 @@ } if (r >= 0) - r = sc_pkcs15init_parse_info(card, mem, len, profile); + r = sc_pkcs15init_parse_info(card, mem, r, profile); if (mem) free(mem); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-muscle.c opensc-0.19.0/src/pkcs15init/pkcs15-muscle.c --- opensc-0.17.0/src/pkcs15init/pkcs15-muscle.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-muscle.c 2018-09-13 11:47:21.000000000 +0000 @@ -177,7 +177,8 @@ /* Verification stuff */ /* Used for verification AND for obtaining private key acls */ r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); - if(!prkf) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); + if (r < 0 || !prkf) + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO); if (r < 0) { sc_file_free(prkf); @@ -241,7 +242,8 @@ /* Verification stuff */ /* Used for verification AND for obtaining private key acls */ r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); - if(!prkf) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); + if(r < 0 || !prkf) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO); if (r < 0) { sc_file_free(prkf); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-myeid.c opensc-0.19.0/src/pkcs15init/pkcs15-myeid.c --- opensc-0.17.0/src/pkcs15init/pkcs15-myeid.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-myeid.c 2018-09-13 11:47:21.000000000 +0000 @@ -821,6 +821,8 @@ dataptr = data_obj.Data; r = sc_asn1_read_tag((const u8 **)&dataptr, data_obj.DataLen, &cla, &tag, &taglen); + if (dataptr == NULL) + r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; LOG_TEST_RET(ctx, r, "Invalid EC public key data. Cannot parse DER structure."); if (taglen == 0) diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-oberthur-awp.c opensc-0.19.0/src/pkcs15init/pkcs15-oberthur-awp.c --- opensc-0.17.0/src/pkcs15init/pkcs15-oberthur-awp.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-oberthur-awp.c 2018-09-13 11:47:21.000000000 +0000 @@ -831,12 +831,9 @@ static void awp_free_key_info(struct awp_key_info *ki) { - if (ki->modulus.value) - free(ki->modulus.value); - if (ki->exponent.value) - free(ki->exponent.value); - if (ki->id.value) - free(ki->id.value); + free(ki->modulus.value); + free(ki->exponent.value); + free(ki->id.value); } @@ -1015,7 +1012,7 @@ * i2c_ASN1_INTEGER which is not in OpenSSL 1.1 * It was adding the tag V_ASN1_INTEGER and the one byte length back in in effect creating * a DER encoded ASN1_INTEGER - * So we can simplifty the code and make compatable with OpenSSL 1.1. This needs to be tested + * So we can simplify the code and make compatible with OpenSSL 1.1. This needs to be tested */ ci->serial.len = 0; ci->serial.value = NULL; @@ -1072,22 +1069,24 @@ static void awp_free_cert_info(struct awp_cert_info *ci) { - if (ci->cn.len && ci->cn.value) - free(ci->cn.value); + if (ci) { + if (ci->cn.len && ci->cn.value) + free(ci->cn.value); - if (ci->id.len && ci->id.value) - free(ci->id.value); + if (ci->id.len && ci->id.value) + free(ci->id.value); - if (ci->subject.len && ci->subject.value) - free(ci->subject.value); + if (ci->subject.len && ci->subject.value) + free(ci->subject.value); - if (ci->issuer.len && ci->issuer.value) - free(ci->issuer.value); + if (ci->issuer.len && ci->issuer.value) + free(ci->issuer.value); - if (ci->x509) - X509_free(ci->x509); + if (ci->x509) + X509_free(ci->x509); - memset(ci,0,sizeof(struct awp_cert_info)); + memset(ci,0,sizeof(struct awp_cert_info)); + } } @@ -1388,25 +1387,26 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Cert Der(%p,%"SC_FORMAT_LEN_SIZE_T"u)", der.value, der.len); rv = awp_encode_cert_info(p15card, obj, &icert); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot encode info"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot encode info"); rv = awp_set_certificate_info(p15card, profile, info_file, &icert); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot set info"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot set info"); rv = awp_update_object_list(p15card, profile, SC_PKCS15_TYPE_CERT_X509, obj_id & 0xFF); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update list"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update list"); rv = awp_update_container(p15card, profile, SC_PKCS15_TYPE_CERT_X509, &icert.id, obj_id, &prvkey_id); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update container"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update container"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PrvKeyID:%04X", prvkey_id); if (prvkey_id) rv = awp_update_key_info(p15card, profile, prvkey_id, &icert); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update key info"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update key info"); awp_free_cert_info(&icert); +err: sc_file_free(info_file); sc_file_free(obj_file); @@ -1434,6 +1434,7 @@ SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); memset(&ikey, 0, sizeof(ikey)); + memset(&icert, 0, sizeof(icert)); key_info = (struct sc_pkcs15_prkey_info *)key_obj->data; der = key_obj->content; @@ -1495,8 +1496,8 @@ sc_file_free(info_file); if (cert_obj) awp_free_cert_info(&icert); - awp_free_key_info(&ikey); + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -1521,6 +1522,8 @@ index = path.value[path.len-1] & 0xFF; obj_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + memset(&ikey, 0, sizeof(ikey)); + rv = awp_new_file(p15card, profile, obj->type, index, &info_file, NULL); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "New public key info file error"); @@ -1530,7 +1533,6 @@ rv = sc_pkcs15_decode_pubkey(ctx, &pubkey, der.value, der.len); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: decode public key error"); - memset(&ikey, 0, sizeof(ikey)); rv = awp_encode_key_info(p15card, obj, &pubkey.u.rsa, &ikey); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: encode info error"); @@ -1543,9 +1545,8 @@ rv = awp_update_container(p15card, profile, obj->type, &ikey.id, obj_id, NULL); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: update container error"); - awp_free_key_info(&ikey); - err: + awp_free_key_info(&ikey); sc_file_free(info_file); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -1801,7 +1802,7 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: cannt get allocate new AWP file"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: cannot get allocate new AWP file"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); @@ -1835,7 +1836,7 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: cannt get allocate new AWP file"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: cannot get allocate new AWP file"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); @@ -1869,7 +1870,7 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: cannt get allocate new AWP file"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: cannot get allocate new AWP file"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); @@ -1903,7 +1904,7 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete DATA' update DF failed: cannt get allocate new AWP file"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete DATA' update DF failed: cannot get allocate new AWP file"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-oberthur.c opensc-0.19.0/src/pkcs15init/pkcs15-oberthur.c --- opensc-0.17.0/src/pkcs15init/pkcs15-oberthur.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-oberthur.c 2018-09-13 11:47:21.000000000 +0000 @@ -78,7 +78,7 @@ if (file->size < 16) { rv = SC_ERROR_INCONSISTENT_PROFILE; - SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "Unsufficient size of the "COSM_TITLE"-token-info file"); + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "Insufficient size of the "COSM_TITLE"-token-info file"); } buffer = calloc(1, file->size); @@ -138,11 +138,11 @@ path.len -= 2; rv = sc_select_file(p15card->card, &path, &parent); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannnot select parent"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot select parent"); rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE); sc_file_free(parent); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannnot authenticate SC_AC_OP_DELETE"); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot authenticate SC_AC_OP_DELETE"); memset(&path, 0, sizeof(path)); path.type = SC_PATH_TYPE_FILE_ID; @@ -183,6 +183,8 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "erase file ddf %04X",df->id); rv = cosm_delete_file(p15card, profile, df); + if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) + goto done; if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "erase file dir %04X",dir->id); @@ -689,7 +691,7 @@ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "create private key ID:%s", sc_pkcs15_print_id(&key_info->id)); /* Here, the path of private key file should be defined. - * Neverthelles, we need to instanciate private key to get the ACLs. */ + * Nevertheless, we need to instantiate private key to get the ACLs. */ rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create key: failed to allocate new key object"); diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-openpgp.c opensc-0.19.0/src/pkcs15init/pkcs15-openpgp.c --- opensc-0.17.0/src/pkcs15init/pkcs15-openpgp.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-openpgp.c 2018-09-13 11:47:21.000000000 +0000 @@ -188,8 +188,10 @@ /* The OpenPGP supports only 32-bit exponent. */ key_info.exponent_len = 32; key_info.exponent = calloc(key_info.exponent_len>>3, 1); /* 1/8 */ - if (key_info.exponent == NULL) + if (key_info.exponent == NULL) { + free(key_info.modulus); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + } r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); if (r < 0) diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-starcos.c opensc-0.19.0/src/pkcs15init/pkcs15-starcos.c --- opensc-0.17.0/src/pkcs15init/pkcs15-starcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-starcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -763,7 +763,7 @@ tkey.key_header[4] = 0x0f; /* do state transition */ else tkey.key_header[4] = 0x8f; /* no state transition */ - tkey.key_header[5] = 0x11; /* requiere local state == 1 to update key */ + tkey.key_header[5] = 0x11; /* require local state == 1 to update key */ tkey.key_header[6] = 0x33; tkey.key_header[7] = 0x00; tkey.key_header[8] = 0x09; diff -Nru opensc-0.17.0/src/pkcs15init/pkcs15-westcos.c opensc-0.19.0/src/pkcs15init/pkcs15-westcos.c --- opensc-0.17.0/src/pkcs15init/pkcs15-westcos.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/pkcs15-westcos.c 2018-09-13 11:47:21.000000000 +0000 @@ -61,6 +61,7 @@ /* Create the application DF */ r = sc_pkcs15init_create_file(profile, p15card, df); + if(r) return r; r = sc_select_file(p15card->card, &df->path, NULL); if(r) return r; @@ -323,7 +324,7 @@ { int r; - /* be sure authentificate card */ + /* be sure authenticate card */ r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL); if(r) return (r); diff -Nru opensc-0.17.0/src/pkcs15init/profile.c opensc-0.19.0/src/pkcs15init/profile.c --- opensc-0.17.0/src/pkcs15init/profile.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/profile.c 2018-09-13 11:47:21.000000000 +0000 @@ -342,11 +342,12 @@ if (!profile_dir) { #ifdef _WIN32 - temp_len = PATH_MAX; + temp_len = PATH_MAX - 1; res = sc_ctx_win32_get_config_value(NULL, "ProfileDir", "Software\\OpenSC Project\\OpenSC", temp_path, &temp_len); if (res) LOG_FUNC_RETURN(ctx, res); + temp_path[temp_len] = '\0'; profile_dir = temp_path; #else profile_dir = SC_PKCS15_PROFILE_DIRECTORY; diff -Nru opensc-0.17.0/src/pkcs15init/setcos.profile opensc-0.19.0/src/pkcs15init/setcos.profile --- opensc-0.17.0/src/pkcs15init/setcos.profile 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/pkcs15init/setcos.profile 2018-09-13 11:47:21.000000000 +0000 @@ -7,7 +7,7 @@ pin-pad-char = 0x00; } -# Addtional default settings +# Additional default settings option default { macros { protected = *=$SOPIN, READ=NONE; @@ -20,7 +20,7 @@ } } -# Addtional onepin option settings +# Additional onepin option settings option onepin { macros { protected = *=$PIN, READ=NONE; diff -Nru opensc-0.17.0/src/scconf/parse.c opensc-0.19.0/src/scconf/parse.c --- opensc-0.17.0/src/scconf/parse.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/scconf/parse.c 2018-09-13 11:47:21.000000000 +0000 @@ -166,6 +166,7 @@ } } else { /* FIXME is it an error if item is NULL? */ + free(parser.key); } return parser.current_item; } diff -Nru opensc-0.17.0/src/scconf/README.scconf opensc-0.19.0/src/scconf/README.scconf --- opensc-0.17.0/src/scconf/README.scconf 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/scconf/README.scconf 2018-09-13 11:47:21.000000000 +0000 @@ -18,7 +18,7 @@ It doesn't have - anything else but data. No locking, no threads etc. -It has heirarchical data blocks, it has lists. +It has hierarchical data blocks, it has lists. Similar, but different: - .ini files. scconf is block structured, has lists and arrays @@ -132,9 +132,9 @@ const scconf_block * block, const char *item_name); This finds a block in the given context. This function doesn't descend -the heirarchy, it only finds blocks in the top level of either +the hierarchy, it only finds blocks in the top level of either the context (the root block) or of the block given in the block -paramter (if not NULL). +parameter (if not NULL). The block pointer returned points to data held by the context, hence the const qualifier. diff -Nru opensc-0.17.0/src/scconf/scconf.c opensc-0.19.0/src/scconf/scconf.c --- opensc-0.17.0/src/scconf/scconf.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/scconf/scconf.c 2018-09-13 11:47:21.000000000 +0000 @@ -147,7 +147,7 @@ if (!list) return def; - /* ignore non 'auto-configurated' values */ + /* ignore non 'auto-configured' values */ if (*list->data == '@' && *(list->data + strlen(list->data) - 1) == '@') return def; diff -Nru opensc-0.17.0/src/sm/sm-common.c opensc-0.19.0/src/sm/sm-common.c --- opensc-0.17.0/src/sm/sm-common.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/sm/sm-common.c 2018-09-13 11:47:21.000000000 +0000 @@ -62,12 +62,19 @@ l1=l2=0; \ switch (n) { \ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ + /* fall through */ \ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ + /* fall through */ \ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ + /* fall through */ \ case 5: l2|=((DES_LONG)(*(--(c)))); \ + /* fall through */ \ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ + /* fall through */ \ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ + /* fall through */ \ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ + /* fall through */ \ case 1: l1|=((DES_LONG)(*(--(c)))); \ } \ } diff -Nru opensc-0.17.0/src/sm/sm-eac.c opensc-0.19.0/src/sm/sm-eac.c --- opensc-0.17.0/src/sm/sm-eac.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/sm/sm-eac.c 2018-09-13 11:47:21.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Frank Morgner + * Copyright (C) 2011-2018 Frank Morgner * * This file is part of OpenSC. * @@ -34,7 +34,7 @@ #include #endif -char npa_default_flags = 0; +char eac_default_flags = 0; #define ISO_MSE 0x22 #if defined(ENABLE_OPENPACE) @@ -70,46 +70,46 @@ * MSE:Set AT */ -typedef struct npa_mse_cd_st { +typedef struct { ASN1_OBJECT *cryptographic_mechanism_reference; ASN1_OCTET_STRING *key_reference1; ASN1_OCTET_STRING *key_reference2; ASN1_OCTET_STRING *eph_pub_key; ASN1_AUXILIARY_DATA *auxiliary_data; CVC_CHAT *chat; -} NPA_MSE_C; +} EAC_MSE_C; /* Note that we can not use ASN1_AUXILIARY_DATA for the auxiliary_data element * here. Due to limitations of OpenSSL it is not possible to *encode* an * optional item template (such as auxiliary_data) in an other item template * (such as ASN1_AUXILIARY_DATA). However, we can do * - * NPA_MSE_C->auxiliary_data = d2i_ASN1_AUXILIARY_DATA(...) + * EAC_MSE_C->auxiliary_data = d2i_ASN1_AUXILIARY_DATA(...) * * because they both use the same underlying struct. * * See also openssl/crypto/asn1/tasn_dec.c:183 */ -ASN1_SEQUENCE(NPA_MSE_C) = { +ASN1_SEQUENCE(EAC_MSE_C) = { /* 0x80 * Cryptographic mechanism reference */ - ASN1_IMP_OPT(NPA_MSE_C, cryptographic_mechanism_reference, ASN1_OBJECT, 0), + ASN1_IMP_OPT(EAC_MSE_C, cryptographic_mechanism_reference, ASN1_OBJECT, 0), /* 0x83 * Reference of a public key / secret key */ - ASN1_IMP_OPT(NPA_MSE_C, key_reference1, ASN1_OCTET_STRING, 3), + ASN1_IMP_OPT(EAC_MSE_C, key_reference1, ASN1_OCTET_STRING, 3), /* 0x84 * Reference of a private key / Reference for computing a session key */ - ASN1_IMP_OPT(NPA_MSE_C, key_reference2, ASN1_OCTET_STRING, 4), + ASN1_IMP_OPT(EAC_MSE_C, key_reference2, ASN1_OCTET_STRING, 4), /* 0x91 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_MSE_C, eph_pub_key, ASN1_OCTET_STRING, 0x11), + ASN1_IMP_OPT(EAC_MSE_C, eph_pub_key, ASN1_OCTET_STRING, 0x11), /* 0x67 * Auxiliary authenticated data. See note above. */ - ASN1_APP_IMP_SEQUENCE_OF_OPT(NPA_MSE_C, auxiliary_data, CVC_DISCRETIONARY_DATA_TEMPLATE, 7), + ASN1_APP_IMP_SEQUENCE_OF_OPT(EAC_MSE_C, auxiliary_data, CVC_DISCRETIONARY_DATA_TEMPLATE, 7), /* Certificate Holder Authorization Template */ - ASN1_OPT(NPA_MSE_C, chat, CVC_CHAT), -} ASN1_SEQUENCE_END(NPA_MSE_C) -DECLARE_ASN1_FUNCTIONS(NPA_MSE_C) -IMPLEMENT_ASN1_FUNCTIONS(NPA_MSE_C) + ASN1_OPT(EAC_MSE_C, chat, CVC_CHAT), +} ASN1_SEQUENCE_END(EAC_MSE_C) +DECLARE_ASN1_FUNCTIONS(EAC_MSE_C) +IMPLEMENT_ASN1_FUNCTIONS(EAC_MSE_C) /* @@ -117,78 +117,78 @@ */ /* Protocol Command Data */ -typedef struct npa_gen_auth_pace_cd_st { +typedef struct { ASN1_OCTET_STRING *mapping_data; ASN1_OCTET_STRING *eph_pub_key; ASN1_OCTET_STRING *auth_token; -} NPA_GEN_AUTH_PACE_C_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_PACE_C_BODY) = { +} EAC_GEN_AUTH_PACE_C_BODY; +ASN1_SEQUENCE(EAC_GEN_AUTH_PACE_C_BODY) = { /* 0x81 * Mapping Data */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, mapping_data, ASN1_OCTET_STRING, 1), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_C_BODY, mapping_data, ASN1_OCTET_STRING, 1), /* 0x83 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 3), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 3), /* 0x85 * Authentication Token */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, auth_token, ASN1_OCTET_STRING, 5), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_PACE_C_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C_BODY) + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_C_BODY, auth_token, ASN1_OCTET_STRING, 5), +} ASN1_SEQUENCE_END(EAC_GEN_AUTH_PACE_C_BODY) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_C_BODY) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_C_BODY) -typedef NPA_GEN_AUTH_PACE_C_BODY NPA_GEN_AUTH_PACE_C; +typedef EAC_GEN_AUTH_PACE_C_BODY EAC_GEN_AUTH_PACE_C; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_PACE_C) = +ASN1_ITEM_TEMPLATE(EAC_GEN_AUTH_PACE_C) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_PACE_C, NPA_GEN_AUTH_PACE_C_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_PACE_C) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C) + 0x1c, EAC_GEN_AUTH_PACE_C, EAC_GEN_AUTH_PACE_C_BODY) +ASN1_ITEM_TEMPLATE_END(EAC_GEN_AUTH_PACE_C) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_C) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_C) /* Protocol Response Data */ -typedef struct npa_gen_auth_pace_rapdu_body_st { +typedef struct { ASN1_OCTET_STRING *enc_nonce; ASN1_OCTET_STRING *mapping_data; ASN1_OCTET_STRING *eph_pub_key; ASN1_OCTET_STRING *auth_token; ASN1_OCTET_STRING *cur_car; ASN1_OCTET_STRING *prev_car; -} NPA_GEN_AUTH_PACE_R_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_PACE_R_BODY) = { +} EAC_GEN_AUTH_PACE_R_BODY; +ASN1_SEQUENCE(EAC_GEN_AUTH_PACE_R_BODY) = { /* 0x80 * Encrypted Nonce */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, enc_nonce, ASN1_OCTET_STRING, 0), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, enc_nonce, ASN1_OCTET_STRING, 0), /* 0x82 * Mapping Data */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, mapping_data, ASN1_OCTET_STRING, 2), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, mapping_data, ASN1_OCTET_STRING, 2), /* 0x84 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, eph_pub_key, ASN1_OCTET_STRING, 4), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, eph_pub_key, ASN1_OCTET_STRING, 4), /* 0x86 * Authentication Token */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, auth_token, ASN1_OCTET_STRING, 6), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, auth_token, ASN1_OCTET_STRING, 6), /* 0x87 * Most recent Certification Authority Reference */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, cur_car, ASN1_OCTET_STRING, 7), + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, cur_car, ASN1_OCTET_STRING, 7), /* 0x88 * Previous Certification Authority Reference */ - ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, prev_car, ASN1_OCTET_STRING, 8), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_PACE_R_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R_BODY) + ASN1_IMP_OPT(EAC_GEN_AUTH_PACE_R_BODY, prev_car, ASN1_OCTET_STRING, 8), +} ASN1_SEQUENCE_END(EAC_GEN_AUTH_PACE_R_BODY) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_R_BODY) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_R_BODY) -typedef NPA_GEN_AUTH_PACE_R_BODY NPA_GEN_AUTH_PACE_R; +typedef EAC_GEN_AUTH_PACE_R_BODY EAC_GEN_AUTH_PACE_R; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_PACE_R) = +ASN1_ITEM_TEMPLATE(EAC_GEN_AUTH_PACE_R) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_PACE_R, NPA_GEN_AUTH_PACE_R_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_PACE_R) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R) + 0x1c, EAC_GEN_AUTH_PACE_R, EAC_GEN_AUTH_PACE_R_BODY) +ASN1_ITEM_TEMPLATE_END(EAC_GEN_AUTH_PACE_R) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_R) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_PACE_R) /* @@ -196,61 +196,61 @@ */ /* Protocol Command Data */ -typedef struct npa_gen_auth_ca_cd_st { +typedef struct eac_gen_auth_ca_cd_st { ASN1_OCTET_STRING *eph_pub_key; -} NPA_GEN_AUTH_CA_C_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_CA_C_BODY) = { +} EAC_GEN_AUTH_CA_C_BODY; +ASN1_SEQUENCE(EAC_GEN_AUTH_CA_C_BODY) = { /* 0x80 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_GEN_AUTH_CA_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 0), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_CA_C_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C_BODY) + ASN1_IMP_OPT(EAC_GEN_AUTH_CA_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 0), +} ASN1_SEQUENCE_END(EAC_GEN_AUTH_CA_C_BODY) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_C_BODY) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_C_BODY) -typedef NPA_GEN_AUTH_CA_C_BODY NPA_GEN_AUTH_CA_C; +typedef EAC_GEN_AUTH_CA_C_BODY EAC_GEN_AUTH_CA_C; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_CA_C) = +ASN1_ITEM_TEMPLATE(EAC_GEN_AUTH_CA_C) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_CA_C, NPA_GEN_AUTH_CA_C_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_CA_C) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C) + 0x1c, EAC_GEN_AUTH_CA_C, EAC_GEN_AUTH_CA_C_BODY) +ASN1_ITEM_TEMPLATE_END(EAC_GEN_AUTH_CA_C) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_C) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_C) /* Protocol Response Data */ -typedef struct npa_gen_auth_ca_rapdu_body_st { +typedef struct eac_gen_auth_ca_rapdu_body_st { ASN1_OCTET_STRING *nonce; ASN1_OCTET_STRING *auth_token; -} NPA_GEN_AUTH_CA_R_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_CA_R_BODY) = { +} EAC_GEN_AUTH_CA_R_BODY; +ASN1_SEQUENCE(EAC_GEN_AUTH_CA_R_BODY) = { /* 0x81 * Nonce */ - ASN1_IMP_OPT(NPA_GEN_AUTH_CA_R_BODY, nonce, ASN1_OCTET_STRING, 1), + ASN1_IMP_OPT(EAC_GEN_AUTH_CA_R_BODY, nonce, ASN1_OCTET_STRING, 1), /* 0x82 * Authentication Token */ - ASN1_IMP_OPT(NPA_GEN_AUTH_CA_R_BODY, auth_token, ASN1_OCTET_STRING, 2), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_CA_R_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R_BODY) + ASN1_IMP_OPT(EAC_GEN_AUTH_CA_R_BODY, auth_token, ASN1_OCTET_STRING, 2), +} ASN1_SEQUENCE_END(EAC_GEN_AUTH_CA_R_BODY) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_R_BODY) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_R_BODY) -typedef NPA_GEN_AUTH_CA_R_BODY NPA_GEN_AUTH_CA_R; +typedef EAC_GEN_AUTH_CA_R_BODY EAC_GEN_AUTH_CA_R; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_CA_R) = +ASN1_ITEM_TEMPLATE(EAC_GEN_AUTH_CA_R) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_CA_R, NPA_GEN_AUTH_CA_R_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_CA_R) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R) + 0x1c, EAC_GEN_AUTH_CA_R, EAC_GEN_AUTH_CA_R_BODY) +ASN1_ITEM_TEMPLATE_END(EAC_GEN_AUTH_CA_R) +DECLARE_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_R) +IMPLEMENT_ASN1_FUNCTIONS(EAC_GEN_AUTH_CA_R) #define maxresp SC_MAX_APDU_BUFFER_SIZE - 2 /** @brief NPA secure messaging context */ -struct npa_sm_ctx { +struct eac_sm_ctx { /** @brief EAC context */ EAC_CTX *ctx; /** @brief Certificate Description given on initialization of PACE */ @@ -270,32 +270,32 @@ extern BUF_MEM *BUF_MEM_create_init(const void *buf, size_t len); -static int npa_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, u8 **enc); -static int npa_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *enc, size_t enclen, u8 **data); -static int npa_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, u8 **outdata); -static int npa_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *mac, size_t maclen, const u8 *macdata, size_t macdatalen); -static int npa_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *apdu); -static int npa_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *sm_apdu); -static int npa_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx, +static int eac_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *apdu); -static void npa_sm_clear_free(const struct iso_sm_ctx *ctx); +static void eac_sm_clear_free(const struct iso_sm_ctx *ctx); -static struct npa_sm_ctx * -npa_sm_ctx_create(EAC_CTX *ctx, const unsigned char *certificate_description, +static struct eac_sm_ctx * +eac_sm_ctx_create(EAC_CTX *ctx, const unsigned char *certificate_description, size_t certificate_description_length, const unsigned char *id_icc, size_t id_icc_length) { - struct npa_sm_ctx *out = malloc(sizeof *out); + struct eac_sm_ctx *out = malloc(sizeof *out); if (!out) goto err; @@ -320,10 +320,10 @@ out->eph_pub_key = NULL; out->auxiliary_data = NULL; - out->flags = npa_default_flags; - if (out->flags & NPA_FLAG_DISABLE_CHECK_TA) + out->flags = eac_default_flags; + if (out->flags & EAC_FLAG_DISABLE_CHECK_TA) TA_disable_checks(out->ctx); - if (out->flags & NPA_FLAG_DISABLE_CHECK_CA) + if (out->flags & EAC_FLAG_DISABLE_CHECK_CA) CA_disable_passive_authentication(out->ctx); return out; @@ -334,7 +334,7 @@ } static int -npa_sm_start(sc_card_t *card, EAC_CTX *eac_ctx, +eac_sm_start(sc_card_t *card, EAC_CTX *eac_ctx, const unsigned char *certificate_description, size_t certificate_description_length, const unsigned char *id_icc, size_t id_icc_length) @@ -353,7 +353,7 @@ goto err; } - sctx->priv_data = npa_sm_ctx_create(eac_ctx, + sctx->priv_data = eac_sm_ctx_create(eac_ctx, certificate_description, certificate_description_length, id_icc, id_icc_length); if (!sctx->priv_data) { @@ -361,14 +361,14 @@ goto err; } - sctx->authenticate = npa_sm_authenticate; - sctx->encrypt = npa_sm_encrypt; - sctx->decrypt = npa_sm_decrypt; - sctx->verify_authentication = npa_sm_verify_authentication; - sctx->pre_transmit = npa_sm_pre_transmit; - sctx->post_transmit = npa_sm_post_transmit; - sctx->finish = npa_sm_finish; - sctx->clear_free = npa_sm_clear_free; + sctx->authenticate = eac_sm_authenticate; + sctx->encrypt = eac_sm_encrypt; + sctx->decrypt = eac_sm_decrypt; + sctx->verify_authentication = eac_sm_verify_authentication; + sctx->pre_transmit = eac_sm_pre_transmit; + sctx->post_transmit = eac_sm_post_transmit; + sctx->finish = eac_sm_finish; + sctx->clear_free = eac_sm_clear_free; sctx->padding_indicator = SM_ISO_PADDING; sctx->block_length = EVP_CIPHER_block_size(eac_ctx->key_ctx->cipher); @@ -394,7 +394,7 @@ const unsigned char *auxiliary_data, size_t auxiliary_data_len, const CVC_CHAT *chat, unsigned char **cdata) { - NPA_MSE_C *data = NULL; + EAC_MSE_C *data = NULL; unsigned char *data_sequence = NULL; const unsigned char *data_no_sequence; unsigned char *p; @@ -406,7 +406,7 @@ goto err; } - data = NPA_MSE_C_new(); + data = EAC_MSE_C_new(); if (!data) { ssl_error(ctx); r = SC_ERROR_INTERNAL; @@ -425,7 +425,7 @@ if (key_reference1 && key_reference1_len) { data->key_reference1 = ASN1_OCTET_STRING_new(); if (!data->key_reference1 - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( data->key_reference1, key_reference1, key_reference1_len)) { sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Error setting key reference 1 of MSE:Set AT data"); r = SC_ERROR_INTERNAL; @@ -436,7 +436,7 @@ if (key_reference2 && key_reference2_len) { data->key_reference2 = ASN1_OCTET_STRING_new(); if (!data->key_reference2 - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( data->key_reference2, key_reference2, key_reference2_len)) { sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Error setting key reference 2 of MSE:Set AT data"); r = SC_ERROR_INTERNAL; @@ -447,7 +447,7 @@ if (eph_pub_key && eph_pub_key_len) { data->eph_pub_key = ASN1_OCTET_STRING_new(); if (!data->eph_pub_key - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( data->eph_pub_key, eph_pub_key, eph_pub_key_len)) { sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Error setting ephemeral Public Key of MSE:Set AT data"); r = SC_ERROR_INTERNAL; @@ -467,7 +467,7 @@ data->chat = (CVC_CHAT *) chat; - length = i2d_NPA_MSE_C(data, &data_sequence); + length = i2d_EAC_MSE_C(data, &data_sequence); data_no_sequence = data_sequence; if (length < 0 || (0x80 & ASN1_get_object(&data_no_sequence, &length, &tag, &class, length))) { @@ -496,14 +496,14 @@ if (data) { /* do not free the functions parameter chat */ data->chat = NULL; - NPA_MSE_C_free(data); + EAC_MSE_C_free(data); } OPENSSL_free(data_sequence); return r; } -static int npa_mse(sc_card_t *card, +static int eac_mse(sc_card_t *card, unsigned char p1, unsigned char p2, int protocol, const unsigned char *key_reference1, size_t key_reference1_len, const unsigned char *key_reference2, size_t key_reference2_len, @@ -555,27 +555,29 @@ return r; } -static int npa_mse_set_at(sc_card_t *card, unsigned char p1, int protocol, +static int eac_mse_set_at(sc_card_t *card, unsigned char p1, int protocol, const unsigned char *key_reference1, size_t key_reference1_len, const unsigned char *key_reference2, size_t key_reference2_len, const unsigned char *eph_pub_key, size_t eph_pub_key_len, const unsigned char *auxiliary_data, size_t auxiliary_data_len, const CVC_CHAT *chat, u8 *sw1, u8 *sw2) { - return npa_mse(card, p1, 0xA4, protocol, key_reference1, + return eac_mse(card, p1, 0xA4, protocol, key_reference1, key_reference1_len, key_reference2, key_reference2_len, eph_pub_key, eph_pub_key_len, auxiliary_data, auxiliary_data_len, chat, sw1, sw2); } -static int npa_mse_set_at_pace(sc_card_t *card, int protocol, +static int eac_mse_set_at_pace(sc_card_t *card, int protocol, enum s_type secret_key, const CVC_CHAT *chat, u8 *sw1, u8 *sw2) { int r, tries; unsigned char key = secret_key; - r = npa_mse_set_at(card, 0xC1, protocol, &key, sizeof key, NULL, + r = eac_mse_set_at(card, 0xC1, protocol, &key, sizeof key, NULL, 0, NULL, 0, NULL, 0, chat, sw1, sw2); + if (0 > r) + goto err; if (*sw1 == 0x63) { if ((*sw2 & 0xc0) == 0xc0) { @@ -583,7 +585,7 @@ if (tries <= 1) { /* this is only a warning... */ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Remaining tries: %d (%s must be %s)\n", - tries, npa_secret_name(secret_key), + tries, eac_secret_name(secret_key), tries ? "resumed" : "unblocked"); } r = SC_SUCCESS; @@ -599,18 +601,19 @@ r = sc_check_sw(card, *sw1, *sw2); } +err: return r; } #define ISO_GENERAL_AUTHENTICATE 0x86 #define ISO_COMMAND_CHAINING 0x10 -static int npa_gen_auth_1_encrypted_nonce(sc_card_t *card, +static int eac_gen_auth_1_encrypted_nonce(sc_card_t *card, u8 **enc_nonce, size_t *enc_nonce_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_PACE_C *c_data = NULL; - NPA_GEN_AUTH_PACE_R *r_data = NULL; + EAC_GEN_AUTH_PACE_C *c_data = NULL; + EAC_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -619,12 +622,12 @@ 0x00, 0x00); apdu.cla = ISO_COMMAND_CHAINING; - c_data = NPA_GEN_AUTH_PACE_C_new(); + c_data = EAC_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); + r = i2d_EAC_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -648,7 +651,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Encrypted Nonce) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, + if (!d2i_EAC_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -681,20 +684,20 @@ err: if (c_data) - NPA_GEN_AUTH_PACE_C_free(c_data); + EAC_GEN_AUTH_PACE_C_free(c_data); OPENSSL_free(d); if (r_data) - NPA_GEN_AUTH_PACE_R_free(r_data); + EAC_GEN_AUTH_PACE_R_free(r_data); return r; } -static int npa_gen_auth_2_map_nonce(sc_card_t *card, +static int eac_gen_auth_2_map_nonce(sc_card_t *card, const u8 *in, size_t in_len, u8 **map_data_out, size_t *map_data_out_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_PACE_C *c_data = NULL; - NPA_GEN_AUTH_PACE_R *r_data = NULL; + EAC_GEN_AUTH_PACE_C *c_data = NULL; + EAC_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -703,20 +706,20 @@ 0x00, 0x00); apdu.cla = ISO_COMMAND_CHAINING; - c_data = NPA_GEN_AUTH_PACE_C_new(); + c_data = EAC_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } c_data->mapping_data = ASN1_OCTET_STRING_new(); if (!c_data->mapping_data - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( c_data->mapping_data, in, in_len)) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); + r = i2d_EAC_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -740,7 +743,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Map Nonce) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, + if (!d2i_EAC_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -773,20 +776,20 @@ err: if (c_data) - NPA_GEN_AUTH_PACE_C_free(c_data); + EAC_GEN_AUTH_PACE_C_free(c_data); OPENSSL_free(d); if (r_data) - NPA_GEN_AUTH_PACE_R_free(r_data); + EAC_GEN_AUTH_PACE_R_free(r_data); return r; } -static int npa_gen_auth_3_perform_key_agreement(sc_card_t *card, +static int eac_gen_auth_3_perform_key_agreement(sc_card_t *card, const u8 *in, size_t in_len, u8 **eph_pub_key_out, size_t *eph_pub_key_out_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_PACE_C *c_data = NULL; - NPA_GEN_AUTH_PACE_R *r_data = NULL; + EAC_GEN_AUTH_PACE_C *c_data = NULL; + EAC_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -795,20 +798,20 @@ 0x00, 0x00); apdu.cla = ISO_COMMAND_CHAINING; - c_data = NPA_GEN_AUTH_PACE_C_new(); + c_data = EAC_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } c_data->eph_pub_key = ASN1_OCTET_STRING_new(); if (!c_data->eph_pub_key - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( c_data->eph_pub_key, in, in_len)) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); + r = i2d_EAC_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -832,7 +835,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, + if (!d2i_EAC_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -865,22 +868,22 @@ err: if (c_data) - NPA_GEN_AUTH_PACE_C_free(c_data); + EAC_GEN_AUTH_PACE_C_free(c_data); OPENSSL_free(d); if (r_data) - NPA_GEN_AUTH_PACE_R_free(r_data); + EAC_GEN_AUTH_PACE_R_free(r_data); return r; } -static int npa_gen_auth_4_mutual_authentication(sc_card_t *card, +static int eac_gen_auth_4_mutual_authentication(sc_card_t *card, const u8 *in, size_t in_len, u8 **auth_token_out, size_t *auth_token_out_len, u8 **recent_car, size_t *recent_car_len, u8 **prev_car, size_t *prev_car_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_PACE_C *c_data = NULL; - NPA_GEN_AUTH_PACE_R *r_data = NULL; + EAC_GEN_AUTH_PACE_C *c_data = NULL; + EAC_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -888,20 +891,20 @@ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, ISO_GENERAL_AUTHENTICATE, 0x00, 0x00); - c_data = NPA_GEN_AUTH_PACE_C_new(); + c_data = EAC_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } c_data->auth_token = ASN1_OCTET_STRING_new(); if (!c_data->auth_token - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( c_data->auth_token, in, in_len)) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); + r = i2d_EAC_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -925,7 +928,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, + if (!d2i_EAC_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -982,10 +985,10 @@ err: if (c_data) - NPA_GEN_AUTH_PACE_C_free(c_data); + EAC_GEN_AUTH_PACE_C_free(c_data); OPENSSL_free(d); if (r_data) - NPA_GEN_AUTH_PACE_R_free(r_data); + EAC_GEN_AUTH_PACE_R_free(r_data); return r; } @@ -996,27 +999,27 @@ char *p = NULL; PACE_SEC *r; /* Flawfinder: ignore */ - char buf[MAX_MRZ_LEN > 32 ? MAX_MRZ_LEN : 32]; + char buf[EAC_MAX_MRZ_LEN > 32 ? EAC_MAX_MRZ_LEN : 32]; if (!length_pin || !pin) { if (0 > snprintf(buf, sizeof buf, "Please enter your %s: ", - npa_secret_name(pin_id))) { + eac_secret_name(pin_id))) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not create password prompt.\n"); return NULL; } - p = malloc(MAX_MRZ_LEN+1); + p = malloc(EAC_MAX_MRZ_LEN+1); if (!p) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for %s.\n", - npa_secret_name(pin_id)); + eac_secret_name(pin_id)); return NULL; } - if (0 > EVP_read_pw_string_min(p, 0, MAX_MRZ_LEN, buf, 0)) { + if (0 > EVP_read_pw_string_min(p, 0, EAC_MAX_MRZ_LEN, buf, 0)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read %s.\n", - npa_secret_name(pin_id)); + eac_secret_name(pin_id)); return NULL; } length_pin = strlen(p); - if (length_pin > MAX_MRZ_LEN) { + if (length_pin > EAC_MAX_MRZ_LEN) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "MRZ too long"); return NULL; } @@ -1178,11 +1181,11 @@ eac_ctx->tr_version = tr_version; - r = npa_mse_set_at_pace(card, eac_ctx->pace_ctx->protocol, + r = eac_mse_set_at_pace(card, eac_ctx->pace_ctx->protocol, pace_input.pin_id, chat, &pace_output->mse_set_at_sw1, &pace_output->mse_set_at_sw2); if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties " + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol properties " "(MSE: Set AT failed)."); goto err; } @@ -1193,7 +1196,7 @@ r = SC_ERROR_OUT_OF_MEMORY; goto err; } - r = npa_gen_auth_1_encrypted_nonce(card, (u8 **) &enc_nonce->data, + r = eac_gen_auth_1_encrypted_nonce(card, (u8 **) &enc_nonce->data, &enc_nonce->length); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get encrypted nonce from card " @@ -1227,7 +1230,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_gen_auth_2_map_nonce(card, (u8 *) mdata->data, mdata->length, + r = eac_gen_auth_2_map_nonce(card, (u8 *) mdata->data, mdata->length, (u8 **) &mdata_opp->data, &mdata_opp->length); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange mapping data with card " @@ -1253,7 +1256,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_gen_auth_3_perform_key_agreement(card, (u8 *) pub->data, pub->length, + r = eac_gen_auth_3_perform_key_agreement(card, (u8 *) pub->data, pub->length, (u8 **) &pub_opp->data, &pub_opp->length); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange ephemeral public key with card " @@ -1280,7 +1283,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_gen_auth_4_mutual_authentication(card, (u8 *) token->data, token->length, + r = eac_gen_auth_4_mutual_authentication(card, (u8 *) token->data, token->length, (u8 **) &token_opp->data, &token_opp->length, &pace_output->recent_car, &pace_output->recent_car_length, &pace_output->previous_car, &pace_output->previous_car_length); @@ -1341,7 +1344,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "ID PCD", pace_output->id_pcd, pace_output->id_pcd_length); - r = npa_sm_start(card, eac_ctx, pace_input.certificate_description, + r = eac_sm_start(card, eac_ctx, pace_input.certificate_description, pace_input.certificate_description_length, pace_output->id_icc, pace_output->id_icc_length); } @@ -1379,24 +1382,24 @@ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } -static int npa_mse_set_at_ta(sc_card_t *card, int protocol, +static int eac_mse_set_at_ta(sc_card_t *card, int protocol, const unsigned char *chr, size_t chr_len, const unsigned char *eph_pub_key, size_t eph_pub_key_len, const unsigned char *auxiliary_data, size_t auxiliary_data_len) { - return npa_mse_set_at(card, 0x81, protocol, chr, chr_len, NULL, 0, + return eac_mse_set_at(card, 0x81, protocol, chr, chr_len, NULL, 0, eph_pub_key, eph_pub_key_len, auxiliary_data, auxiliary_data_len, NULL, NULL, NULL); } -static int npa_mse_set_dst(sc_card_t *card, +static int eac_mse_set_dst(sc_card_t *card, const unsigned char *chr, size_t chr_len) { - return npa_mse(card, 0x81, 0xb6, 0, chr, chr_len, NULL, 0, NULL, 0, NULL, + return eac_mse(card, 0x81, 0xb6, 0, chr, chr_len, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL); } -static int npa_get_challenge(sc_card_t *card, +static int eac_get_challenge(sc_card_t *card, unsigned char *challenge, size_t len) { sc_apdu_t apdu; @@ -1422,7 +1425,7 @@ return r; } -static int npa_verify(sc_card_t *card, +static int eac_verify(sc_card_t *card, const unsigned char *cert, size_t cert_len) { sc_apdu_t apdu; @@ -1458,7 +1461,7 @@ return r; } -static int npa_external_authenticate(sc_card_t *card, +static int eac_external_authenticate(sc_card_t *card, unsigned char *signature, size_t signature_len) { int r; @@ -1498,7 +1501,7 @@ CVC_CERT *cvc_cert = NULL; BUF_MEM *nonce = NULL, *signature = NULL; struct iso_sm_ctx *isosmctx = NULL; - struct npa_sm_ctx *eacsmctx = NULL; + struct eac_sm_ctx *eacsmctx = NULL; unsigned char *ef_cardaccess = NULL; EAC_CTX *eac_ctx = NULL; @@ -1541,7 +1544,7 @@ goto err; } - isosmctx->priv_data = npa_sm_ctx_create(eac_ctx, NULL, 0, NULL, 0); + isosmctx->priv_data = eac_sm_ctx_create(eac_ctx, NULL, 0, NULL, 0); if (!isosmctx->priv_data) { r = SC_ERROR_INTERNAL; goto err; @@ -1563,16 +1566,16 @@ } cert = *certs; - r = npa_mse_set_dst(card, + r = eac_mse_set_dst(card, cvc_cert->body->certificate_authority_reference->data, cvc_cert->body->certificate_authority_reference->length); if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties " + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol properties " "(MSE: Set AT failed)."); goto err; } - r = npa_verify(card, cert, cert_len); + r = eac_verify(card, cert, cert_len); if (r < 0) goto err; @@ -1600,13 +1603,13 @@ } - r = npa_mse_set_at_ta(card, eacsmctx->ctx->ta_ctx->protocol, + r = eac_mse_set_at_ta(card, eacsmctx->ctx->ta_ctx->protocol, cvc_cert->body->certificate_holder_reference->data, cvc_cert->body->certificate_holder_reference->length, (unsigned char *) eacsmctx->eph_pub_key->data, eacsmctx->eph_pub_key->length, auxiliary_data, auxiliary_data_len); if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties " + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol properties " "(MSE: Set AT failed)."); goto err; } @@ -1617,7 +1620,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_get_challenge(card, (unsigned char *) nonce->data, nonce->length); + r = eac_get_challenge(card, (unsigned char *) nonce->data, nonce->length); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get nonce for TA."); goto err; @@ -1641,7 +1644,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_external_authenticate(card, (unsigned char *) signature->data, + r = eac_external_authenticate(card, (unsigned char *) signature->data, signature->length); err: @@ -1658,18 +1661,18 @@ return r; } -static int npa_mse_set_at_ca(sc_card_t *card, int protocol) +static int eac_mse_set_at_ca(sc_card_t *card, int protocol) { - return npa_mse_set_at(card, 0x41, protocol, NULL, 0, NULL, 0, NULL, 0, + return eac_mse_set_at(card, 0x41, protocol, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL); } -static int npa_gen_auth_ca(sc_card_t *card, const BUF_MEM *eph_pub_key, +static int eac_gen_auth_ca(sc_card_t *card, const BUF_MEM *eph_pub_key, BUF_MEM **nonce, BUF_MEM **token) { sc_apdu_t apdu; - NPA_GEN_AUTH_CA_C *c_data = NULL; - NPA_GEN_AUTH_CA_R *r_data = NULL; + EAC_GEN_AUTH_CA_C *c_data = NULL; + EAC_GEN_AUTH_CA_R *r_data = NULL; unsigned char *d = NULL; int r; unsigned char resp[maxresp]; @@ -1677,20 +1680,21 @@ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, ISO_GENERAL_AUTHENTICATE, 0, 0); - c_data = NPA_GEN_AUTH_CA_C_new(); + c_data = EAC_GEN_AUTH_CA_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } c_data->eph_pub_key = ASN1_OCTET_STRING_new(); if (!c_data->eph_pub_key - || !M_ASN1_OCTET_STRING_set( c_data->eph_pub_key, - eph_pub_key->data, eph_pub_key->length)) { + || !ASN1_OCTET_STRING_set(c_data->eph_pub_key, + (const unsigned char *) eph_pub_key->data, + eph_pub_key->length)) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_CA_C(c_data, &d); + r = i2d_EAC_GEN_AUTH_CA_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -1714,7 +1718,7 @@ sc_debug_hex(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_CA_R(&r_data, + if (!d2i_EAC_GEN_AUTH_CA_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -1744,9 +1748,9 @@ err: if (c_data) - NPA_GEN_AUTH_CA_C_free(c_data); + EAC_GEN_AUTH_CA_C_free(c_data); if (r_data) - NPA_GEN_AUTH_CA_R_free(r_data); + EAC_GEN_AUTH_CA_R_free(r_data); OPENSSL_free(d); return r; @@ -1764,7 +1768,7 @@ int r; BUF_MEM *picc_pubkey = NULL; struct iso_sm_ctx *isosmctx; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card || !ef_cardsecurity || !ef_cardsecurity_len) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -1828,9 +1832,9 @@ } - r = npa_mse_set_at_ca(card, ctx->ca_ctx->protocol); + r = eac_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 " + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol properties " "(MSE: Set AT failed)."); goto err; } @@ -1843,7 +1847,7 @@ r = SC_ERROR_INTERNAL; goto err; } - r = npa_gen_auth_ca(card, eph_pub_key, &nonce, &token); + r = eac_gen_auth_ca(card, eph_pub_key, &nonce, &token); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "(General Authenticate failed)."); goto err; @@ -1875,7 +1879,7 @@ } if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) { - r = npa_sm_start(card, ctx, NULL, 0, NULL, 0); + r = eac_sm_start(card, ctx, NULL, 0, NULL, 0); } err: @@ -1891,7 +1895,7 @@ } static int -increment_ssc(struct npa_sm_ctx *eacsmctx) +increment_ssc(struct eac_sm_ctx *eacsmctx) { if (!eacsmctx) return SC_ERROR_INVALID_ARGUMENTS; @@ -1903,13 +1907,13 @@ } static int -npa_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, u8 **enc) { BUF_MEM *encbuf = NULL, *databuf = NULL; u8 *p = NULL; int r; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card || !ctx || !enc || !ctx->priv_data) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -1945,13 +1949,13 @@ } static int -npa_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *enc, size_t enclen, u8 **data) { BUF_MEM *encbuf = NULL, *databuf = NULL; u8 *p = NULL; int r; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card || !ctx || !enc || !ctx->priv_data || !data) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -1987,13 +1991,13 @@ } static int -npa_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, u8 **macdata) { BUF_MEM *inbuf = NULL, *macbuf = NULL; u8 *p = NULL; int r; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card || !ctx || !ctx->priv_data || !macdata) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -2036,13 +2040,13 @@ } static int -npa_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *mac, size_t maclen, const u8 *macdata, size_t macdatalen) { int r; BUF_MEM *inbuf = NULL, *my_mac = NULL; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card || !ctx || !ctx->priv_data) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -2111,7 +2115,7 @@ return newlen; } static int -npa_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *apdu) { int r; @@ -2120,9 +2124,9 @@ int len; BUF_MEM *signature = NULL; unsigned char *sequence = NULL; - NPA_MSE_C *msesetat = NULL; + EAC_MSE_C *msesetat = NULL; const unsigned char *p; - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card) return SC_ERROR_INVALID_ARGUMENTS; @@ -2132,7 +2136,7 @@ } eacsmctx = ctx->priv_data; - if (!(eacsmctx->flags & NPA_FLAG_DISABLE_CHECK_ALL)) { + if (!(eacsmctx->flags & EAC_FLAG_DISABLE_CHECK_ALL)) { if (apdu->ins == 0x2a && apdu->p1 == 0x00 && apdu->p2 == 0xbe) { /* PSO:Verify Certificate * check certificate description to match given certificate */ @@ -2206,7 +2210,7 @@ len = add_tag(&sequence, 1, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, apdu->data, apdu->datalen); p = sequence; - if (len < 0 || !d2i_NPA_MSE_C(&msesetat, &p, len)) { + if (len < 0 || !d2i_EAC_MSE_C(&msesetat, &p, len)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse MSE:Set AT."); ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -2302,13 +2306,13 @@ if (sequence) OPENSSL_free(sequence); if (msesetat) - NPA_MSE_C_free(msesetat); + EAC_MSE_C_free(msesetat); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } static int -npa_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *sm_apdu) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, @@ -2316,10 +2320,10 @@ } static int -npa_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx, +eac_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx, sc_apdu_t *apdu) { - struct npa_sm_ctx *eacsmctx; + struct eac_sm_ctx *eacsmctx; if (!card) return SC_ERROR_INVALID_ARGUMENTS; if(!ctx || !ctx->priv_data || !apdu) @@ -2327,7 +2331,7 @@ SC_ERROR_INVALID_ARGUMENTS); eacsmctx = ctx->priv_data; - if (!(eacsmctx->flags & NPA_FLAG_DISABLE_CHECK_ALL)) { + if (!(eacsmctx->flags & EAC_FLAG_DISABLE_CHECK_ALL)) { if (apdu->sw1 == 0x90 && apdu->sw2 == 0x00) { if (apdu->ins == 0x84 && apdu->p1 == 0x00 && apdu->p2 == 0x00 && apdu->le == 8 && apdu->resplen == 8) { @@ -2355,10 +2359,10 @@ } static void -npa_sm_clear_free(const struct iso_sm_ctx *ctx) +eac_sm_clear_free(const struct iso_sm_ctx *ctx) { if (ctx) { - struct npa_sm_ctx *eacsmctx = ctx->priv_data; + struct eac_sm_ctx *eacsmctx = ctx->priv_data; EAC_CTX_clear_free(eacsmctx->ctx); if (eacsmctx->certificate_description) BUF_MEM_free(eacsmctx->certificate_description); @@ -2419,7 +2423,7 @@ static const char *PUK_name = "PUK"; static const char *CAN_name = "CAN"; static const char *UNDEF_name = "UNDEF"; -const char *npa_secret_name(enum s_type pin_id) { +const char *eac_secret_name(enum s_type pin_id) { switch (pin_id) { case PACE_MRZ: return MRZ_name; @@ -2434,76 +2438,7 @@ } } -int -npa_reset_retry_counter(sc_card_t *card, enum s_type pin_id, - int ask_for_secret, const char *new, size_t new_len) -{ - sc_apdu_t apdu; - char *p = NULL; - int r; - - if (ask_for_secret && (!new || !new_len)) { - if (!(SC_READER_CAP_PIN_PAD & card->reader->capabilities)) { -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - p = malloc(MAX_PIN_LEN+1); - if (!p) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for new PIN.\n"); - return SC_ERROR_OUT_OF_MEMORY; - } - if (0 > EVP_read_pw_string_min(p, - MIN_PIN_LEN, MAX_PIN_LEN+1, - "Please enter your new PIN: ", 0)) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read new PIN.\n"); - free(p); - return SC_ERROR_INTERNAL; - } - new_len = strlen(p); - if (new_len > MAX_PIN_LEN) - return SC_ERROR_INVALID_PIN_LENGTH; - new = p; -#else - return SC_ERROR_NOT_SUPPORTED; -#endif - } - } - - sc_format_apdu(card, &apdu, 0, 0x2C, 0, pin_id); - apdu.data = (u8 *) new; - apdu.datalen = new_len; - apdu.lc = apdu.datalen; - - if (new_len || ask_for_secret) { - apdu.p1 = 0x02; - apdu.cse = SC_APDU_CASE_3_SHORT; - } else { - apdu.p1 = 0x03; - apdu.cse = SC_APDU_CASE_1; - } - - if (ask_for_secret && !new_len) { - struct sc_pin_cmd_data data; - data.apdu = &apdu; - data.cmd = SC_PIN_CMD_CHANGE; - data.flags = SC_PIN_CMD_IMPLICIT_CHANGE; - data.pin2.encoding = SC_PIN_ENCODING_ASCII; - data.pin2.length_offset = 0; - data.pin2.offset = 5; - data.pin2.max_length = MAX_PIN_LEN; - data.pin2.min_length = MIN_PIN_LEN; - data.pin2.pad_length = 0; - r = card->reader->ops->perform_verify(card->reader, &data); - } else - r = sc_transmit_apdu(card, &apdu); - - if (p) { - sc_mem_clear(p, new_len); - free(p); - } - - return r; -} - -int npa_pace_get_tries_left(sc_card_t *card, +int eac_pace_get_tries_left(sc_card_t *card, enum s_type pin_id, int *tries_left) { int r; @@ -2511,7 +2446,7 @@ if (tries_left) { #if defined(ENABLE_OPENPACE) && defined(ENABLE_SM) - r = npa_mse_set_at_pace(card, 0, pin_id, 0, &sw1, &sw2); + r = eac_mse_set_at_pace(card, 0, pin_id, 0, &sw1, &sw2); #else sc_apdu_t apdu; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, ISO_MSE, 0xC1, 0xA4); @@ -2531,14 +2466,3 @@ return r; } - -int get_pace_capabilities(u8 *bitmap) -{ - if (!bitmap) - return SC_ERROR_INVALID_ARGUMENTS; - - /* BitMap */ - *bitmap = NPA_BITMAP_PACE|NPA_BITMAP_EID|NPA_BITMAP_ESIGN; - - return SC_SUCCESS; -} diff -Nru opensc-0.17.0/src/sm/sm-eac.h opensc-0.19.0/src/sm/sm-eac.h --- opensc-0.17.0/src/sm/sm-eac.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/sm/sm-eac.h 2018-09-13 11:47:21.000000000 +0000 @@ -19,7 +19,7 @@ */ /** * @file - * @defgroup npa Interface to German identity card (neuer Personalausweis, nPA) + * @defgroup eac Interface to Extended Access Control * @{ */ #ifndef _SC_EAC_H @@ -80,50 +80,6 @@ }; #endif -/** @brief NPA capabilities (TR-03119): PACE */ -#define NPA_BITMAP_PACE 0x40 -/** @brief NPA capabilities (TR-03119): EPA: eID */ -#define NPA_BITMAP_EID 0x20 -/** @brief NPA capabilities (TR-03119): EPA: eSign */ -#define NPA_BITMAP_ESIGN 0x10 - -/** @brief NPA result (TR-03119): Kein Fehler */ -#define NPA_SUCCESS 0x00000000 -/** @brief NPA result (TR-03119): Längen im Input sind inkonsistent */ -#define NPA_ERROR_LENGTH_INCONSISTENT 0xD0000001 -/** @brief NPA result (TR-03119): Unerwartete Daten im Input */ -#define NPA_ERROR_UNEXPECTED_DATA 0xD0000002 -/** @brief NPA result (TR-03119): Unerwartete Kombination von Daten im Input */ -#define NPA_ERROR_UNEXPECTED_DATA_COMBINATION 0xD0000003 -/** @brief NPA result (TR-03119): Die Karte unterstützt das PACE – Verfahren nicht. (Unerwartete Struktur in Antwortdaten der Karte) */ -#define NPA_ERROR_CARD_NOT_SUPPORTED 0xE0000001 -/** @brief NPA result (TR-03119): Der Kartenleser unterstützt den angeforderten bzw. den ermittelten Algorithmus nicht. */ -#define NPA_ERROR_ALGORITH_NOT_SUPPORTED 0xE0000002 -/** @brief NPA result (TR-03119): Der Kartenleser kennt die PIN – ID nicht. */ -#define NPA_ERROR_PINID_NOT_SUPPORTED 0xE0000003 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf Select EF_CardAccess (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_SELECT_EF_CARDACCESS 0xF0000000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf Read Binary (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_READ_BINARY 0xF0010000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf MSE: Set AT (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_MSE_SET_AT 0xF0020000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 1 (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_GENERAL_AUTHENTICATE_1 0xF0030000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 2 (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_GENERAL_AUTHENTICATE_2 0xF0040000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 3 (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_GENERAL_AUTHENTICATE_3 0xF0050000 -/** @brief NPA result (TR-03119): Negative Antwort der Karte auf General Authenticate Step 4 (needs to be OR-ed with SW1|SW2) */ -#define NPA_ERROR_GENERAL_AUTHENTICATE_4 0xF0060000 -/** @brief NPA result (TR-03119): Kommunikationsabbruch mit Karte. */ -#define NPA_ERROR_COMMUNICATION 0xF0100001 -/** @brief NPA result (TR-03119): Keine Karte im Feld. */ -#define NPA_ERROR_NO_CARD 0xF0100002 -/** @brief NPA result (TR-03119): Benutzerabbruch. */ -#define NPA_ERROR_ABORTED 0xF0200001 -/** @brief NPA result (TR-03119): Benutzer – Timeout */ -#define NPA_ERROR_TIMEOUT 0xF0200002 - /** @brief File identifier of EF.CardAccess */ #define FID_EF_CARDACCESS 0x011C /** @brief Short file identifier of EF.CardAccess */ @@ -134,17 +90,17 @@ #define SFID_EF_CARDSECURITY 0x1D /** @brief Maximum length of PIN */ -#define MAX_PIN_LEN 6 +#define EAC_MAX_PIN_LEN 6 /** @brief Minimum length of PIN */ -#define MIN_PIN_LEN 6 +#define EAC_MIN_PIN_LEN 6 /** @brief Length of CAN */ -#define CAN_LEN 6 +#define EAC_CAN_LEN 6 /** @brief Minimum length of MRZ */ -#define MAX_MRZ_LEN 128 +#define EAC_MAX_MRZ_LEN 128 /** @brief Number of retries for PIN */ -#define MAX_PIN_TRIES 3 +#define EAC_MAX_PIN_TRIES 3 /** @brief Usage counter of PIN in suspended state */ -#define UC_PIN_SUSPENDED 1 +#define EAC_UC_PIN_SUSPENDED 1 /** @@ -154,18 +110,7 @@ * * @return Printable string containing the name */ -const char *npa_secret_name(enum s_type pin_id); - - -/** - * @brief Get the PACE capabilities - * - * @param[in,out] bitmap where to store capabilities bitmap - * @note Since this code offers no support for terminal certificate, the bitmap is always \c PACE_BITMAP_PACE|PACE_BITMAP_EID - * - * @return \c SC_SUCCESS or error code if an error occurred - */ -int get_pace_capabilities(u8 *bitmap); +const char *eac_secret_name(enum s_type pin_id); /** * @brief Establish secure messaging using PACE @@ -233,25 +178,8 @@ 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 - * - * According to TR-03110 the reset retry counter APDU is used to set a new PIN - * or to reset the retry counter of the PIN. The standard requires this - * operation to be authorized either by an established PACE channel or by the - * effective authorization of the terminal's certificate. - * - * @param[in] card - * @param[in] pin_id Type of secret (usually PIN or CAN). You may use enum s_type from \c . - * @param[in] ask_for_secret whether to ask the user for the secret (\c 1) or not (\c 0) - * @param[in] new (optional) new secret - * @param[in] new_len (optional) length of \a new - * - * @return \c SC_SUCCESS or error code if an error occurred - */ -int npa_reset_retry_counter(sc_card_t *card, - enum s_type pin_id, int ask_for_secret, - const char *new, size_t new_len); +/** @brief Disable all sanity checks done by OpenSC */ +#define EAC_FLAG_DISABLE_CHECK_ALL 1 /** * @brief Sends an MSE:Set AT to determine the number of remaining tries @@ -262,34 +190,16 @@ * * @return \c SC_SUCCESS or error code if an error occurred */ -int npa_pace_get_tries_left(sc_card_t *card, +int eac_pace_get_tries_left(sc_card_t *card, enum s_type pin_id, int *tries_left); -/** - * @brief Send APDU to unblock the PIN - * - * @param[in] card - */ -#define npa_unblock_pin(card) \ - npa_reset_retry_counter(card, PACE_PIN, 0, NULL, 0) -/** - * @brief Send APDU to set a new PIN - * - * @param[in] card - * @param[in] newp (optional) new PIN - * @param[in] newplen (optional) length of \a new - */ -#define npa_change_pin(card, newp, newplen) \ - npa_reset_retry_counter(card, PACE_PIN, 1, newp, newplen) -/** @brief Disable all sanity checks done by libnpa */ -#define NPA_FLAG_DISABLE_CHECK_ALL 1 /** @brief Disable checking validity period of CV certificates */ -#define NPA_FLAG_DISABLE_CHECK_TA 2 +#define EAC_FLAG_DISABLE_CHECK_TA 2 /** @brief Disable checking passive authentication during CA */ -#define NPA_FLAG_DISABLE_CHECK_CA 4 +#define EAC_FLAG_DISABLE_CHECK_CA 4 -/** @brief Use \c npa_default_flags to disable checks for EAC/SM */ -extern char npa_default_flags; +/** @brief Use \c eac_default_flags to disable checks for EAC/SM */ +extern char eac_default_flags; #ifdef __cplusplus } diff -Nru opensc-0.17.0/src/sm/sm-iso.c opensc-0.19.0/src/sm/sm-iso.c --- opensc-0.17.0/src/sm/sm-iso.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/sm/sm-iso.c 2018-09-13 11:47:21.000000000 +0000 @@ -156,15 +156,15 @@ switch (*le_len) { case 1: - p[0] = le; + p[0] = le & 0xff; break; case 2: - p[0] = le >> 8; + p[0] = (le >> 8) & 0xff; p[1] = le & 0xff; break; case 3: p[0] = 0x00; - p[1] = le >> 8; + p[1] = (le >> 8) & 0xff; p[2] = le & 0xff; break; default: diff -Nru opensc-0.17.0/src/sm/sm-iso-internal.h opensc-0.19.0/src/sm/sm-iso-internal.h --- opensc-0.17.0/src/sm/sm-iso-internal.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/sm/sm-iso-internal.h 2018-09-13 11:47:21.000000000 +0000 @@ -72,7 +72,7 @@ int iso_free_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu); /** - * @brief Cleans up allocated ressources of the ISO SM driver + * @brief Cleans up allocated resources of the ISO SM driver * * \c iso_sm_close() is designed as SM card operation. However, have in mind * that this card operation is not called automatically for \c diff -Nru opensc-0.17.0/src/smm/Makefile.am opensc-0.19.0/src/smm/Makefile.am --- opensc-0.17.0/src/smm/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/smm/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -2,7 +2,7 @@ MAINTAINERCLEANFILES = Makefile.in -EXTRA_DIST = Makefile.mak +EXTRA_DIST = Makefile.mak smm-local.dll.manifest AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/common -I$(top_builddir)/src/include diff -Nru opensc-0.17.0/src/smm/Makefile.mak opensc-0.19.0/src/smm/Makefile.mak --- opensc-0.17.0/src/smm/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/smm/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -3,7 +3,17 @@ TARGET = smm-local.dll OBJECTS = smm-local.obj sm-global-platform.obj sm-cwa14890.obj sm-card-iasecc.obj sm-card-authentic.obj -LIBS = $(TOPDIR)\src\sm\libsm.lib $(TOPDIR)\src\libopensc\opensc_a.lib $(TOPDIR)\src\common\libscdl.lib +LIBS = $(TOPDIR)\src\sm\libsm.lib \ + $(TOPDIR)\src\libopensc\opensc_a.lib \ + $(TOPDIR)\src\pkcs15init\pkcs15init.lib \ + $(TOPDIR)\src\scconf\scconf.lib \ + $(TOPDIR)\src\common\common.lib \ + $(TOPDIR)\src\common\libscdl.lib \ + $(TOPDIR)\src\ui\strings.lib \ + $(TOPDIR)\src\ui\notify.lib \ + $(TOPDIR)\src\sm\libsmiso.lib \ + $(TOPDIR)\src\sm\libsmeac.lib \ + $(TOPDIR)\src\pkcs15init\pkcs15init.lib all: $(TARGET) @@ -14,7 +24,7 @@ echo LIBRARY $* > $*.def echo EXPORTS >> $*.def type $*.exports >> $*.def - 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 + 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 Shell32.lib Comctl32.lib if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2 !ELSE diff -Nru opensc-0.17.0/src/smm/sm-card-authentic.c opensc-0.19.0/src/smm/sm-card-authentic.c --- opensc-0.17.0/src/smm/sm-card-authentic.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/smm/sm-card-authentic.c 2018-09-13 11:47:21.000000000 +0000 @@ -80,7 +80,7 @@ sc_log(ctx, "key_buf:%s", sc_dump_hex(key_buff, 16)); rv = sm_encrypt_des_ecb3(master_key, key_buff, sizeof(key_buff), &tmp, &tmp_len); - LOG_TEST_RET(ctx, rv, "GP init session: cannot derivate key"); + LOG_TEST_RET(ctx, rv, "GP init session: cannot derive key"); memcpy(keys[ii], tmp, sizeof(gp_keyset->enc)); free(tmp); @@ -91,24 +91,11 @@ } if (!rv && ctx) { - char dump_buf[2048]; - - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, - gp_session->card_challenge, sizeof(gp_session->card_challenge), dump_buf, sizeof(dump_buf)); - sc_log(ctx, "Card challenge: %s", dump_buf); - - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, - gp_session->host_challenge, sizeof(gp_session->host_challenge), dump_buf, sizeof(dump_buf)); - sc_log(ctx, "Host challenge: %s", dump_buf); - - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, gp_keyset->enc, sizeof(gp_keyset->enc), dump_buf, sizeof(dump_buf)); - sc_log(ctx, "ENC: %s", dump_buf); - - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, gp_keyset->mac, sizeof(gp_keyset->mac), dump_buf, sizeof(dump_buf)); - sc_log(ctx, "MAC: %s", dump_buf); - - sc_hex_dump(ctx, SC_LOG_DEBUG_NORMAL, gp_keyset->kek, sizeof(gp_keyset->kek), dump_buf, sizeof(dump_buf)); - sc_log(ctx, "KEK: %s", dump_buf); + sc_log_hex(ctx, "Card challenge", gp_session->card_challenge, sizeof(gp_session->card_challenge)); + sc_log_hex(ctx, "Host challenge", gp_session->host_challenge, sizeof(gp_session->host_challenge)); + sc_log_hex(ctx, "ENC", gp_keyset->enc, sizeof(gp_keyset->enc)); + sc_log_hex(ctx, "MAC", gp_keyset->mac, sizeof(gp_keyset->mac)); + sc_log_hex(ctx, "KEK", gp_keyset->kek, sizeof(gp_keyset->kek)); } return rv; diff -Nru opensc-0.17.0/src/smm/sm-card-iasecc.c opensc-0.19.0/src/smm/sm-card-iasecc.c --- opensc-0.17.0/src/smm/sm-card-iasecc.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/smm/sm-card-iasecc.c 2018-09-13 11:47:21.000000000 +0000 @@ -248,7 +248,7 @@ rapdu->apdu.p1 = 0x00; rapdu->apdu.p2 = pin_data->pin_reference & ~IASECC_OBJECT_REF_GLOBAL; if (pin_data->pin1.len > SM_MAX_DATA_SIZE) - LOG_TEST_RET(ctx, rv, "SM get 'VERIFY PIN' APDU: invelid PIN size"); + LOG_TEST_RET(ctx, rv, "SM get 'VERIFY PIN' APDU: invalid PIN size"); memcpy((unsigned char *)rapdu->apdu.data, pin_data->pin1.data, pin_data->pin1.len); rapdu->apdu.datalen = pin_data->pin1.len; @@ -637,7 +637,7 @@ if (out && out_len) { if (out_len < offs + decrypted_len) - LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "IAS/ECC decode answer(s): unsufficient output buffer size"); + LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "IAS/ECC decode answer(s): insufficient output buffer size"); memcpy(out + offs, decrypted, decrypted_len); diff -Nru opensc-0.17.0/src/smm/smm-local.dll.manifest opensc-0.19.0/src/smm/smm-local.dll.manifest --- opensc-0.17.0/src/smm/smm-local.dll.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/smm/smm-local.dll.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/tests/lottery.c opensc-0.19.0/src/tests/lottery.c --- opensc-0.17.0/src/tests/lottery.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tests/lottery.c 2018-09-13 11:47:21.000000000 +0000 @@ -24,7 +24,7 @@ struct timeval tv1, tv2; u8 buf[14]; - i = sc_test_init(&argc, argv); + sc_test_init(&argc, argv); for (i = 0; i < 39; i++) freq[i] = 0; c = 0; diff -Nru opensc-0.17.0/src/tests/Makefile.am opensc-0.19.0/src/tests/Makefile.am --- opensc-0.17.0/src/tests/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tests/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -3,7 +3,7 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in EXTRA_DIST = Makefile.mak -SUBDIRS = regression +SUBDIRS = regression p11test noinst_PROGRAMS = base64 lottery p15dump pintest prngtest AM_CPPFLAGS = -I$(top_srcdir)/src diff -Nru opensc-0.17.0/src/tests/p11test/cert.cfg opensc-0.19.0/src/tests/p11test/cert.cfg --- opensc-0.17.0/src/tests/p11test/cert.cfg 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/cert.cfg 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,6 @@ +organization = "OpenSC" +expiration_days = 365 +email = "none@example.org" +signing_key +encryption_key + diff -Nru opensc-0.17.0/src/tests/p11test/Makefile.am opensc-0.19.0/src/tests/p11test/Makefile.am --- opensc-0.17.0/src/tests/p11test/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,30 @@ +include $(top_srcdir)/win32/ltrc.inc + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +EXTRA_DIST = Makefile.mak + +noinst_PROGRAMS = p11test +noinst_HEADERS = p11test_loader.h p11test_case_common.h \ + p11test_case_readonly.h p11test_case_multipart.h \ + p11test_case_mechs.h p11test_case_ec_sign.h \ + p11test_case_usage.h p11test_case_wait.h \ + p11test_case_pss_oaep.h p11test_helpers.h + +AM_CPPFLAGS = -I$(top_srcdir)/src + +p11test_SOURCES = p11test.c p11test_loader.c \ + p11test_case_common.c \ + p11test_case_readonly.c \ + p11test_case_multipart.c \ + p11test_case_mechs.c \ + p11test_case_ec_sign.c \ + p11test_case_usage.c \ + p11test_case_wait.c \ + p11test_case_pss_oaep.c \ + p11test_helpers.c +p11test_CFLAGS = -DNDEBUG $(CMOCKA_CFLAGS) +p11test_LDADD = $(OPTIONAL_OPENSSL_LIBS) $(CMOCKA_LIBS) + +if WIN32 +p11test_SOURCES += $(top_builddir)/win32/versioninfo.rc +endif diff -Nru opensc-0.17.0/src/tests/p11test/Makefile.mak opensc-0.19.0/src/tests/p11test/Makefile.mak --- opensc-0.17.0/src/tests/p11test/Makefile.mak 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,26 @@ +TOPDIR = ..\..\.. + +TARGETS = p11test.exe + +OBJECTS = p11test_loader.obj \ + p11test_case_common.obj \ + p11test_case_readonly.obj \ + p11test_case_multipart.obj \ + p11test_case_mechs.obj \ + p11test_case_ec_sign.obj \ + p11test_case_usage.obj \ + p11test_case_wait.obj \ + p11test_case_pss_oaep.obj \ + p11test_helpers.obj \ + $(TOPDIR)\win32\versioninfo.res + +all: $(TARGETS) + +!INCLUDE $(TOPDIR)\win32\Make.rules.mak + +$(TARGETS): $(OBJECTS) $(LIBS) + +.c.exe: + cl $(COPTS) /c $< + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) + if EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;1 diff -Nru opensc-0.17.0/src/tests/p11test/p11test.c opensc-0.19.0/src/tests/p11test/p11test.c --- opensc-0.17.0/src/tests/p11test/p11test.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * p11test.c: Test suite for PKCS#11 API + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "p11test_helpers.h" + +#include "p11test_case_readonly.h" +#include "p11test_case_multipart.h" +#include "p11test_case_ec_sign.h" +#include "p11test_case_usage.h" +#include "p11test_case_mechs.h" +#include "p11test_case_wait.h" +#include "p11test_case_pss_oaep.h" + +#define DEFAULT_P11LIB "../../pkcs11/.libs/opensc-pkcs11.so" + +void display_usage() { + fprintf(stdout, + " Usage:\n" + " ./p11test [-m module_path] [-s slot_id] [-p pin]\n" + " -m module_path Path to tested module (e.g. /usr/lib64/opensc-pkcs11.so)\n" + " Default is "DEFAULT_P11LIB"\n" + " -p pin Application PIN\n" + " -s slot_id Slot ID with the card\n" + " -i Wait for the card before running the test (interactive)\n" + " -o File to write a log in JSON\n" + " -h This help\n" + "\n"); +} + +int main(int argc, char** argv) { + char command; + const struct CMUnitTest readonly_tests_without_initialization[] = { + /* Test card events on slot */ + cmocka_unit_test_setup_teardown(wait_test, + token_initialize, token_cleanup), + + /* Check all the mechanisms provided by the token */ + cmocka_unit_test_setup_teardown(supported_mechanisms_test, + token_setup, token_cleanup), + + /* Complex readonly test of all objects on the card */ + cmocka_unit_test_setup_teardown(readonly_tests, + user_login_setup, after_test_cleanup), + + /* Multipart signatures and encryption */ + cmocka_unit_test_setup_teardown(multipart_tests, + user_login_setup, after_test_cleanup), + + /* Regression test Sign&Verify with various data lengths */ + cmocka_unit_test_setup_teardown(ec_sign_size_test, + user_login_setup, after_test_cleanup), + + /* Verify that the Usage flags on the objects are sane */ + cmocka_unit_test_setup_teardown(usage_test, + user_login_setup, after_test_cleanup), + + /* Verify that RSA-PSS and RSA-OAEP functions if supported */ + cmocka_unit_test_setup_teardown(pss_oaep_test, + user_login_setup, after_test_cleanup), + }; + + token.library_path = NULL; + token.pin = NULL; + token.pin_length = 0; + token.interactive = 0; + token.slot_id = (unsigned long) -1; + token.log.outfile = NULL; + + while ((command = getopt(argc, argv, "?hm:s:p:io:")) != -1) { + switch (command) { + case 'o': + token.log.outfile = strdup(optarg); + break; + case 'm': + token.library_path = strdup(optarg); + break; + case 's': + token.slot_id = atol(optarg); + break; + case 'p': + token.pin = (CK_UTF8CHAR*) strdup(optarg); + token.pin_length = strlen(optarg); + break; + case 'i': + token.interactive = 1; + break; + case 'h': + case '?': + display_usage(); + return 0; + default: + break; + } + } + + if (token.library_path == NULL) { + debug_print("Falling back to the default library " DEFAULT_P11LIB); + token.library_path = strdup(DEFAULT_P11LIB); + } + + if (token.pin == NULL || token.pin_length == 0) { + printf("No PIN specified. Please, specify it on command-line using -p switch\n"); + return -1; + } + + debug_print("Card info:\n\tPIN %s\n\tPIN LENGTH %lu\n\t", + token.pin, token.pin_length); + + return cmocka_run_group_tests(readonly_tests_without_initialization, + group_setup, group_teardown); +} + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_common.c opensc-0.19.0/src/tests/p11test/p11test_case_common.c --- opensc-0.17.0/src/tests/p11test/p11test_case_common.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_common.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,731 @@ +/* + * p11test_case_common.c: Functions shared between test cases. + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" + +char name_buffer[11]; +char flag_buffer[11]; + +/** + * If the object enforces re-authentication, do it now. + */ +void always_authenticate(test_cert_t *o, token_info_t *info) +{ + CK_RV rv; + if (!o->always_auth) + return; + + rv = info->function_pointer->C_Login(info->session_handle, + CKU_CONTEXT_SPECIFIC, info->pin, info->pin_length); + if (rv != CKR_OK) { + fail_msg(" [ SKIP %s ] Re-authentication failed", o->id_str); + } +} + +/** + * Allocate new place for next certificate to store in the list + * and return pointer to this object + */ +test_cert_t * +add_object(test_certs_t *objects, CK_ATTRIBUTE key_id, CK_ATTRIBUTE label) +{ + test_cert_t *o = NULL; + objects->count = objects->count+1; + objects->data = realloc(objects->data, objects->count * sizeof(test_cert_t)); + if (objects->data == NULL) + return NULL; + + o = &(objects->data[objects->count - 1]); + o->private_handle = CK_INVALID_HANDLE; + o->public_handle = CK_INVALID_HANDLE; + o->always_auth = 0; + o->bits = 0; + o->verify_public = 0; + o->num_mechs = 0; + o->type = -1; + o->sign = 0; + o->verify = 0; + o->decrypt = 0; + o->encrypt = 0; + o->wrap = 0; + o->unwrap = 0; + o->derive_priv = 0; + o->derive_pub = 0; + o->key_type = -1; + o->x509 = NULL; /* The "reuse" capability of d2i_X509() is strongly discouraged */ + o->key.rsa = NULL; + o->key.ec = NULL; + + /* Store the passed CKA_ID and CKA_LABEL */ + o->key_id = malloc(key_id.ulValueLen); + memcpy(o->key_id, key_id.pValue, key_id.ulValueLen); + o->key_id_size = key_id.ulValueLen; + o->id_str = convert_byte_string(o->key_id, o->key_id_size); + o->label = malloc(label.ulValueLen + 1); + strncpy(o->label, label.pValue, label.ulValueLen); + o->label[label.ulValueLen] = '\0'; + + return o; +} + +/* + * Search for certificate in the list by ID and return pointer to it + */ +test_cert_t * search_certificate(test_certs_t *objects, CK_ATTRIBUTE *id) +{ + unsigned int i = 0; + + while (i < objects->count && (objects->data[i].key_id_size != id->ulValueLen || + memcmp(objects->data[i].key_id, id->pValue, id->ulValueLen) != 0)) + i++; + + if (i == objects->count) + return NULL; + + return &(objects->data[i]); +} + +static void +add_supported_mechs(test_cert_t *o) +{ + size_t i; + + if (o->type == EVP_PK_RSA) { + if (token.num_rsa_mechs > 0 ) { + /* Get supported mechanisms by token */ + o->num_mechs = token.num_rsa_mechs; + for (i = 0; i <= token.num_rsa_mechs; i++) { + o->mechs[i].mech = token.rsa_mechs[i].mech; + o->mechs[i].result_flags = 0; + o->mechs[i].usage_flags = + token.rsa_mechs[i].usage_flags; + } + } else { + /* Use the default list */ + o->num_mechs = 1; + o->mechs[0].mech = CKM_RSA_PKCS; + o->mechs[0].result_flags = 0; + o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY + | CKF_ENCRYPT | CKF_DECRYPT; + } + } else if (o->type == EVP_PK_EC) { + if (token.num_ec_mechs > 0 ) { + o->num_mechs = token.num_ec_mechs; + for (i = 0; i <= token.num_ec_mechs; i++) { + o->mechs[i].mech = token.ec_mechs[i].mech; + o->mechs[i].result_flags = 0; + o->mechs[i].usage_flags = + token.ec_mechs[i].usage_flags; + } + } else { + /* Use the default list */ + o->num_mechs = 1; + o->mechs[0].mech = CKM_ECDSA; + o->mechs[0].result_flags = 0; + o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY; + } + } +} + +/** + * Allocate place in the structure for every certificate found + * and store related information + */ +int callback_certificates(test_certs_t *objects, + CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle) +{ + EVP_PKEY *evp = NULL; + const u_char *cp; + test_cert_t *o = NULL; + + if (*(CK_CERTIFICATE_TYPE *)template[3].pValue != CKC_X_509) + return 0; + + if ((o = add_object(objects, template[0], template[2])) == NULL) + return -1; + + /* Extract public key from the certificate */ + cp = template[1].pValue; + if (d2i_X509(&(o->x509), &cp, template[1].ulValueLen) == NULL) { + fail_msg("d2i_X509"); + } else if ((evp = X509_get_pubkey(o->x509)) == NULL) { + fail_msg("X509_get_pubkey failed."); + } + + if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) { + /* Extract public RSA key */ + RSA *rsa = EVP_PKEY_get0_RSA(evp); + if ((o->key.rsa = RSAPublicKey_dup(rsa)) == NULL) + fail_msg("RSAPublicKey_dup failed"); + o->type = EVP_PK_RSA; + o->bits = EVP_PKEY_bits(evp); + + } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { + /* Extract public EC key */ + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(evp); + if ((o->key.ec = EC_KEY_dup(ec)) == NULL) + fail_msg("EC_KEY_dup failed"); + o->type = EVP_PK_EC; + o->bits = EVP_PKEY_bits(evp); + + } else { + fprintf(stderr, "[WARN %s ]evp->type = 0x%.4X (not RSA, EC)\n", + o->id_str, EVP_PKEY_id(evp)); + } + EVP_PKEY_free(evp); + + debug_print(" [ OK %s ] Certificate with label %s loaded successfully", + o->id_str, o->label); + return 0; +} + +/** + * Pair found private keys on the card with existing certificates + */ +int callback_private_keys(test_certs_t *objects, + CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle) +{ + test_cert_t *o = NULL; + char *key_id; + + /* Search for already stored certificate with same ID */ + if ((o = search_certificate(objects, &(template[3]))) == NULL) { + key_id = convert_byte_string(template[3].pValue, + template[3].ulValueLen); + fprintf(stderr, "Can't find certificate for private key with ID %s\n", key_id); + free(key_id); + + fprintf(stderr, "Let's create a bogus structure without certificate data\n"); + if ((o = add_object(objects, template[3], template[7])) == NULL) + return -1; + } + + if (o->private_handle != CK_INVALID_HANDLE) { + key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen); + fprintf(stderr, "Object already filled? ID %s\n", key_id); + free(key_id); + return -1; + } + + /* Store attributes, flags and handles */ + o->private_handle = object_handle; + o->sign = (template[0].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[0].pValue) : CK_FALSE; + o->decrypt = (template[1].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[1].pValue) : CK_FALSE; + o->key_type = (template[2].ulValueLen != (CK_ULONG) -1) + ? *((CK_KEY_TYPE *) template[2].pValue) : (CK_KEY_TYPE) -1; + o->always_auth = (template[4].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[4].pValue) : CK_FALSE; + o->unwrap = (template[5].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[5].pValue) : CK_FALSE; + o->derive_priv = (template[6].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[6].pValue) : CK_FALSE; + + debug_print(" [ OK %s ] Private key loaded successfully S:%d D:%d T:%02lX", + o->id_str, o->sign, o->decrypt, o->key_type); + return 0; +} + +/** + * Pair found public keys on the card with existing certificates + */ +int callback_public_keys(test_certs_t *objects, + CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle) +{ + test_cert_t *o = NULL; + char *key_id; + + /* Search for already stored certificate with same ID */ + if ((o = search_certificate(objects, &(template[3]))) == NULL) { + key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen); + fprintf(stderr, "Can't find certificate for public key with ID %s\n", key_id); + free(key_id); + return -1; + } + + if (o->verify_public != 0) { + key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen); + fprintf(stderr, "Object already filled? ID %s\n", key_id); + free(key_id); + return -1; + } + + o->public_handle = object_handle; + o->verify = (template[0].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[0].pValue) : CK_FALSE; + o->encrypt = (template[1].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[1].pValue) : CK_FALSE; + /* store key type in case there is no corresponding private key */ + o->key_type = (template[2].ulValueLen != (CK_ULONG) -1) + ? *((CK_KEY_TYPE *) template[2].pValue) : (CK_KEY_TYPE) -1; + o->wrap = (template[8].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[8].pValue) : CK_FALSE; + o->derive_pub = (template[9].ulValueLen != (CK_ULONG) -1) + ? *((CK_BBOOL *) template[9].pValue) : CK_FALSE; + + /* check if we get the same public key as from the certificate */ + if (o->key_type == CKK_RSA) { + BIGNUM *n = NULL, *e = NULL; + n = BN_bin2bn(template[4].pValue, template[4].ulValueLen, NULL); + e = BN_bin2bn(template[5].pValue, template[5].ulValueLen, NULL); + if (o->key.rsa != NULL) { + const BIGNUM *cert_n = NULL, *cert_e = NULL; + RSA_get0_key(o->key.rsa, &cert_n, &cert_e, NULL); + if (BN_cmp(cert_n, n) != 0 || + BN_cmp(cert_e, e) != 0) { + debug_print(" [WARN %s ] Got different public key then from the certificate", + o->id_str); + BN_free(n); + BN_free(e); + return -1; + } + BN_free(n); + BN_free(e); + o->verify_public = 1; + } else { /* store the public key for future use */ + o->type = EVP_PK_RSA; + o->key.rsa = RSA_new(); + RSA_set0_key(o->key.rsa, n, e, NULL); + n = NULL; + e = NULL; + } + } else if (o->key_type == CKK_EC) { + ASN1_OBJECT *oid = NULL; + ASN1_OCTET_STRING *s = NULL; + const unsigned char *pub, *p; + BIGNUM *bn = NULL; + EC_POINT *ecpoint; + EC_GROUP *ecgroup; + int nid, pub_len; + + /* Parse the nid out of the EC_PARAMS */ + p = template[6].pValue; + oid = d2i_ASN1_OBJECT(NULL, &p, template[6].ulValueLen); + nid = OBJ_obj2nid(oid); + ASN1_OBJECT_free(oid); + ecgroup = EC_GROUP_new_by_curve_name(nid); + EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE); + + p = template[7].pValue; + s = d2i_ASN1_OCTET_STRING(NULL, &p, template[7].ulValueLen); + pub = ASN1_STRING_get0_data(s); + pub_len = ASN1_STRING_length(s); + bn = BN_bin2bn(pub, pub_len, NULL); + ASN1_STRING_free(s); + if (bn == NULL) { + debug_print(" [WARN %s ] Can not convert EC_POINT from" + "PKCS#11 to BIGNUM", o->id_str); + EC_GROUP_free(ecgroup); + return -1; + } + + ecpoint = EC_POINT_bn2point(ecgroup, bn, NULL, NULL); + BN_free(bn); + if (ecpoint == NULL) { + debug_print(" [WARN %s ] Can not convert EC_POINT from" + "BIGNUM to OpenSSL format", o->id_str); + EC_GROUP_free(ecgroup); + return -1; + } + + if (o->key.ec != NULL) { + const EC_GROUP *cert_group = EC_KEY_get0_group(o->key.ec); + const EC_POINT *cert_point = EC_KEY_get0_public_key(o->key.ec); + int cert_nid = EC_GROUP_get_curve_name(cert_group); + + if (cert_nid != nid || + EC_GROUP_cmp(cert_group, ecgroup, NULL) != 0 || + EC_POINT_cmp(ecgroup, cert_point, ecpoint, NULL) != 0) { + debug_print(" [WARN %s ] Got different public" + "key then from the certificate", + o->id_str); + EC_GROUP_free(ecgroup); + EC_POINT_free(ecpoint); + return -1; + } + EC_GROUP_free(ecgroup); + EC_POINT_free(ecpoint); + o->verify_public = 1; + } else { /* store the public key for future use */ + o->type = EVP_PK_EC; + o->key.ec = EC_KEY_new_by_curve_name(nid); + EC_KEY_set_public_key(o->key.ec, ecpoint); + EC_KEY_set_group(o->key.ec, ecgroup); + } + } else { + debug_print(" [WARN %s ] non-RSA, non-EC key. Key type: %02lX", + o->id_str, o->key_type); + return -1; + } + + add_supported_mechs(o); + + debug_print(" [ OK %s ] Public key loaded successfully V:%d E:%d T:%02lX", + o->id_str, o->verify, o->encrypt, o->key_type); + return 0; +} + +int search_objects(test_certs_t *objects, token_info_t *info, + CK_ATTRIBUTE filter[], CK_LONG filter_size, CK_ATTRIBUTE template[], CK_LONG template_size, + int (*callback)(test_certs_t *, CK_ATTRIBUTE[], unsigned int, CK_OBJECT_HANDLE)) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_ULONG object_count; + CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE_PTR object_handles = NULL; + unsigned long i = 0, objects_length = 0; + int j; + + /* FindObjects first + * https://wiki.oasis-open.org/pkcs11/CommonBugs + */ + rv = fp->C_FindObjectsInit(info->session_handle, filter, filter_size); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: rv = 0x%.8lX\n", rv); + return -1; + } + + while(1) { + rv = fp->C_FindObjects(info->session_handle, &object_handle, 1, &object_count); + if (object_count == 0) + break; + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: rv = 0x%.8lX\n", rv); + return -1; + } + /* store handle */ + if (i >= objects_length) { + objects_length += 4; // do not realloc after each row + object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE_PTR)); + if (object_handles == NULL) + fail_msg("Realloc failed. Need to store object handles.\n"); + } + object_handles[i++] = object_handle; + } + objects_length = i; //terminate list of handles + + rv = fp->C_FindObjectsFinal(info->session_handle); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: rv = 0x%.8lX\n", rv); + fail_msg("Could not find certificate.\n"); + } + + for (i = 0; i < objects_length; i++) { + /* Find attributes one after another to handle errors + * https://wiki.oasis-open.org/pkcs11/CommonBugs + */ + for (j = 0; j < template_size; j++) { + template[j].pValue = NULL; + template[j].ulValueLen = 0; + + rv = fp->C_GetAttributeValue(info->session_handle, object_handles[i], + &(template[j]), 1); + if (rv == CKR_ATTRIBUTE_TYPE_INVALID) + continue; + else if (rv != CKR_OK) + fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv); + + /* Allocate memory to hold the data we want */ + if (template[j].ulValueLen == 0) { + continue; + } else { + template[j].pValue = malloc(template[j].ulValueLen); + if (template[j].pValue == NULL) + fail_msg("malloc failed"); + } + /* Call again to get actual attribute */ + rv = fp->C_GetAttributeValue(info->session_handle, object_handles[i], + &(template[j]), 1); + if (rv != CKR_OK) + fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv); + } + + callback(objects, template, template_size, object_handles[i]); + // XXX check results + for (j = 0; j < template_size; j++) + free(template[j].pValue); + } + free(object_handles); + return 0; +} + +void search_for_all_objects(test_certs_t *objects, token_info_t *info) +{ + CK_OBJECT_CLASS keyClass = CKO_CERTIFICATE; + CK_OBJECT_CLASS privateClass = CKO_PRIVATE_KEY; + CK_OBJECT_CLASS publicClass = CKO_PUBLIC_KEY; + CK_ATTRIBUTE filter[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)}, + }; + CK_ULONG filter_size = 1; + CK_ATTRIBUTE attrs[] = { + { CKA_ID, NULL_PTR, 0}, + { CKA_VALUE, NULL_PTR, 0}, + { CKA_LABEL, NULL_PTR, 0}, + { CKA_CERTIFICATE_TYPE, NULL_PTR, 0}, + }; + CK_ULONG attrs_size = sizeof (attrs) / sizeof (CK_ATTRIBUTE); + CK_ATTRIBUTE private_attrs[] = { + { CKA_SIGN, NULL, 0}, // CK_BBOOL + { CKA_DECRYPT, NULL, 0}, // CK_BBOOL + { CKA_KEY_TYPE, NULL, 0}, // CKK_ + { CKA_ID, NULL, 0}, + { CKA_ALWAYS_AUTHENTICATE, NULL, 0}, // CK_BBOOL + { CKA_UNWRAP, NULL, 0}, // CK_BBOOL + { CKA_DERIVE, NULL, 0}, // CK_BBOOL + { CKA_LABEL, NULL_PTR, 0}, + }; + CK_ULONG private_attrs_size = sizeof (private_attrs) / sizeof (CK_ATTRIBUTE); + CK_ATTRIBUTE public_attrs[] = { + { CKA_VERIFY, NULL, 0}, // CK_BBOOL + { CKA_ENCRYPT, NULL, 0}, // CK_BBOOL + { CKA_KEY_TYPE, NULL, 0}, + { CKA_ID, NULL, 0}, + { CKA_MODULUS, NULL, 0}, + { CKA_PUBLIC_EXPONENT, NULL, 0}, + { CKA_EC_PARAMS, NULL, 0}, + { CKA_EC_POINT, NULL, 0}, + { CKA_WRAP, NULL, 0}, // CK_BBOOL + { CKA_DERIVE, NULL, 0}, // CK_BBOOL + }; + CK_ULONG public_attrs_size = sizeof (public_attrs) / sizeof (CK_ATTRIBUTE); + + debug_print("\nSearch for all certificates on the card"); + search_objects(objects, info, filter, filter_size, + attrs, attrs_size, callback_certificates); + + + /* do the same thing with private keys (collect handles based on the collected IDs) */ + debug_print("\nSearch for all private keys respective to the certificates"); + filter[0].pValue = &privateClass; + // search for all and pair on the fly + search_objects(objects, info, filter, filter_size, + private_attrs, private_attrs_size, callback_private_keys); + + debug_print("\nSearch for all public keys respective to the certificates"); + filter[0].pValue = &publicClass; + search_objects(objects, info, filter, filter_size, + public_attrs, public_attrs_size, callback_public_keys); +} + +void clean_all_objects(test_certs_t *objects) { + unsigned int i; + for (i = 0; i < objects->count; i++) { + free(objects->data[i].key_id); + free(objects->data[i].id_str); + free(objects->data[i].label); + X509_free(objects->data[i].x509); + if (objects->data[i].key_type == CKK_RSA && + objects->data[i].key.rsa != NULL) + RSA_free(objects->data[i].key.rsa); + else if (objects->data[i].key.ec != NULL) + EC_KEY_free(objects->data[i].key.ec); + } + free(objects->data); +} + +const char *get_mechanism_name(int mech_id) +{ + switch (mech_id) { + case CKM_RSA_PKCS: + return "RSA_PKCS"; + case CKM_SHA1_RSA_PKCS: + return "SHA1_RSA_PKCS"; + case CKM_SHA224_RSA_PKCS: + return "SHA224_RSA_PKCS"; + case CKM_SHA256_RSA_PKCS: + return "SHA256_RSA_PKCS"; + case CKM_SHA384_RSA_PKCS: + return "SHA384_RSA_PKCS"; + case CKM_SHA512_RSA_PKCS: + return "SHA512_RSA_PKCS"; + case CKM_RSA_X_509: + return "RSA_X_509"; + case CKM_ECDSA: + return "ECDSA"; + case CKM_ECDSA_SHA1: + return "ECDSA_SHA1"; + case CKM_ECDSA_SHA256: + return "ECDSA_SHA256"; + case CKM_ECDSA_SHA384: + return "ECDSA_SHA384"; + case CKM_ECDSA_SHA512: + return "ECDSA_SHA512"; + case CKM_ECDH1_DERIVE: + return "ECDH1_DERIVE"; + case CKM_ECDH1_COFACTOR_DERIVE: + return "ECDH1_COFACTOR_DERIVE"; + case CKM_EC_KEY_PAIR_GEN: + return "EC_KEY_PAIR_GEN"; + case CKM_RSA_PKCS_KEY_PAIR_GEN: + return "RSA_PKCS_KEY_PAIR_GEN"; + case CKM_MD5_RSA_PKCS: + return "MD5_RSA_PKCS"; + case CKM_RIPEMD160_RSA_PKCS: + return "RIPEMD160_RSA_PKCS"; + case CKM_RSA_PKCS_PSS: + return "RSA_PKCS_PSS"; + case CKM_SHA1_RSA_PKCS_PSS: + return "SHA1_RSA_PKCS_PSS"; + case CKM_SHA256_RSA_PKCS_PSS: + return "SHA256_RSA_PKCS_PSS"; + case CKM_SHA384_RSA_PKCS_PSS: + return "SHA384_RSA_PKCS_PSS"; + case CKM_SHA512_RSA_PKCS_PSS: + return "SHA512_RSA_PKCS_PSS"; + case CKM_SHA_1_HMAC: + return "SHA_1_HMAC"; + case CKM_SHA256_HMAC: + return "SHA256_HMAC"; + case CKM_SHA384_HMAC: + return "SHA384_HMAC"; + case CKM_SHA512_HMAC: + return "SHA512_HMAC"; + case CKM_RSA_PKCS_OAEP: + return "RSA_PKCS_OAEP"; + case CKM_SHA_1: + return "SHA_1"; + case CKM_SHA224: + return "SHA224"; + case CKM_SHA256: + return "SHA256"; + case CKM_SHA384: + return "SHA384"; + case CKM_SHA512: + return "SHA512"; + default: + sprintf(name_buffer, "0x%.8X", mech_id); + return name_buffer; + } +} + +const char *get_mgf_name(int mgf_id) +{ + switch (mgf_id) { + case CKG_MGF1_SHA1: + return "MGF1_SHA_1"; + case CKG_MGF1_SHA224: + return "MGF1_SHA224"; + case CKG_MGF1_SHA256: + return "MGF1_SHA256"; + case CKG_MGF1_SHA384: + return "MGF1_SHA384"; + case CKG_MGF1_SHA512: + return "MGF1_SHA512"; + default: + sprintf(name_buffer, "0x%.8X", mgf_id); + return name_buffer; + } +} + +const char *get_mechanism_flag_name(int mech_id) +{ + switch (mech_id) { + case CKF_HW: + return "CKF_HW"; + case CKF_ENCRYPT: + return "CKF_ENCRYPT"; + case CKF_DECRYPT: + return "CKF_DECRYPT"; + case CKF_DIGEST: + return "CKF_DIGEST"; + case CKF_SIGN: + return "CKF_SIGN"; + case CKF_SIGN_RECOVER: + return "CKF_SIGN_RECOVER"; + case CKF_VERIFY: + return "CKF_VERIFY"; + case CKF_VERIFY_RECOVER: + return "CKF_VERIFY_RECOVER"; + case CKF_GENERATE: + return "CKF_GENERATE"; + case CKF_GENERATE_KEY_PAIR: + return "CKF_GENERATE_KEY_PAIR"; + case CKF_WRAP: + return "CKF_WRAP"; + case CKF_UNWRAP: + return "CKF_UNWRAP"; + case CKF_DERIVE: + return "CKF_DERIVE"; + case CKF_EC_F_P: + return "CKF_EC_F_P"; + case CKF_EC_F_2M: + return "CKF_EC_F_2M"; + case CKF_EC_NAMEDCURVE: + return "CKF_EC_NAMEDCURVE"; + case CKF_EC_UNCOMPRESS: + return "CKF_EC_UNCOMPRESS"; + case CKF_EC_COMPRESS: + return "CKF_EC_COMPRESS"; + case CKF_EC_ECPARAMETERS: + return "CKF_EC_ECPARAMETERS"; + default: + sprintf(flag_buffer, "0x%.8X", mech_id); + return flag_buffer; + } +} + +char *convert_byte_string(unsigned char *id, unsigned long length) +{ + unsigned int i; + char *data = malloc(3 * length * sizeof(char) + 1); + for (i = 0; i < length; i++) + sprintf(&data[i*3], "%02X:", id[i]); + data[length*3-1] = '\0'; + return data; +} + +void write_data_row(token_info_t *info, int cols, ...) +{ + va_list ap; + int i, intval, type; + char *data; + + cols = cols*2; /* shut GCC up */ + va_start(ap, cols); + fprintf(info->log.fd, "\n\t["); + for (i = 1; i <= cols; i+=2) { + if (i > 1) + fprintf(info->log.fd, ","); + type = va_arg(ap, int); + if (type == 'd') { + intval = va_arg(ap, int); + fprintf(info->log.fd, "\n\t\t\"%d\"", intval); + } else if (type == 's') { + data = va_arg(ap, char*); + fprintf(info->log.fd, "\n\t\t\"%s\"", data); + } + } + fprintf(info->log.fd, "\n\t]"); + va_end(ap); +} + +int is_pss_mechanism(CK_MECHANISM_TYPE mech) +{ + return (mech == CKM_RSA_PKCS_PSS + || mech == CKM_SHA1_RSA_PKCS_PSS + || mech == CKM_SHA256_RSA_PKCS_PSS + || mech == CKM_SHA384_RSA_PKCS_PSS + || mech == CKM_SHA512_RSA_PKCS_PSS + || mech == CKM_SHA224_RSA_PKCS_PSS); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_common.h opensc-0.19.0/src/tests/p11test/p11test_case_common.h --- opensc-0.17.0/src/tests/p11test/p11test_case_common.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_common.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * p11test_case_common.h: Functions shared between test cases. + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef P11TEST_CASE_COMMON_H +#define P11TEST_CASE_COMMON_H + +#include +#include +#include +#include "p11test_common.h" + +typedef struct { + unsigned char *key_id; + CK_ULONG key_id_size; + char *id_str; + X509 *x509; + int type; + union { + RSA *rsa; + EC_KEY *ec; + } key; + CK_OBJECT_HANDLE private_handle; + CK_OBJECT_HANDLE public_handle; + CK_BBOOL sign; + CK_BBOOL decrypt; + CK_BBOOL verify; + CK_BBOOL encrypt; + CK_BBOOL wrap; + CK_BBOOL unwrap; + CK_BBOOL derive_priv; + CK_BBOOL derive_pub; + CK_KEY_TYPE key_type; + CK_BBOOL always_auth; + char *label; + CK_ULONG bits; + int verify_public; + test_mech_t mechs[MAX_MECHS]; + int num_mechs; +} test_cert_t; + +typedef struct { + unsigned int count; + test_cert_t *data; +} test_certs_t; + +void always_authenticate(test_cert_t *o, token_info_t *info); + +int search_objects(test_certs_t *objects, token_info_t *info, + CK_ATTRIBUTE filter[], CK_LONG filter_size, CK_ATTRIBUTE template[], CK_LONG template_size, + int (*callback)(test_certs_t *, CK_ATTRIBUTE[], unsigned int, CK_OBJECT_HANDLE)); +void search_for_all_objects(test_certs_t *objects, token_info_t *info); +void clean_all_objects(test_certs_t *objects); + +const char *get_mechanism_name(int mech_id); +const char *get_mgf_name(int mech_id); +const char *get_mechanism_flag_name(int flag_id); +char *convert_byte_string(unsigned char *id, unsigned long length); + +int is_pss_mechanism(CK_MECHANISM_TYPE mech); + +// TODO sanitize inputs + +#define P11TEST_START(info) if (info->log.fd) { \ + if (info->log.in_test) \ + fprintf(info->log.fd, "\n\t\"result\": \"unknown\"\n}"); \ + fprintf(info->log.fd, "%s\n{\n\t\"test_id\": \"%s\"", \ + info->log.first ? "" : ",", __func__); \ + info->log.in_test = 1; \ + info->log.first = 0; \ + info->log.in_data = 0; \ + } else {} + +#define _P11TEST_FINALIZE(info, result) if (info->log.fd) {\ + if (info->log.in_data) {\ + fprintf(info->log.fd, "]"); \ + } \ + if (info->log.fd && info->log.in_test) { \ + fprintf(info->log.fd, ",\n\t\"result\": \"" result "\"\n}"); \ + info->log.in_test = 0; \ + } \ + } else {} + +#define P11TEST_SKIP(info) do { _P11TEST_FINALIZE(info, "skip") skip(); } while(0); + +#define P11TEST_PASS(info) do { _P11TEST_FINALIZE(info, "pass") } while(0); + +#define P11TEST_FAIL(info, msg, ...) do { \ + if (info->log.fd && info->log.in_test) { \ + fprintf(info->log.fd, ",\n\t\"fail_reason\": \"" msg "\"", ##__VA_ARGS__); \ + } \ + _P11TEST_FINALIZE(info, "fail") \ + fail_msg(msg, ##__VA_ARGS__); \ + } while (0); + +#define P11TEST_DATA_ROW(info, cols, ...) if (info->log.fd) { \ + if (info->log.in_test == 0) \ + fail_msg("Can't add data outside of the test");\ + if (info->log.in_data == 0) {\ + fprintf(info->log.fd, ",\n\t\"data\": [");\ + info->log.in_data = 1;\ + } else { \ + fprintf(info->log.fd, ",");\ + } \ + write_data_row(info, cols, ##__VA_ARGS__); \ + } else {} + +void write_data_row(token_info_t *info, int cols, ...); + +#endif /* P11TEST_CASE_COMMON_H */ diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_ec_sign.c opensc-0.19.0/src/tests/p11test/p11test_case_ec_sign.c --- opensc-0.17.0/src/tests/p11test/p11test_case_ec_sign.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_ec_sign.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * p11test_case_ec_sign.c: Test different data lengths for EC signatures + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "p11test_case_ec_sign.h" + +void ec_sign_size_test(void **state) { + unsigned int i; + int min, max, j, l, errors = 0, rv; + token_info_t *info = (token_info_t *) *state; + + P11TEST_START(info); + if (token.num_ec_mechs == 0 ) { + fprintf(stderr, "Token does not support any ECC mechanisms. Skipping.\n"); + skip(); + } + + test_certs_t objects; + objects.count = 0; + objects.data = NULL; + + search_for_all_objects(&objects, info); + + debug_print("\nCheck functionality of Sign&Verify on different data lengths"); + for (i = 0; i < objects.count; i++) { + if (objects.data[i].key_type != CKK_EC) + continue; + // sanity: Test all mechanisms + min = (objects.data[i].bits + 7) / 8 - 2; + max = (objects.data[i].bits + 7) / 8 + 2; + if (objects.data[i].sign && objects.data[i].verify) { + for (j = 0; j < objects.data[i].num_mechs; j++) { + for (l = min; l < max; l++) { + rv = sign_verify_test(&(objects.data[i]), info, + &(objects.data[i].mechs[j]), l, 0); + if (rv == -1) + errors++; + } + } + } + } + clean_all_objects(&objects); + + if (errors > 0) + P11TEST_FAIL(info, "Some signatures were not verified successfully. Please review the log"); + P11TEST_PASS(info); +} + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_ec_sign.h opensc-0.19.0/src/tests/p11test/p11test_case_ec_sign.h --- opensc-0.17.0/src/tests/p11test/p11test_case_ec_sign.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_ec_sign.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * p11test_case_ec_sign.h: Test different data lengths for EC signatures + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" +#include "p11test_case_readonly.h" + +void ec_sign_size_test(void **state); diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_mechs.c opensc-0.19.0/src/tests/p11test/p11test_case_mechs.c --- opensc-0.17.0/src/tests/p11test/p11test_case_mechs.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_mechs.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,138 @@ +/* + * p11test_case_mechs.c: Check mechanisms supported by token + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_mechs.h" + +void supported_mechanisms_test(void **state) { + token_info_t *info = (token_info_t *) *state; + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + + CK_RV rv; + CK_ULONG mechanism_count, i; + CK_MECHANISM_TYPE_PTR mechanism_list; + CK_MECHANISM_INFO_PTR mechanism_info; + CK_FLAGS j; + test_mech_t *mech = NULL; + + P11TEST_START(info); + rv = function_pointer->C_GetMechanismList(info->slot_id, NULL_PTR, + &mechanism_count); + if ((rv == CKR_OK) && (mechanism_count > 0)) { + mechanism_list = (CK_MECHANISM_TYPE_PTR) + malloc(mechanism_count * sizeof(CK_MECHANISM_TYPE)); + rv = function_pointer->C_GetMechanismList(info->slot_id, + mechanism_list, &mechanism_count); + if (rv != CKR_OK) { + free(mechanism_list); + function_pointer->C_Finalize(NULL_PTR); + P11TEST_FAIL(info, "Could not get mechanism list!"); + } + + mechanism_info = (CK_MECHANISM_INFO_PTR) + malloc(mechanism_count * sizeof(CK_MECHANISM_INFO)); + if (mechanism_info == NULL) + P11TEST_FAIL(info, "Couldn't malloc()"); + + for (i = 0; i < mechanism_count; i++) { + CK_MECHANISM_TYPE mechanism_type = mechanism_list[i]; + rv = function_pointer->C_GetMechanismInfo(info->slot_id, + mechanism_type, &mechanism_info[i]); + if (rv != CKR_OK) + continue; + + /* store mechanisms list for later tests */ + + /* List all known RSA mechanisms */ + if (mechanism_list[i] == CKM_RSA_X_509 + || mechanism_list[i] == CKM_RSA_PKCS + || mechanism_list[i] == CKM_MD5_RSA_PKCS + || mechanism_list[i] == CKM_RIPEMD160_RSA_PKCS + || mechanism_list[i] == CKM_SHA1_RSA_PKCS + || mechanism_list[i] == CKM_SHA224_RSA_PKCS + || mechanism_list[i] == CKM_SHA256_RSA_PKCS + || mechanism_list[i] == CKM_SHA384_RSA_PKCS + || mechanism_list[i] == CKM_SHA512_RSA_PKCS + || mechanism_list[i] == CKM_RSA_PKCS_PSS + || mechanism_list[i] == CKM_SHA1_RSA_PKCS_PSS + || mechanism_list[i] == CKM_SHA256_RSA_PKCS_PSS + || mechanism_list[i] == CKM_SHA384_RSA_PKCS_PSS + || mechanism_list[i] == CKM_SHA512_RSA_PKCS_PSS + || mechanism_list[i] == CKM_RSA_PKCS_OAEP) { + if (token.num_rsa_mechs < MAX_MECHS) { + mech = &token.rsa_mechs[token.num_rsa_mechs++]; + mech->mech = mechanism_list[i]; + mech->usage_flags = mechanism_info[i].flags; + } else + P11TEST_FAIL(info, "Too many RSA mechanisms (%d)", MAX_MECHS); + } + + /* We list all known EC mechanisms */ + if (mechanism_list[i] == CKM_ECDSA + || mechanism_list[i] == CKM_ECDSA_SHA1 + || mechanism_list[i] == CKM_ECDSA_SHA256 + || mechanism_list[i] == CKM_ECDSA_SHA384 + || mechanism_list[i] == CKM_ECDSA_SHA512) { + if (token.num_ec_mechs < MAX_MECHS) { + mech = &token.ec_mechs[token.num_ec_mechs++]; + mech->mech = mechanism_list[i]; + mech->usage_flags = mechanism_info[i].flags; + } else + P11TEST_FAIL(info, "Too many EC mechanisms (%d)", MAX_MECHS); + } + if ((mechanism_info[i].flags & CKF_GENERATE_KEY_PAIR) != 0) { + if (token.num_keygen_mechs < MAX_MECHS) { + mech = &token.keygen_mechs[token.num_keygen_mechs++]; + mech->mech = mechanism_list[i]; + mech->usage_flags = mechanism_info[i].flags; + } else + P11TEST_FAIL(info, "Too many KEYGEN mechanisms (%d)", MAX_MECHS); + } + } + + printf("[ MECHANISM ] [ KEY SIZE ] [ FLAGS ]\n"); + printf("[ CKM_* ] [ MIN][ MAX] [ ]\n"); + P11TEST_DATA_ROW(info, 4, + 's', "MECHANISM", + 's', "MIN KEY", + 's', "MAX KEY", + 's', "FLAGS"); + for (i = 0; i < mechanism_count; i++) { + printf("[%-21s] [%4lu][%4lu] [%10s]", + get_mechanism_name(mechanism_list[i]), + mechanism_info[i].ulMinKeySize, + mechanism_info[i].ulMaxKeySize, + get_mechanism_flag_name(mechanism_info[i].flags)); + P11TEST_DATA_ROW(info, 4, + 's', get_mechanism_name(mechanism_list[i]), + 'd', mechanism_info[i].ulMinKeySize, + 'd', mechanism_info[i].ulMaxKeySize, + 's', get_mechanism_flag_name(mechanism_info[i].flags)); + for (j = 1; j <= CKF_EC_COMPRESS; j = j<<1) + if ((mechanism_info[i].flags & j) != 0) + printf(" %s", get_mechanism_flag_name(j)); + printf("\n"); + } + free(mechanism_list); + free(mechanism_info); + } + P11TEST_PASS(info); +} + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_mechs.h opensc-0.19.0/src/tests/p11test/p11test_case_mechs.h --- opensc-0.17.0/src/tests/p11test/p11test_case_mechs.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_mechs.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * p11test_case_mechs.h: Check mechanisms supported by token + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" + +void supported_mechanisms_test(void **state); diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_multipart.c opensc-0.19.0/src/tests/p11test/p11test_case_multipart.c --- opensc-0.17.0/src/tests/p11test/p11test_case_multipart.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_multipart.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * p11test_case_multipart.c: Multipart Sign & Verify tests (RSA only) + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_multipart.h" + +void multipart_tests(void **state) { + + token_info_t *info = (token_info_t *) *state; + unsigned int i; + int used, j; + test_certs_t objects; + + objects.count = 0; + objects.data = NULL; + + P11TEST_START(info); + search_for_all_objects(&objects, info); + + debug_print("\nCheck functionality of Multipart Sign&Verify and/or Encrypt&Decrypt"); + for (i = 0; i < objects.count; i++) { + if (objects.data[i].type == EVP_PK_EC) { + debug_print(" [ SKIP %s ] EC keys do not support multi-part operations", + objects.data[i].id_str); + continue; + } + used = 0; + /* do the Sign&Verify and/or Encrypt&Decrypt */ + /* XXX some keys do not have appropriate flags, but we can use them + * or vice versa */ + //if (objects.data[i].sign && objects.data[i].verify) + for (j = 0; j < objects.data[i].num_mechs; j++) + used |= sign_verify_test(&(objects.data[i]), info, + &(objects.data[i].mechs[j]), 32, 1); + + if (!used) { + debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX", + objects.data[i].id_str, objects.data[i].key_type); + } + } + + if (objects.count == 0) { + printf(" [WARN] No objects to display\n"); + return; + } + + /* print summary */ + printf("[KEY ID] [TYPE] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [LABEL]\n"); + P11TEST_DATA_ROW(info, 3, + 's', "KEY ID", + 's', "MECHANISM", + 's', "MULTIPART SIGN&VERIFY WORKS"); + for (i = 0; i < objects.count; i++) { + if (objects.data[i].type == EVP_PK_EC) + continue; + printf("[%-6s] [%s] [%6lu] [ %s ] [%s%s] [%s]\n", + objects.data[i].id_str, + objects.data[i].key_type == CKK_RSA ? "RSA " : + objects.data[i].key_type == CKK_EC ? " EC " : " ?? ", + objects.data[i].bits, + objects.data[i].verify_public == 1 ? " ./ " : " ", + objects.data[i].sign ? "[./] " : "[ ] ", + objects.data[i].verify ? " [./] " : " [ ] ", + objects.data[i].label); + for (j = 0; j < objects.data[i].num_mechs; j++) { + test_mech_t *mech = &objects.data[i].mechs[j]; + if ((mech->usage_flags & CKF_SIGN) == 0) { + /* not applicable mechanisms are skipped */ + continue; + } + printf(" [ %-20s ] [ %s ]\n", + get_mechanism_name(mech->mech), + mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : " "); + if ((mech->result_flags & FLAGS_SIGN_ANY) == 0) + continue; /* do not export unknown and non-working algorithms */ + P11TEST_DATA_ROW(info, 3, + 's', objects.data[i].id_str, + 's', get_mechanism_name(mech->mech), + 's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : ""); + } + printf("\n"); + } + printf(" Public == Cert ------------^ ^ ^ ^\n"); + printf(" Sign Attribute --------------------' | |\n"); + printf(" Sign&Verify functionality ------------' |\n"); + printf(" Verify Attribute ------------------------'\n"); + + clean_all_objects(&objects); + P11TEST_PASS(info); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_multipart.h opensc-0.19.0/src/tests/p11test/p11test_case_multipart.h --- opensc-0.17.0/src/tests/p11test/p11test_case_multipart.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_multipart.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * p11test_case_multipart.h: Multipart Sign & Verify tests (RSA only) + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" +#include "p11test_case_readonly.h" + +void multipart_tests(void **state); + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_pss_oaep.c opensc-0.19.0/src/tests/p11test/p11test_case_pss_oaep.c --- opensc-0.17.0/src/tests/p11test/p11test_case_pss_oaep.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_pss_oaep.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,874 @@ +/* + * p11test_case_pss_oaep.c: RSA-PSS and RSA-OAEP tests + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_pss_oaep.h" +#include "libopensc/internal.h" + +#include +#include + +#define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n" +#define BUFFER_SIZE 4096 + +const unsigned char *global_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN; +size_t global_message_length = sizeof(SHORT_MESSAGE_TO_SIGN); + +const CK_MECHANISM_TYPE * +get_oaep_mechanism_hashes(CK_MECHANISM_TYPE mech) +{ + static CK_MECHANISM_TYPE h[6]; + + switch (mech) { + case CKM_RSA_PKCS_OAEP: + h[0] = CKM_SHA_1; + h[1] = CKM_SHA224; + h[2] = CKM_SHA256; + h[3] = CKM_SHA384; + h[4] = CKM_SHA512; + h[5] = -1; + break; + + default: + h[0] = -1; + break; + } + + return h; +} +const CK_MECHANISM_TYPE * +get_pss_mechanism_hashes(CK_MECHANISM_TYPE mech) +{ + static CK_MECHANISM_TYPE h[6]; + + switch (mech) { + case CKM_RSA_PKCS_PSS: + h[0] = CKM_SHA_1; + h[1] = CKM_SHA224; + h[2] = CKM_SHA256; + h[3] = CKM_SHA384; + h[4] = CKM_SHA512; + h[5] = -1; + break; + + case CKM_SHA1_RSA_PKCS_PSS: + h[0] = CKM_SHA_1; + h[1] = -1; + break; + + case CKM_SHA224_RSA_PKCS_PSS: + h[0] = CKM_SHA224; + h[1] = -1; + break; + + case CKM_SHA256_RSA_PKCS_PSS: + h[0] = CKM_SHA256; + h[1] = -1; + break; + + case CKM_SHA384_RSA_PKCS_PSS: + h[0] = CKM_SHA384; + h[1] = -1; + break; + + case CKM_SHA512_RSA_PKCS_PSS: + h[0] = CKM_SHA512; + h[1] = -1; + break; + + default: + h[0] = -1; + break; + } + + return h; +} + +const CK_MECHANISM_TYPE * +get_mechanism_hashes(CK_MECHANISM_TYPE mech) +{ + if (mech == CKM_RSA_PKCS_OAEP) + return get_oaep_mechanism_hashes(mech); + else + return get_pss_mechanism_hashes(mech); +} + +const CK_RSA_PKCS_MGF_TYPE * +get_mgfs(void) +{ + static CK_RSA_PKCS_MGF_TYPE h[6]; + h[0] = CKG_MGF1_SHA1; + h[1] = CKG_MGF1_SHA224; + h[2] = CKG_MGF1_SHA256; + h[3] = CKG_MGF1_SHA384; + h[4] = CKG_MGF1_SHA512; + h[5] = -1; + return h; +} + +const EVP_MD *mgf_cryptoki_to_ossl(CK_RSA_PKCS_MGF_TYPE mgf) +{ + switch (mgf) { + case CKG_MGF1_SHA224: + return EVP_sha224(); + + case CKG_MGF1_SHA256: + return EVP_sha256(); + + case CKG_MGF1_SHA384: + return EVP_sha384(); + + case CKG_MGF1_SHA512: + return EVP_sha512(); + + case CKG_MGF1_SHA1: + default: + return EVP_sha1(); + + } +} + +const EVP_MD *md_cryptoki_to_ossl(CK_MECHANISM_TYPE hash) +{ + /* Digest mechanisms */ + switch (hash) { + case CKM_SHA224: + return EVP_sha224(); + + case CKM_SHA256: + return EVP_sha256(); + + case CKM_SHA384: + return EVP_sha384(); + + case CKM_SHA512: + return EVP_sha512(); + + case CKM_SHA_1: + default: + return EVP_sha1(); + + } +} + +size_t get_hash_length(CK_MECHANISM_TYPE mech) +{ + switch (mech) { + case CKM_SHA224: + return SHA224_DIGEST_LENGTH; + case CKM_SHA256: + return SHA256_DIGEST_LENGTH; + case CKM_SHA384: + return SHA384_DIGEST_LENGTH; + case CKM_SHA512: + return SHA512_DIGEST_LENGTH; + default: + case CKM_SHA_1: + return SHA_DIGEST_LENGTH; + } +} + +CK_BYTE *hash_message(const CK_BYTE *message, size_t message_length, + CK_MECHANISM_TYPE hash) +{ + switch (hash) { + case CKM_SHA224: + return SHA224(message, message_length, NULL); + + case CKM_SHA256: + return SHA256(message, message_length, NULL); + + case CKM_SHA384: + return SHA384(message, message_length, NULL); + + case CKM_SHA512: + return SHA512(message, message_length, NULL); + + case CKM_SHA_1: + default: + return SHA1(message, message_length, NULL); + + } +} + +int oaep_encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) +{ + size_t enc_length = 0; + CK_RV rv = -1; + EVP_PKEY_CTX *pctx = NULL; + const EVP_MD *md = EVP_md_null(); + const EVP_MD *mgf1_md = EVP_md_null(); + EVP_PKEY *key = NULL; + + md = md_cryptoki_to_ossl(mech->hash); + mgf1_md = mgf_cryptoki_to_ossl(mech->mgf); + + if ((key = EVP_PKEY_new()) == NULL + || RSA_up_ref(o->key.rsa) < 1 + || EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) { + fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } + + if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL + || EVP_PKEY_encrypt_init(pctx) != 1 + || EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING) != 1 + || EVP_PKEY_CTX_set_rsa_oaep_md(pctx, md) != 1 + || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) != 1) { + fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } + + if (EVP_PKEY_encrypt(pctx, NULL, &enc_length, message, message_length) <= 0) { + fprintf(stderr, " [ ERROR %s ] Failed get signature length. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } + + *enc_message = OPENSSL_malloc(enc_length); + + rv = EVP_PKEY_encrypt(pctx, *enc_message, &enc_length, message, message_length); + if (rv <= 0) { + fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + } +out: + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(key); + return enc_length; +} + +void fill_oaep_params(CK_RSA_PKCS_OAEP_PARAMS *oaep_params, + test_mech_t *mech) +{ + oaep_params->hashAlg = mech->hash; + oaep_params->mgf = mech->mgf; + oaep_params->source = CKZ_DATA_SPECIFIED; + oaep_params->pSourceData = NULL; + oaep_params->ulSourceDataLen = 0; + +} + +int oaep_encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; + CK_ULONG enc_message_length; + static int encrypt_support = 1; + + fill_oaep_params(&oaep_params, mech); + enc_mechanism.pParameter = &oaep_params; + enc_mechanism.ulParameterLen = sizeof(oaep_params); + + if (!encrypt_support) + goto openssl_encrypt; + + rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism, + o->public_handle); + if (rv != CKR_OK) { + debug_print(" C_EncryptInit: rv = 0x%.8lX", rv); + encrypt_support = 0; /* avoid trying over and over again */ + goto openssl_encrypt; + } + + /* get the expected length */ + rv = fp->C_Encrypt(info->session_handle, message, message_length, + NULL, &enc_message_length); + if (rv != CKR_OK) { + debug_print(" C_Encrypt: rv = 0x%.8lX", rv); + goto openssl_encrypt; + } + *enc_message = malloc(enc_message_length); + if (*enc_message == NULL) { + debug_print("malloc returned null"); + return -1; + } + + /* Do the actual encryption with allocated buffer */ + rv = fp->C_Encrypt(info->session_handle, message, message_length, + *enc_message, &enc_message_length); + if (rv == CKR_OK) { + mech->result_flags |= FLAGS_DECRYPT_OPENSSL; + return enc_message_length; + } + debug_print(" C_Encrypt: rv = 0x%.8lX", rv); + +openssl_encrypt: + debug_print(" [ KEY %s ] Falling back to openssl encryption", o->id_str); + return oaep_encrypt_message_openssl(o, info, message, message_length, mech, + enc_message); +} + +int oaep_decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message, + CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; + CK_ULONG dec_message_length = BUFFER_SIZE; + + fill_oaep_params(&oaep_params, mech); + dec_mechanism.pParameter = &oaep_params; + dec_mechanism.ulParameterLen = sizeof(oaep_params); + + rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism, + o->private_handle); + if (rv == CKR_KEY_TYPE_INCONSISTENT) { + debug_print(" [SKIP %s ] Not allowed to decrypt with this key?", o->id_str); + return 0; + } else if (rv != CKR_OK) { + debug_print(" C_DecryptInit: rv = 0x%.8lX\n", rv); + return -1; + } + + *dec_message = malloc(dec_message_length); + + always_authenticate(o, info); + + rv = fp->C_Decrypt(info->session_handle, enc_message, + enc_message_length, *dec_message, &dec_message_length); + if (rv != CKR_OK) { + free(*dec_message); + debug_print(" C_Decrypt: rv = 0x%.8lX\n", rv); + return -1; + } + return (int) dec_message_length; +} + +/* Perform encryption and decryption of a message using private key referenced + * in the o object with mechanism defined by mech. + * + * NONE of the reasonable mechanisms support encryption/decryption + * + * Returns + * * 1 for successful Encrypt&Decrypt sequence + * * 0 for skipped test (unsupported mechanism, key, ...) + * * -1 otherwise. + * Serious errors terminate the execution. + */ +int oaep_encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech) +{ + CK_BYTE *message = (CK_BYTE *) SHORT_MESSAGE_TO_SIGN; + CK_BYTE *dec_message = NULL; + int dec_message_length = 0; + int message_length = 16; + unsigned char *enc_message; + int enc_message_length, rv; + + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", o->id_str); + return 0; + } + + if (o->type != EVP_PK_RSA) { + debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str); + return 0; + } + + if (mech->mech != CKM_RSA_PKCS_OAEP) { + mech->usage_flags &= ~CKF_DECRYPT; + debug_print(" [SKIP %s ] non RSA-OAEP mechanism", o->id_str); + return 0; + } + + message_length = MIN((int)global_message_length, + (int)((o->bits+7)/8 - 2*get_hash_length(mech->hash) - 2)); + + /* will not work for 1024b RSA key and SHA512 hash: It has max size -2 */ + if (message_length < 0) { + mech->usage_flags &= ~CKF_DECRYPT; + debug_print(" [SKIP %s ] Too small modulus (%ld bits)" + " or too large hash %s (%lu B) for OAEP", o->id_str, + o->bits, get_mechanism_name(mech->hash), + get_hash_length(mech->hash)); + return 0; + } + + debug_print(" [ KEY %s ] Encrypt message of length %d using CKM_%s, " + "hash CKM_%s, mgf=CKG_%s", o->id_str, (unsigned) message_length, + get_mechanism_name(mech->mech), get_mechanism_name(mech->hash), + get_mgf_name(mech->mgf)); + enc_message_length = oaep_encrypt_message(o, info, message, + (unsigned) message_length, mech, &enc_message); + if (enc_message_length <= 0) { + return -1; + } + + debug_print(" [ KEY %s ] Decrypt message", o->id_str); + dec_message_length = oaep_decrypt_message(o, info, enc_message, + enc_message_length, mech, &dec_message); + free(enc_message); + if (dec_message_length <= 0) { + return -1; + } + + if (memcmp(dec_message, message, dec_message_length) == 0 + && dec_message_length == message_length) { + debug_print(" [ OK %s ] Text decrypted successfully.", o->id_str); + mech->result_flags |= FLAGS_DECRYPT; + rv = 1; + } else { + dec_message[dec_message_length] = '\0'; + debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s", + o->id_str, dec_message); + rv = 0; + } + free(dec_message); + return rv; +} + +static int get_max_salt_len(unsigned long bits, CK_MECHANISM_TYPE hash) +{ + return (bits + 7)/8 - get_hash_length(hash) - 2; +} + +int fill_pss_params(CK_RSA_PKCS_PSS_PARAMS *pss_params, + test_mech_t *mech, test_cert_t *o) +{ + pss_params->hashAlg = mech->hash; + pss_params->mgf = mech->mgf; + switch (mech->salt){ + case -2: + /* max possible ( modlen - hashlen -2 ) */ + pss_params->sLen = get_max_salt_len(o->bits,mech->hash); + break; + case -1: + /* digest length */ + /* will not work with SHA512 and 1024b keys (max is 62b!) */ + if ((int) get_hash_length(mech->hash) > get_max_salt_len(o->bits, mech->hash)) { + return -1; + } + pss_params->sLen = get_hash_length(mech->hash); + break; + case 0: + default: + pss_params->sLen = 0; + break; + } + return 1; +} + +int pss_sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **sign) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_ULONG sign_length = 0; + CK_RSA_PKCS_PSS_PARAMS pss_params; + + if (fill_pss_params(&pss_params, mech, o) != 1) { + debug_print(" [SKIP %s ] Impossible to use requested salt length", o->id_str); + return 0; + } + sign_mechanism.pParameter = &pss_params; + sign_mechanism.ulParameterLen = sizeof(pss_params); + + rv = fp->C_SignInit(info->session_handle, &sign_mechanism, + o->private_handle); + if (rv == CKR_KEY_TYPE_INCONSISTENT) { + debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str); + return 0; + } else if (rv == CKR_MECHANISM_INVALID) { + debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str); + return 0; + } else if (rv != CKR_OK) { + debug_print(" C_SignInit: rv = 0x%.8lX\n", rv); + return -1; + } + + always_authenticate(o, info); + + /* Call C_Sign with NULL argument to find out the real size of signature */ + rv = fp->C_Sign(info->session_handle, + message, message_length, *sign, &sign_length); + if (rv != CKR_OK) { + fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv); + return -1; + } + + *sign = malloc(sign_length); + if (*sign == NULL) { + fprintf(stderr, "%s: malloc failed", __func__); + return -1; + } + + /* Call C_Sign with allocated buffer to the actual signature */ + rv = fp->C_Sign(info->session_handle, + message, message_length, *sign, &sign_length); + + if (rv != CKR_OK) { + free(*sign); + fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv); + return -1; + } + return sign_length; +} + +int pss_verify_message_openssl(test_cert_t *o, token_info_t *info, + CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, + unsigned char *sign, CK_ULONG sign_length) +{ + CK_RV rv = -1; + EVP_PKEY_CTX *pctx = NULL; + const CK_BYTE *my_message; + CK_ULONG my_message_length; + const EVP_MD *mgf_md = EVP_md_null(); + const EVP_MD *md = EVP_md_null(); + EVP_PKEY *key = NULL; + + md = md_cryptoki_to_ossl(mech->hash); + mgf_md = mgf_cryptoki_to_ossl(mech->mgf); + + if (mech->mech != CKM_RSA_PKCS_PSS) { + my_message = hash_message(message, message_length, mech->hash); + my_message_length = get_hash_length(mech->hash); + } else { + my_message = message; + my_message_length = message_length; + } + + if ((key = EVP_PKEY_new()) == NULL + || RSA_up_ref(o->key.rsa) < 1 + || EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) { + fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } + + if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL + || EVP_PKEY_verify_init(pctx) != 1 + || EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1 + || EVP_PKEY_CTX_set_signature_md(pctx, md) != 1 + || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, mech->salt) != 1 + || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_md) != 1) { + fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } + + rv = EVP_PKEY_verify(pctx, sign, sign_length, my_message, my_message_length); + if (rv == 1) { + debug_print(" [ OK %s ] Signature is valid.", o->id_str); + mech->result_flags |= FLAGS_SIGN_OPENSSL; + } else { + fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + goto out; + } +out: + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(key); + return rv; +} + +int pss_verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char *sign, + CK_ULONG sign_length) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_RSA_PKCS_PSS_PARAMS pss_params; + static int verify_support = 1; + + if (!verify_support) + goto openssl_verify; + + fill_pss_params(&pss_params, mech, o); + sign_mechanism.pParameter = &pss_params; + sign_mechanism.ulParameterLen = sizeof(pss_params); + + /* try C_Verify() if it is supported */ + rv = fp->C_VerifyInit(info->session_handle, &sign_mechanism, + o->public_handle); + if (rv != CKR_OK) { + debug_print(" C_VerifyInit: rv = 0x%.8lX", rv); + verify_support = 0; /* avoid trying over and over again */ + goto openssl_verify; + } + + rv = fp->C_Verify(info->session_handle, + message, message_length, sign, sign_length); + + if (rv == CKR_OK) { + mech->result_flags |= FLAGS_SIGN; + debug_print(" [ OK %s ] Verification successful", o->id_str); + return 1; + } + debug_print(" C_Verify: rv = 0x%.8lX", rv); + verify_support = 0; /* avoid trying over and over again */ + +openssl_verify: + debug_print(" [ KEY %s ] Falling back to openssl verification", o->id_str); + return pss_verify_message_openssl(o, info, message, message_length, mech, + sign, sign_length); +} + +/* Perform signature and verification of a message using private key referenced + * in the o object with mechanism defined by mech. + * + * Returns + * * 1 for successful Sign&Verify sequence + * * 0 for skipped test (unsupported mechanism, key, ...) + * * -1 otherwise. + * Serious errors terminate the execution. + */ +int pss_sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech) +{ + CK_BYTE *message = NULL; + size_t message_length = global_message_length; + CK_BYTE *sign = NULL; + CK_ULONG sign_length = 0; + int rv = 0; + + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", o->id_str); + return 0; + } + + if (o->type != EVP_PK_RSA) { + debug_print(" [SKIP %s ] Skip non-RSA key", o->id_str); + return 0; + } + + if (!is_pss_mechanism(mech->mech)) { + mech->usage_flags &= ~CKF_SIGN; + debug_print(" [SKIP %s ] non RSA-PSS mechanism %s", o->id_str, + get_mechanism_name(mech->mech)); + return 0; + } + + if (mech->mech == CKM_RSA_PKCS_PSS) { + message = hash_message(global_message, global_message_length, + mech->hash); + message_length = get_hash_length(mech->hash); + } else { + message = (unsigned char *) SHORT_MESSAGE_TO_SIGN; + } + + debug_print(" [ KEY %s ] Signing message using CKM_%s, CKM_%s," + " CKG_%s, salt_len=%d", o->id_str, + get_mechanism_name(mech->mech), get_mechanism_name(mech->hash), + get_mgf_name(mech->mgf), mech->salt); + rv = pss_sign_message(o, info, message, message_length, mech, &sign); + if (rv <= 0) { + return rv; + } + sign_length = (unsigned long) rv; + + debug_print(" [ KEY %s ] Verify message signature", o->id_str); + rv = pss_verify_message(o, info, message, message_length, mech, + sign, sign_length); + free(sign); + return rv; +} + +/* ignore the prefilled mechanisms and list all combinations of mechanisms + * found, all resonable hash functions, MGFs and salt lengths + */ +void fill_object_pss_mechanisms(token_info_t *info, test_cert_t *o) +{ + const CK_MECHANISM_TYPE *h; + const CK_RSA_PKCS_MGF_TYPE *mgf; + int n = 0, s; + unsigned int j; + + for (j = 0; j < token.num_rsa_mechs; j++) { + test_mech_t *source_mech = &token.rsa_mechs[j]; + + /* skip non-RSA-PSS mechs early */ + if (!is_pss_mechanism(source_mech->mech) && + source_mech->mech != CKM_RSA_PKCS_OAEP) { + continue; + } + + h = get_mechanism_hashes(source_mech->mech); + for (; *h != (CK_MECHANISM_TYPE) -1; h++) { + mgf = get_mgfs(); + for (; *mgf != (CK_RSA_PKCS_MGF_TYPE) -1; mgf++) { + /* OAEP does not have salt */ + if (source_mech->mech == CKM_RSA_PKCS_OAEP) + s = 0; + else + s = -2; + + for (; s <= 0; s++) { + test_mech_t *mech = &o->mechs[n++]; + mech->mech = source_mech->mech; + mech->hash = *h; + mech->mgf = *mgf; + mech->salt = s; + mech->usage_flags = + source_mech->usage_flags; + mech->result_flags = 0; + if (n >= MAX_MECHS) + P11TEST_FAIL(info, + "Too many mechanisms (%d)", + MAX_MECHS); + } + } + } + + } + o->num_mechs = n; +} + +int have_pss_oaep_mechanisms() +{ + unsigned have = 0, i; + for (i = 0; i <= token.num_rsa_mechs; i++) { + if (is_pss_mechanism(token.rsa_mechs[i].mech) || + token.rsa_mechs[i].mech == CKM_RSA_PKCS_OAEP) { + have++; + } + } + return have; +} + +void pss_oaep_test(void **state) { + + token_info_t *info = (token_info_t *) *state; + unsigned int i; + int used, j; + test_certs_t objects; + + P11TEST_START(info); + + if (have_pss_oaep_mechanisms() == 0) { + fprintf(stderr, "Token does not support any RSA-PSS or OAEP mechanisms. Skipping.\n"); + skip(); + } + + objects.count = 0; + objects.data = NULL; + search_for_all_objects(&objects, info); + + debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt"); + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + /* do the Sign&Verify and/or Encrypt&Decrypt */ + used = 0; + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", + o->id_str); + continue; + } + fill_object_pss_mechanisms(info, o); + for (j = 0; j < o->num_mechs; j++) + if (o->mechs[j].mech != CKM_RSA_PKCS_OAEP) + used |= pss_sign_verify_test(o, info, + &(o->mechs[j])); + + for (j = 0; j < o->num_mechs; j++) + if (o->mechs[j].mech == CKM_RSA_PKCS_OAEP) + used |= oaep_encrypt_decrypt_test(o, info, + &(o->mechs[j])); + + if (!used) { + debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX", + o->id_str, o->key_type); + } + } + + if (objects.count == 0) { + printf(" [WARN] No objects to display\n"); + return; + } + + /* print summary */ + printf("[KEY ID] [LABEL]\n"); + printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT]\n"); + printf("[ MECHANISM ] [ HASH ] [ MGF ] [SALT] [ WORKS ] [ WORKS ]\n"); + P11TEST_DATA_ROW(info, 7, + 's', "KEY ID", + 's', "MECHANISM", + 's', "HASH", + 's', "MGF", + 's', "SALT", + 's', "SIGN&VERIFY WORKS", + 's', "ENCRYPT&DECRYPT WORKS"); + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + + /* Do not list non-RSA keys here */ + if (o->type != EVP_PK_RSA) + continue; + + printf("\n[%-6s] [%s]\n", + o->id_str, + o->label); + printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s]\n", + o->key_type == CKK_RSA ? "RSA " : + o->key_type == CKK_EC ? " EC " : " ?? ", + o->bits, + o->verify_public == 1 ? " ./ " : " ", + o->sign ? "[./] " : "[ ] ", + o->verify ? " [./] " : " [ ] ", + o->encrypt ? "[./] " : "[ ] ", + o->decrypt ? " [./] " : " [ ] "); + if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) { + printf(" no usable attributes found ... ignored\n"); + continue; + } + for (j = 0; j < o->num_mechs; j++) { + test_mech_t *mech = &o->mechs[j]; + printf(" [ %-20s ] [%-6s] [%-11s] [%4d] [ %s ] [ %s ]\n", + get_mechanism_name(mech->mech), + get_mechanism_name(mech->hash), + get_mgf_name(mech->mgf), + mech->salt, + mech->result_flags & FLAGS_SIGN_ANY + ? "[./]" : " ", + mech->result_flags & FLAGS_DECRYPT_ANY + ? "[./]" : " "); + if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 && + (mech->result_flags & FLAGS_DECRYPT_ANY) == 0) + continue; /* skip empty rows for export */ + P11TEST_DATA_ROW(info, 7, + 's', o->id_str, + 's', get_mechanism_name(mech->mech), + 's', get_mechanism_name(mech->hash), + 's', get_mgf_name(mech->mgf), + 'd', mech->salt, + 's', mech->result_flags & FLAGS_SIGN_ANY + ? "YES" : "", + 's', mech->result_flags & FLAGS_DECRYPT_ANY + ? "YES" : ""); + } + } + printf(" Public == Cert ----------^ ^ ^ ^ ^ ^ ^\n"); + printf(" Sign Attribute -------------------------------------------' | | | | |\n"); + printf(" Sign&Verify functionality -----------------------------------' | | | |\n"); + printf(" Verify Attribute -----------------------------------------------' | | |\n"); + printf(" Encrypt Attribute ------------------------------------------------------' | |\n"); + printf(" Encrypt & Decrypt functionality -------------------------------------------' |\n"); + printf(" Decrypt Attribute ------------------------------------------------------------'\n"); + + clean_all_objects(&objects); + P11TEST_PASS(info); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_pss_oaep.h opensc-0.19.0/src/tests/p11test/p11test_case_pss_oaep.h --- opensc-0.17.0/src/tests/p11test/p11test_case_pss_oaep.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_pss_oaep.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * p11test_case_pss_oaep.h: RSA-PSS and RSA-OAEP tests + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" + +void pss_oaep_test(void **state); diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_readonly.c opensc-0.19.0/src/tests/p11test/p11test_case_readonly.c --- opensc-0.17.0/src/tests/p11test/p11test_case_readonly.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_readonly.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,699 @@ +/* + * p11test_case_readonly.c: Sign & Verify tests + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_readonly.h" + +#include +#include +#include + +#define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n" +#define SHORT_MESSAGE_DIGEST "\x30\x21\x30\x09\x06\x05\x2b\x0e" \ + "\x03\x02\x1a\x05\x00\x04\x14\xd9" \ + "\xdd\xa3\x76\x44\x2f\x50\xe1\xec" \ + "\xd3\x8b\xcd\x6f\xc6\xce\x4e\xfd" \ + "\xd3\x1a\x3f" +#define BUFFER_SIZE 4096 + +const unsigned char *const_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN; + +static unsigned char * +rsa_x_509_pad_message(const unsigned char *message, + unsigned long *message_length, test_cert_t *o, int encrypt) +{ + int pad_message_length = (o->bits+7)/8; + unsigned char *pad_message = malloc(pad_message_length); + if (!encrypt) + RSA_padding_add_PKCS1_type_1(pad_message, pad_message_length, + message, *message_length); + else + RSA_padding_add_PKCS1_type_2(pad_message, pad_message_length, + message, *message_length); + *message_length = pad_message_length; + return pad_message; +} + +int encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) +{ + int rv, padding; + + *enc_message = malloc(RSA_size(o->key.rsa)); + if (*enc_message == NULL) { + debug_print("malloc returned null"); + return -1; + } + + /* Prepare padding for RSA_X_509 */ + padding = ((mech->mech == CKM_RSA_X_509) ? RSA_NO_PADDING : RSA_PKCS1_PADDING); + rv = RSA_public_encrypt(message_length, message, + *enc_message, o->key.rsa, padding); + if (rv < 0) { + free(*enc_message); + debug_print("RSA_public_encrypt: rv = 0x%.8X\n", rv); + return -1; + } + return rv; +} + +int encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_ULONG enc_message_length; + static int encrypt_support = 1; + + if (!encrypt_support) + goto openssl_encrypt; + + rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism, + o->public_handle); + if (rv != CKR_OK) { + debug_print(" C_EncryptInit: rv = 0x%.8lX", rv); + encrypt_support = 0; /* avoid trying over and over again */ + goto openssl_encrypt; + } + + /* get the expected length */ + rv = fp->C_Encrypt(info->session_handle, message, message_length, + NULL, &enc_message_length); + if (rv != CKR_OK) { + debug_print(" C_Encrypt: rv = 0x%.8lX", rv); + goto openssl_encrypt; + } + *enc_message = malloc(enc_message_length); + if (*enc_message == NULL) { + debug_print("malloc returned null"); + return -1; + } + + /* Do the actual encryption with allocated buffer */ + rv = fp->C_Encrypt(info->session_handle, message, message_length, + *enc_message, &enc_message_length); + if (rv == CKR_OK) { + mech->result_flags |= FLAGS_SIGN; + return enc_message_length; + } + debug_print(" C_Encrypt: rv = 0x%.8lX", rv); + +openssl_encrypt: + debug_print(" [ KEY %s ] Falling back to openssl encryption", o->id_str); + return encrypt_message_openssl(o, info, message, message_length, mech, + enc_message); +} + +int decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message, + CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_ULONG dec_message_length = BUFFER_SIZE; + + rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism, + o->private_handle); + if (rv == CKR_KEY_TYPE_INCONSISTENT) { + debug_print(" [SKIP %s ] Not allowed to decrypt with this key?", o->id_str); + return 0; + } else if (rv != CKR_OK) { + debug_print("C_DecryptInit: rv = 0x%.8lX\n", rv); + return -1; + } + + *dec_message = malloc(dec_message_length); + + always_authenticate(o, info); + + rv = fp->C_Decrypt(info->session_handle, enc_message, + enc_message_length, *dec_message, &dec_message_length); + if (rv != CKR_OK) { + free(*dec_message); + debug_print(" C_Decrypt: rv = 0x%.8lX\n", rv); + return -1; + } + return (int) dec_message_length; +} + +/* Perform encryption and decryption of a message using private key referenced + * in the o object with mechanism defined by mech. + * + * NONE of the reasonable mechanisms support multipart encryption/decryption + * + * Returns + * * 1 for successful Encrypt&Decrypt sequence + * * 0 for skipped test (unsupported mechanism, key, ...) + * * -1 otherwise. + * Serious errors terminate the execution. + */ +int encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech, + CK_ULONG message_length, int multipart) +{ + CK_BYTE *message = NULL; + CK_BYTE *dec_message = NULL; + int dec_message_length = 0; + unsigned char *enc_message; + int enc_message_length, rv; + + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", o->id_str); + return 0; + } + + if (o->type != EVP_PK_RSA) { + debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str); + return 0; + } + + if (mech->mech == CKM_RSA_PKCS_OAEP) { + mech->usage_flags &= ~CKF_DECRYPT; + debug_print(" [SKIP %s ] RSA-OAEP tested separately", o->id_str); + return 0; + } + + if (mech->mech != CKM_RSA_X_509 && mech->mech != CKM_RSA_PKCS) { + debug_print(" [ KEY %s ] Skip encryption for non-supported mechanism %s", + o->id_str, get_mechanism_name(mech->mech)); + return 0; + } + + if (mech->mech == CKM_RSA_X_509) + message = rsa_x_509_pad_message(const_message, + &message_length, o, 1); + else + message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN); + + debug_print(" [ KEY %s ] Encrypt message using CKM_%s", + o->id_str, get_mechanism_name(mech->mech)); + enc_message_length = encrypt_message(o, info, message, message_length, + mech, &enc_message); + if (enc_message_length <= 0) { + free(message); + return -1; + } + + debug_print(" [ KEY %s ] Decrypt message", o->id_str); + dec_message_length = decrypt_message(o, info, enc_message, + enc_message_length, mech, &dec_message); + free(enc_message); + if (dec_message_length <= 0) { + free(message); + return -1; + } + + if (memcmp(dec_message, message, dec_message_length) == 0 + && (unsigned int) dec_message_length == message_length) { + debug_print(" [ OK %s ] Text decrypted successfully.", o->id_str); + mech->result_flags |= FLAGS_DECRYPT; + rv = 1; + } else { + dec_message[dec_message_length] = '\0'; + debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s", + o->id_str, dec_message); + rv = 0; + } + free(dec_message); + free(message); + return rv; +} + +int sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char **sign, + int multipart) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; + CK_ULONG sign_length = 0; + char *name; + + rv = fp->C_SignInit(info->session_handle, &sign_mechanism, + o->private_handle); + if (rv == CKR_KEY_TYPE_INCONSISTENT) { + debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str); + return 0; + } else if (rv == CKR_MECHANISM_INVALID) { + debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str); + return 0; + } else if (rv != CKR_OK) { + debug_print(" C_SignInit: rv = 0x%.8lX\n", rv); + return -1; + } + + always_authenticate(o, info); + + if (multipart) { + int part = message_length / 3; + rv = fp->C_SignUpdate(info->session_handle, message, part); + if (rv == CKR_MECHANISM_INVALID) { + fprintf(stderr, " Multipart Signature not supported with CKM_%s\n", + get_mechanism_name(mech->mech)); + return -1; + } else if (rv != CKR_OK) { + fprintf(stderr, " C_SignUpdate: rv = 0x%.8lX\n", rv); + return -1; + } + rv = fp->C_SignUpdate(info->session_handle, message + part, message_length - part); + if (rv != CKR_OK) { + fprintf(stderr, " C_SignUpdate: rv = 0x%.8lX\n", rv); + return -1; + } + /* Call C_SignFinal with NULL argument to find out the real size of signature */ + rv = fp->C_SignFinal(info->session_handle, *sign, &sign_length); + if (rv != CKR_OK) { + fprintf(stderr, " C_SignFinal: rv = 0x%.8lX\n", rv); + return -1; + } + + *sign = malloc(sign_length); + if (*sign == NULL) { + fprintf(stderr, "%s: malloc failed", __func__); + return -1; + } + + /* Call C_SignFinal with allocated buffer to the actual signature */ + rv = fp->C_SignFinal(info->session_handle, *sign, &sign_length); + name = "C_SignFinal"; + } else { + /* Call C_Sign with NULL argument to find out the real size of signature */ + rv = fp->C_Sign(info->session_handle, + message, message_length, *sign, &sign_length); + if (rv != CKR_OK) { + fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv); + return -1; + } + + *sign = malloc(sign_length); + if (*sign == NULL) { + fprintf(stderr, "%s: malloc failed", __func__); + return -1; + } + + /* Call C_Sign with allocated buffer to the actual signature */ + rv = fp->C_Sign(info->session_handle, + message, message_length, *sign, &sign_length); + name = "C_Sign"; + } + if (rv != CKR_OK) { + free(*sign); + fprintf(stderr, " %s: rv = 0x%.8lX\n", name, rv); + return -1; + } + return sign_length; +} + +int verify_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char *sign, + CK_ULONG sign_length) +{ + CK_RV rv; + CK_BYTE *cmp_message = NULL; + int cmp_message_length; + + if (o->type == EVP_PK_RSA) { + int type; + + /* raw RSA mechanism */ + if (mech->mech == CKM_RSA_PKCS || mech->mech == CKM_RSA_X_509) { + CK_BYTE dec_message[BUFFER_SIZE]; + int padding = ((mech->mech == CKM_RSA_X_509) + ? RSA_NO_PADDING : RSA_PKCS1_PADDING); + int dec_message_length = RSA_public_decrypt(sign_length, sign, + dec_message, o->key.rsa, padding); + if (dec_message_length < 0) { + fprintf(stderr, "RSA_public_decrypt: rv = %d: %s\n", dec_message_length, + ERR_error_string(ERR_peek_last_error(), NULL)); + return -1; + } + if (memcmp(dec_message, message, dec_message_length) == 0 + && dec_message_length == (int) message_length) { + debug_print(" [ OK %s ] Signature is valid.", o->id_str); + mech->result_flags |= FLAGS_SIGN_OPENSSL; + return 1; + } else { + fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + return 0; + } + } + + /* Digest mechanisms */ + switch (mech->mech) { + case CKM_SHA1_RSA_PKCS: + cmp_message = SHA1(message, message_length, NULL); + cmp_message_length = SHA_DIGEST_LENGTH; + type = NID_sha1; + break; + case CKM_SHA224_RSA_PKCS: + cmp_message = SHA224(message, message_length, NULL); + cmp_message_length = SHA224_DIGEST_LENGTH; + type = NID_sha224; + break; + case CKM_SHA256_RSA_PKCS: + cmp_message = SHA256(message, message_length, NULL); + cmp_message_length = SHA256_DIGEST_LENGTH; + type = NID_sha256; + break; + case CKM_SHA384_RSA_PKCS: + cmp_message = SHA384(message, message_length, NULL); + cmp_message_length = SHA384_DIGEST_LENGTH; + type = NID_sha384; + break; + case CKM_SHA512_RSA_PKCS: + cmp_message = SHA512(message, message_length, NULL); + cmp_message_length = SHA512_DIGEST_LENGTH; + type = NID_sha512; + break; + case CKM_MD5_RSA_PKCS: + cmp_message = MD5(message, message_length, NULL); + cmp_message_length = MD5_DIGEST_LENGTH; + type = NID_md5; + break; + case CKM_RIPEMD160_RSA_PKCS: + cmp_message = RIPEMD160(message, message_length, NULL); + cmp_message_length = RIPEMD160_DIGEST_LENGTH; + type = NID_ripemd160; + break; + default: + debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str); + return 0; + } + rv = RSA_verify(type, cmp_message, cmp_message_length, + sign, sign_length, o->key.rsa); + if (rv == 1) { + debug_print(" [ OK %s ] Signature is valid.", o->id_str); + mech->result_flags |= FLAGS_SIGN_OPENSSL; + } else { + fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", + o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); + return -1; + } + } else if (o->type == EVP_PK_EC) { + unsigned int nlen; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BIGNUM *r = NULL, *s = NULL; + if (sig == NULL) { + fprintf(stderr, "ECDSA_SIG_new: failed"); + return -1; + } + nlen = sign_length/2; + r = BN_bin2bn(&sign[0], nlen, NULL); + s = BN_bin2bn(&sign[nlen], nlen, NULL); + ECDSA_SIG_set0(sig, r, s); + switch (mech->mech) { + case CKM_ECDSA_SHA512: + cmp_message = SHA512(message, message_length, NULL); + cmp_message_length = SHA512_DIGEST_LENGTH; + break; + case CKM_ECDSA_SHA384: + cmp_message = SHA384(message, message_length, NULL); + cmp_message_length = SHA384_DIGEST_LENGTH; + break; + case CKM_ECDSA_SHA256: + cmp_message = SHA256(message, message_length, NULL); + cmp_message_length = SHA256_DIGEST_LENGTH; + break; + case CKM_ECDSA_SHA1: + cmp_message = SHA1(message, message_length, NULL); + cmp_message_length = SHA_DIGEST_LENGTH; + break; + case CKM_ECDSA: + cmp_message = message; + cmp_message_length = message_length; + break; + default: + debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str); + return 0; + } + rv = ECDSA_do_verify(cmp_message, cmp_message_length, sig, o->key.ec); + if (rv == 1) { + ECDSA_SIG_free(sig); + debug_print(" [ OK %s ] EC Signature of length %lu is valid.", + o->id_str, message_length); + mech->result_flags |= FLAGS_SIGN_OPENSSL; + return 1; + } else { + ECDSA_SIG_free(sig); + fprintf(stderr, " [FAIL %s ] ECDSA_do_verify: rv = %lu: %s\n", o->id_str, + rv, ERR_error_string(ERR_peek_last_error(), NULL)); + return -1; + } + } else { + fprintf(stderr, " [ KEY %s ] Unknown type. Not verifying", o->id_str); + } + return 0; +} + +int verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, + CK_ULONG message_length, test_mech_t *mech, unsigned char *sign, + CK_ULONG sign_length, int multipart) +{ + CK_RV rv; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; + static int verify_support = 1; +#ifndef NDEBUG + char *name; +#endif + + if (!verify_support) + goto openssl_verify; + + /* try C_Verify() if it is supported */ + rv = fp->C_VerifyInit(info->session_handle, &sign_mechanism, + o->public_handle); + if (rv != CKR_OK) { + debug_print(" C_VerifyInit: rv = 0x%.8lX", rv); + verify_support = 0; /* avoid trying over and over again */ + goto openssl_verify; + } + if (multipart) { + int part = message_length / 3; + /* First part */ + rv = fp->C_VerifyUpdate(info->session_handle, message, part); + if (rv != CKR_OK) { + debug_print(" C_VerifyUpdate: rv = 0x%.8lX", rv); + goto openssl_verify; + } + /* Second part */ + rv = fp->C_VerifyUpdate(info->session_handle, message + part, + message_length - part); + if (rv != CKR_OK) { + debug_print(" C_VerifyUpdate: rv = 0x%.8lX", rv); + goto openssl_verify; + } + /* Final */ + rv = fp->C_VerifyFinal(info->session_handle, + sign, sign_length); +#ifndef NDEBUG + name = "C_VerifyFinal"; +#endif + } else { + rv = fp->C_Verify(info->session_handle, + message, message_length, sign, sign_length); +#ifndef NDEBUG + name = "C_Verify"; +#endif + } + if (rv == CKR_OK) { + mech->result_flags |= FLAGS_SIGN; + debug_print(" [ OK %s ] Verification successful", o->id_str); + return 1; + } + debug_print(" %s: rv = 0x%.8lX", name, rv); + verify_support = 0; /* avoid trying over and over again */ + +openssl_verify: + debug_print(" [ KEY %s ] Falling back to openssl verification", o->id_str); + return verify_message_openssl(o, info, message, message_length, mech, + sign, sign_length); +} + +/* Perform signature and verification of a message using private key referenced + * in the o object with mechanism defined by mech. Message length can be + * specified using argument message_length. + * + * Returns + * * 1 for successful Sign&Verify sequence + * * 0 for skipped test (unsupported mechanism, key, ...) + * * -1 otherwise. + * Serious errors terminate the execution. + */ +int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech, + CK_ULONG message_length, int multipart) +{ + CK_BYTE *message = NULL; + CK_BYTE *sign = NULL; + CK_ULONG sign_length = 0; + int rv = 0; + + if (message_length > strlen(SHORT_MESSAGE_TO_SIGN)) + fail_msg("Truncate is longer than the actual message"); + + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", o->id_str); + return 0; + } + + if (o->type != EVP_PK_EC && o->type != EVP_PK_RSA) { + debug_print(" [SKIP %s ] Skip non-RSA and non-EC key", o->id_str); + return 0; + } + + if (is_pss_mechanism(mech->mech)) { + mech->usage_flags &= ~CKF_SIGN; + debug_print(" [SKIP %s ] RSA-PSS tested separately", o->id_str); + return 0; + } + + if (mech->mech == CKM_RSA_X_509) /* manually add padding */ + message = rsa_x_509_pad_message(const_message, + &message_length, o, 0); + else if (mech->mech == CKM_RSA_PKCS) { + /* DigestInfo + SHA1(message) */ + message_length = 35; + message = malloc(message_length * sizeof(unsigned char)); + memcpy(message, SHORT_MESSAGE_DIGEST, message_length); + } else + message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN); + + debug_print(" [ KEY %s ] Signing message of length %lu using CKM_%s", + o->id_str, message_length, get_mechanism_name(mech->mech)); + rv = sign_message(o, info, message, message_length, mech, &sign, multipart); + if (rv <= 0) { + free(message); + return rv; + } + sign_length = (unsigned long) rv; + + debug_print(" [ KEY %s ] Verify message signature", o->id_str); + rv = verify_message(o, info, message, message_length, mech, + sign, sign_length, multipart); + free(sign); + free(message); + return rv; +} + +void readonly_tests(void **state) { + + token_info_t *info = (token_info_t *) *state; + unsigned int i; + int used, j; + test_certs_t objects; + + objects.count = 0; + objects.data = NULL; + + search_for_all_objects(&objects, info); + + P11TEST_START(info); + debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt"); + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + /* do the Sign&Verify and/or Encrypt&Decrypt */ + used = 0; + if (o->private_handle == CK_INVALID_HANDLE) { + debug_print(" [SKIP %s ] Missing private key", + o->id_str); + continue; + } + /* XXX some keys do not have appropriate flags, but we can use them + * or vice versa */ + //if (o->sign && o->verify) + for (j = 0; j < o->num_mechs; j++) + used |= sign_verify_test(&(objects.data[i]), info, + &(o->mechs[j]), 32, 0); + + //if (o->encrypt && o->decrypt) + for (j = 0; j < o->num_mechs; j++) + used |= encrypt_decrypt_test(&(objects.data[i]), info, + &(o->mechs[j]), 32, 0); + + if (!used) { + debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX", + o->id_str, o->key_type); + } + } + + if (objects.count == 0) { + printf(" [WARN] No objects to display\n"); + return; + } + + /* print summary */ + printf("[KEY ID] [LABEL]\n"); + printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT] [WRAP&UNWR] [ DERIVE ]\n"); + P11TEST_DATA_ROW(info, 4, + 's', "KEY ID", + 's', "MECHANISM", + 's', "SIGN&VERIFY WORKS", + 's', "ENCRYPT&DECRYPT WORKS"); + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + printf("\n[%-6s] [%s]\n", + o->id_str, + o->label); + printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s]\n", + o->key_type == CKK_RSA ? "RSA " : + o->key_type == CKK_EC ? " EC " : " ?? ", + o->bits, + o->verify_public == 1 ? " ./ " : " ", + o->sign ? "[./] " : "[ ] ", + o->verify ? " [./] " : " [ ] ", + o->encrypt ? "[./] " : "[ ] ", + o->decrypt ? " [./] " : " [ ] ", + o->wrap ? "[./]" : "[ ]", + o->unwrap ? "[./]" : "[ ]", + o->derive_pub ? "[./]" : "[ ]", + o->derive_priv ? "[./]" : "[ ]"); + if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) { + printf(" no usable attributes found ... ignored\n"); + continue; + } + for (j = 0; j < o->num_mechs; j++) { + test_mech_t *mech = &o->mechs[j]; + if ((mech->usage_flags & CKF_SIGN) == 0) { + /* not applicable mechanisms are skipped */ + continue; + } + printf(" [ %-20s ] [ %s ] [ %s ] [ ] [ ]\n", + get_mechanism_name(mech->mech), + mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : " ", + mech->result_flags & FLAGS_DECRYPT_ANY ? "[./]" : " "); + if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 && + (mech->result_flags & FLAGS_DECRYPT_ANY) == 0) + continue; /* skip empty rows for export */ + P11TEST_DATA_ROW(info, 4, + 's', o->id_str, + 's', get_mechanism_name(mech->mech), + 's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "", + 's', mech->result_flags & FLAGS_DECRYPT_ANY ? "YES" : ""); + } + } + printf(" Public == Cert -----^ ^ ^ ^ ^ ^ ^ ^----^- Attributes\n"); + printf(" Sign Attribute -------------' | | | | '---- Decrypt Attribute\n"); + printf(" Sign&Verify functionality -----' | | '------- Enc&Dec functionality\n"); + printf(" Verify Attribute -----------------' '---------- Encrypt Attribute\n"); + + clean_all_objects(&objects); + P11TEST_PASS(info); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_readonly.h opensc-0.19.0/src/tests/p11test/p11test_case_readonly.h --- opensc-0.17.0/src/tests/p11test/p11test_case_readonly.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_readonly.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * p11test_case_readonly.h: Sign & Verify tests + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" + +void readonly_tests(void **state); +int encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech, + CK_ULONG message_length, int multipart); +int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech, + CK_ULONG message_length, int multipart); + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_usage.c opensc-0.19.0/src/tests/p11test/p11test_case_usage.c --- opensc-0.17.0/src/tests/p11test/p11test_case_usage.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_usage.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,137 @@ +/* + * p11test_case_usage.c: Check if the usage flags are sane + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "p11test_case_usage.h" + +void usage_test(void **state) { + unsigned int i; + int errors = 0; + token_info_t *info = (token_info_t *) *state; + + test_certs_t objects; + objects.count = 0; + objects.data = NULL; + + P11TEST_START(info); + search_for_all_objects(&objects, info); + + debug_print("Check if the usage flags are sane.\n"); + for (i = 0; i < objects.count; i++) { + /* Ignore if there is missing private key */ + if (objects.data[i].private_handle == CK_INVALID_HANDLE) + continue; + + /* The usage flags are paired */ + if (objects.data[i].sign && !objects.data[i].verify) { + errors++; + fprintf(stderr, " [ ERROR %s ] If Sign is set, Verify should be set too.\n", + objects.data[i].id_str); + } + if (objects.data[i].decrypt && !objects.data[i].encrypt) { + errors++; + fprintf(stderr, " [ ERROR %s ] If Decrypt is set, Encrypt should be set too.\n", + objects.data[i].id_str); + } + if (objects.data[i].unwrap && !objects.data[i].wrap) { + errors++; + fprintf(stderr, " [ ERROR %s ] If Unwrap is set, Wrap should be set too.\n", + objects.data[i].id_str); + } + if (objects.data[i].derive_pub != objects.data[i].derive_priv) { + errors++; + fprintf(stderr, " [ ERROR %s ] Derive should be set on both private and public part.\n", + objects.data[i].id_str); + } + + /* We have at least one usage flag for every key group */ + if (! objects.data[i].sign && ! objects.data[i].verify && + ! objects.data[i].encrypt && ! objects.data[i].decrypt && + ! objects.data[i].wrap && ! objects.data[i].unwrap && + ! objects.data[i].derive_pub && ! objects.data[i].derive_priv) { + errors++; + fprintf(stderr, " [ ERROR %s ] Key group should have at least one usage flag.\n", + objects.data[i].id_str); + } + } + + /* print summary */ + printf("[KEY ID] [LABEL]\n"); + printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT] [WRAP&UNWR] [ DERIVE ] [ALWAYS_AUTH]\n"); + P11TEST_DATA_ROW(info, 14, + 's', "KEY ID", + 's', "LABEL", + 's', "TYPE", + 's', "BITS", + 's', "VERIFY PUBKEY", + 's', "SIGN", + 's', "VERIFY", + 's', "ENCRYPT", + 's', "DECRYPT", + 's', "WRAP", + 's', "UNWRAP", + 's', "DERIVE PUBLIC", + 's', "DERIVE PRIVATE", + 's', "ALWAYS AUTH"); + for (i = 0; i < objects.count; i++) { + printf("\n[%-6s] [%s]\n", + objects.data[i].id_str, + objects.data[i].label); + printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s] [ %s ]\n", + objects.data[i].key_type == CKK_RSA ? "RSA " : + objects.data[i].key_type == CKK_EC ? " EC " : " ?? ", + objects.data[i].bits, + objects.data[i].verify_public == 1 ? " ./ " : " ", + objects.data[i].sign ? "[./] " : "[ ] ", + objects.data[i].verify ? " [./] " : " [ ] ", + objects.data[i].encrypt ? "[./] " : "[ ] ", + objects.data[i].decrypt ? " [./] " : " [ ] ", + objects.data[i].wrap ? "[./]" : "[ ]", + objects.data[i].unwrap ? "[./]" : "[ ]", + objects.data[i].derive_pub ? "[./]" : "[ ]", + objects.data[i].derive_priv ? "[./]" : "[ ]", + objects.data[i].always_auth ? "[./]" : "[ ]"); + P11TEST_DATA_ROW(info, 14, + 's', objects.data[i].id_str, + 's', objects.data[i].label, + 's', objects.data[i].key_type == CKK_RSA ? "RSA" : + objects.data[i].key_type == CKK_EC ? "EC" : "??", + 'd', objects.data[i].bits, + 's', objects.data[i].verify_public == 1 ? "YES" : "", + 's', objects.data[i].sign ? "YES" : "", + 's', objects.data[i].verify ? "YES" : "", + 's', objects.data[i].encrypt ? "YES" : "", + 's', objects.data[i].decrypt ? "YES" : "", + 's', objects.data[i].wrap ? "YES" : "", + 's', objects.data[i].unwrap ? "YES" : "", + 's', objects.data[i].derive_pub ? "YES" : "", + 's', objects.data[i].derive_priv ? "YES" : "", + 's', objects.data[i].always_auth ? "YES" : ""); + } + printf(" Public == Cert -----^ ^-----^ ^-----^ ^----^ ^---^\n"); + printf(" Sign & Verify Attributes ------' | | |\n"); + printf(" Encrypt & Decrypt Attributes ----------------' | |\n"); + printf(" Wrap & Unwrap Attributes ---------------------------------' |\n"); + printf(" Public and Private key Derive Attributes -----------------------------'\n"); + + clean_all_objects(&objects); + if (errors > 0) + P11TEST_FAIL(info, "Not all the usage flags were successfully verified. See the verbose log."); + P11TEST_PASS(info); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_usage.h opensc-0.19.0/src/tests/p11test/p11test_case_usage.h --- opensc-0.17.0/src/tests/p11test/p11test_case_usage.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_usage.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * p11test_case_usage.h: Check if the usage flags are sane + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_case_common.h" +#include "p11test_case_readonly.h" + +void usage_test(void **state); diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_wait.c opensc-0.19.0/src/tests/p11test/p11test_case_wait.c --- opensc-0.17.0/src/tests/p11test/p11test_case_wait.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_wait.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * p11test_case_wait.c: Test slot events (insert / remove) + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "p11test_case_wait.h" + +void wait_test(void **state) { + + token_info_t *info = (token_info_t *) *state; + CK_FUNCTION_LIST_PTR fp = info->function_pointer; + CK_RV rv; + CK_SLOT_ID slot_id; + CK_SLOT_INFO slot_info; + int token_present = 0; + + P11TEST_START(info); + if (!info->interactive) { + fprintf(stderr, "To test wait, run in interactive mode (-i switch).\n"); + P11TEST_SKIP(info); + } + + do { + printf(" [ Waiting for slot event ... ]\n"); + + rv = fp->C_WaitForSlotEvent(0, &slot_id, NULL_PTR); + if (rv == CKR_FUNCTION_NOT_SUPPORTED) { + fprintf(stderr, "Function does not support call with blocking wait. Skipping.\n"); + skip(); + } else if (rv != CKR_OK) + P11TEST_FAIL(info, "C_WaitForSlotEvent: rv = 0x%.8lX\n", rv); + + rv = fp->C_GetSlotInfo(slot_id, &slot_info); + if (rv != CKR_OK) + P11TEST_FAIL(info, "C_GetSlotInfo: rv = 0x%.8lX\n", rv); + + token_present = ((slot_info.flags & CKF_TOKEN_PRESENT) != 0); + + printf(" [ Slot %lu ] %s\n", slot_id, slot_info.slotDescription); + printf(" Status: %s\n", + token_present ? "Token present": "No token"); + } while (!token_present); + P11TEST_PASS(info); +} diff -Nru opensc-0.17.0/src/tests/p11test/p11test_case_wait.h opensc-0.19.0/src/tests/p11test/p11test_case_wait.h --- opensc-0.17.0/src/tests/p11test/p11test_case_wait.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_case_wait.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * p11test_case_wait.h: Test slot events (insert / remove) + * + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "p11test_case_common.h" + +void wait_test(void **state); + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_common.h opensc-0.19.0/src/tests/p11test/p11test_common.h --- opensc-0.17.0/src/tests/p11test/p11test_common.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_common.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * p11test_common.h: Test suite shared declarations for PKCS#11 API + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef P11TEST_COMMON_H +#define P11TEST_COMMON_H +#include "config.h" +#include +#include +#include +#include +#include +#include "pkcs11/pkcs11.h" +#include "libopensc/sc-ossl-compat.h" + +#define MAX_MECHS 200 + +#ifndef NDEBUG + #define debug_print(fmt, ...) \ + { fprintf(stderr, fmt "\n", ##__VA_ARGS__); } while (0) +#else + #define debug_print(fmt, ...) +#endif + +#define FLAGS_SIGN 0x01 +#define FLAGS_SIGN_OPENSSL 0x02 +#define FLAGS_SIGN_ANY ( FLAGS_SIGN | FLAGS_SIGN_OPENSSL ) +#define FLAGS_DECRYPT 0x04 +#define FLAGS_DECRYPT_OPENSSL 0x08 +#define FLAGS_DECRYPT_ANY ( FLAGS_DECRYPT | FLAGS_DECRYPT_OPENSSL ) + +typedef struct { + char *outfile; + FILE *fd; + int in_test; + int first; + int in_data; + int first_data; +} log_context_t; + +typedef struct { + CK_MECHANISM_TYPE mech; + CK_MECHANISM_TYPE hash; + CK_RSA_PKCS_MGF_TYPE mgf; + int salt; + int usage_flags; + int result_flags; +} test_mech_t; + +typedef struct { + CK_FUNCTION_LIST_PTR function_pointer; + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session_handle; + CK_UTF8CHAR* pin; + size_t pin_length; + char *library_path; + unsigned int interactive; + log_context_t log; + + test_mech_t rsa_mechs[MAX_MECHS]; + size_t num_rsa_mechs; + test_mech_t ec_mechs[MAX_MECHS]; + size_t num_ec_mechs; + test_mech_t keygen_mechs[MAX_MECHS]; + size_t num_keygen_mechs; +} token_info_t; + +token_info_t token; + +#endif /* P11TEST_COMMON_H */ + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_helpers.c opensc-0.19.0/src/tests/p11test/p11test_helpers.c --- opensc-0.17.0/src/tests/p11test/p11test_helpers.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_helpers.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * p11test_helpers.c: Test suite for PKCS#11 API: Supporting functions + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_helpers.h" +#include "p11test_loader.h" + +int open_session(token_info_t *info) { + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + CK_RV rv; + + rv = function_pointer->C_OpenSession(info->slot_id, + CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, + &info->session_handle); + + if(rv != CKR_OK) + return 1; + + debug_print("Session was successfully created"); + return 0; +} + +int initialize_cryptoki(token_info_t *info) { + + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + CK_RV rv; + + rv = function_pointer->C_Initialize(NULL_PTR); + if(rv != CKR_OK){ + fprintf(stderr,"Could not initialize CRYPTOKI!\n"); + return 1; + } + + if(get_slot_with_card(info)) { + function_pointer->C_Finalize(NULL_PTR); + fprintf(stderr,"There is no card present in reader.\n"); + return 1; + } + + return 0; +} + +int token_initialize(void **state) { + token_info_t *info = (token_info_t *) *state; + if(initialize_cryptoki(info)) { + debug_print("CRYPTOKI couldn't be initialized"); + return 1; + } + return 0; +} + +void logfile_init(token_info_t *info) { + if (token.log.outfile == NULL) + return; + + if ((info->log.fd = fopen(token.log.outfile, "w")) == NULL) + fail_msg("Couldn't open file for test results."); + fprintf(info->log.fd, "{\n\"time\": 0,\n\"results\": ["); + info->log.in_test = 0; + info->log.first = 1; +} + +void logfile_finalize(token_info_t *info) { + if (info == NULL || info->log.fd == NULL) + return; + + /* Make sure the JSON object for test is closed */ + if (info->log.in_test) { + fprintf(info->log.fd, ",\n\t\"result\": \"unknown\"\n},"); + info->log.in_test = 0; + } + + fprintf(info->log.fd, "]\n}\n"); + fclose(info->log.fd); +} + +int group_setup(void **state) +{ + + token_info_t * info = calloc(sizeof(token_info_t), 1); + + assert_non_null(info); + + info->pin = token.pin; + info->pin_length = token.pin_length; + info->interactive = token.interactive; + info->slot_id = token.slot_id; + + if (load_pkcs11_module(info, token.library_path)) { + free(info); + fail_msg("Could not load module!\n"); + } + + logfile_init(info); + + *state = info; + return 0; +} + +int group_teardown(void **state) { + + token_info_t *info = (token_info_t *) *state; + debug_print("Clearing state after group tests!"); + // XXX do not finalize already Finalized + //if(info && info->function_pointer) + // info->function_pointer->C_Finalize(NULL_PTR); + + free(token.library_path); + free(token.pin); + + logfile_finalize(info); + free(info); + + close_pkcs11_module(); + + return 0; +} + +int prepare_token(token_info_t *info) { + if(initialize_cryptoki(info)) { + debug_print("CRYPTOKI couldn't be initialized"); + return 1; + } + + if(open_session(info)) { + debug_print("Could not open session to token!"); + return 1; + } + + return 0; +} + +int finalize_token(token_info_t *info) { + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + + info->session_handle = 0; + debug_print("Closing all sessions"); + function_pointer->C_CloseAllSessions(info->slot_id); + debug_print("Finalize CRYPTOKI"); + function_pointer->C_Finalize(NULL_PTR); + return 0; +} + +int user_login_setup(void **state) { + token_info_t *info = (token_info_t *) *state; + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + CK_RV rv; + + if (prepare_token(info)) + fail_msg("Could not prepare token.\n"); + + debug_print("Logging in to the token!"); + rv = function_pointer->C_Login(info->session_handle, CKU_USER, + token.pin, token.pin_length); + + if(rv != CKR_OK) + fail_msg("Could not login to token with user PIN '%s'\n", token.pin); + + return 0; +} + +int after_test_cleanup(void **state) { + + token_info_t *info = (token_info_t *) *state; + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + + debug_print("Logging out from token"); + function_pointer->C_Logout(info->session_handle); + + finalize_token(info); + return 0; +} + +int token_setup(void **state) { + token_info_t *info = (token_info_t *) *state; + + if(prepare_token(info)) + fail_msg("Could not prepare token.\n"); + + return 0; +} + +int token_cleanup(void **state) { + token_info_t *info = (token_info_t *) *state; + + finalize_token(info); + return 0; +} + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_helpers.h opensc-0.19.0/src/tests/p11test/p11test_helpers.h --- opensc-0.17.0/src/tests/p11test/p11test_helpers.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_helpers.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * p11test_helpers.h: Test suite for PKCS#11 API: Supporting functions + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef P11TEST_HELPERS_H +#define P11TEST_HELPERS_H +#include "p11test_common.h" + +int group_setup(void **state); +int group_teardown(void **state); + +int user_login_setup(void **state); +int after_test_cleanup(void **state); + +int token_setup(void **state); +int token_cleanup(void **state); + +int token_initialize(void **state); +#endif //P11TEST_HELPERS_H diff -Nru opensc-0.17.0/src/tests/p11test/p11test_loader.c opensc-0.19.0/src/tests/p11test/p11test_loader.c --- opensc-0.17.0/src/tests/p11test/p11test_loader.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_loader.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,147 @@ +/* + * p11test_loader.c: Library loader for PKCS#11 test suite + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "p11test_loader.h" + +static void *pkcs11_so; + +int get_slot_with_card(token_info_t * info) +{ + CK_SLOT_ID_PTR slot_list; + CK_SLOT_ID slot_id; + CK_ULONG slot_count = 0; + CK_RV rv; + int error = 0; + unsigned int i; + + CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer; + + /* Get slot list for memory allocation */ + rv = function_pointer->C_GetSlotList(0, NULL_PTR, &slot_count); + + if ((rv == CKR_OK) && (slot_count > 0)) { + slot_list = malloc(slot_count * sizeof (CK_SLOT_ID)); + + if (slot_list == NULL) { + fprintf(stderr, "System error: unable to allocate memory\n"); + return 1; + } + + /* Get the slot list for processing */ + rv = function_pointer->C_GetSlotList(0, slot_list, &slot_count); + if (rv != CKR_OK) { + fprintf(stderr, "GetSlotList failed: unable to get slot count.\n"); + error = 1; + goto cleanup; + } + } else { + fprintf(stderr, "GetSlotList failed: unable to get slot list.\n"); + return 1; + } + + /* Find a slot capable of specified mechanism */ + for (i = 0; i < slot_count; i++) { + CK_SLOT_INFO slot_info; + slot_id = slot_list[i]; + + rv = function_pointer->C_GetSlotInfo(slot_id, &slot_info); + if (rv != CKR_OK) + continue; + + if (info->slot_id == slot_id) { + if (info->slot_id == slot_list[i]) { /* explicitly specified slot */ + debug_print("Manually selected slot %lu (%s a token)\n", info->slot_id, + ((slot_info.flags & CKF_TOKEN_PRESENT) ? "with" : "without")); + goto cleanup; + } + } + + if (slot_info.flags & CKF_TOKEN_PRESENT) { + /* first found slot if not specified */ + if (info->slot_id == (unsigned long) -1) { + info->slot_id = slot_id; + goto cleanup; + } + } + } + error = 1; + fprintf(stderr, "No slot with card inserted or the selected slot does not exist\n"); + + cleanup: + if (slot_list) { + free(slot_list); + } + + return error; +} + +int load_pkcs11_module(token_info_t * info, const char* path_to_pkcs11_library) { + CK_RV rv; + CK_RV (*C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR) = 0; + + if(strlen(path_to_pkcs11_library) == 0) { + fprintf(stderr, "You have to specify path to PKCS#11 library."); + return 1; + } + + pkcs11_so = dlopen(path_to_pkcs11_library, RTLD_NOW); + + if (!pkcs11_so) { + fprintf(stderr, "Error loading pkcs#11 so: %s\n", dlerror()); + return 1; + } + + C_GetFunctionList = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(pkcs11_so, "C_GetFunctionList"); + + if (!C_GetFunctionList) { + fprintf(stderr, "Could not get function list: %s\n", dlerror()); + return 1; + } + + rv = C_GetFunctionList(&info->function_pointer); + if (CKR_OK != rv) { + fprintf(stderr, "C_GetFunctionList call failed: 0x%.8lX", rv); + return 1; + } + + rv = info->function_pointer->C_Initialize(NULL_PTR); + + if (rv != CKR_OK) { + fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); + return 1; + } + + if (get_slot_with_card(info)) { + fprintf(stderr, "There is no card present in reader.\n"); + info->function_pointer->C_Finalize(NULL_PTR); + return 1; + } + + info->function_pointer->C_Finalize(NULL_PTR); + return 0; +} + +void close_pkcs11_module() { + if(pkcs11_so) + dlclose(pkcs11_so); +} + diff -Nru opensc-0.17.0/src/tests/p11test/p11test_loader.h opensc-0.19.0/src/tests/p11test/p11test_loader.h --- opensc-0.17.0/src/tests/p11test/p11test_loader.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test_loader.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * p11test_loader.h: Library loader for PKCS#11 test suite + * + * Copyright (C) 2016 Martin Strhársky + * Copyright (C) 2016, 2017 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef P11TEST_LOADER_H +#define P11TEST_LOADER_H + +#include +#include "p11test_helpers.h" + +int load_pkcs11_module(token_info_t * info, const char* path_to_pkcs11_library); +int get_slot_with_card(token_info_t * info); +void close_pkcs11_module(); + + +#endif //P11TEST_LOADER_H diff -Nru opensc-0.17.0/src/tests/p11test/p11test.supp opensc-0.19.0/src/tests/p11test/p11test.supp --- opensc-0.17.0/src/tests/p11test/p11test.supp 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/p11test.supp 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,30 @@ +{ + Suppress pcsc_detect_readers() + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + obj:* + obj:* + fun:pcsc_detect_readers + fun:sc_ctx_detect_readers + fun:sc_context_create + fun:C_Initialize +} +{ + Suppress MessageSend() errors + Memcheck:Param + socketcall.sendto(msg) + fun:send + fun:MessageSend + fun:MessageSendWithHeader + fun:SCardConnect + fun:pcsc_detect_readers + fun:sc_ctx_detect_readers + fun:sc_context_create + fun:C_Initialize + fun:load_pkcs11_module + fun:group_setup + obj:/usr/lib64/libcmocka.so.0.3.1 + fun:_cmocka_run_group_tests +} + diff -Nru opensc-0.17.0/src/tests/p11test/README.md opensc-0.19.0/src/tests/p11test/README.md --- opensc-0.17.0/src/tests/p11test/README.md 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/README.md 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,56 @@ +# Non-destructive PKCS#11 test suite (not only for readonly cards) + +## What are the dependencies? + +In addition to the dependencies needed by OpenSC, the test suite is +using [`cmocka`](https://cmocka.org/) unit testing framework +(`libcmocka-devel` package in Fedora/EPEL). + +## How to use? + +Build OpenSC from source: + + git clone git@github.com:OpenSC/OpenSC.git + cd OpenSC + ./bootstrap + ./configure + make -j4 + +Plug in the card/reader, change to test directory and run the test: + + cd src/tests/p11test + ./p11test -p 123456 + +It will run all tests on the first card found in PKCS#11 API +with pin `123456` and using just built OpenSC shared library from master. + +### I have more slots with different cards. + +Slot can be selected using `-s` switch on command-line. + + ./p11test -s 4 + +Slot numbers can be obtained using from `pkcs11-tool -L` (note that different +libraries might have different numbers for the slots). + +### I want to test different pkcs11 library + +You can specify different library or build from different branch +on command-line: + + ./p11test -m /usr/lib64/pkcs11/libcoolkeypk11.so + +or to debug PKCS#11 calls using `/usr/lib64/pkcs11-spy.so`: + + export PKCS11SPY="../pkcs11/.libs/opensc-pkcs11.so" + ./p11test -m ../pkcs11/.libs/pkcs11-spy.so + +You can run the test suite also on the soft tokens. The testbench for +`softhsm` and `opencryptoki` is available in the script `runtest.sh`. + +TODO: + + * Test `CKM_ECDSA_DERIVE` mechanism(s) + * Read pin from environment variable? + * Keygen write tests (optional) + * Reflect cmocka dependency in the configure diff -Nru opensc-0.17.0/src/tests/p11test/runtest.sh opensc-0.19.0/src/tests/p11test/runtest.sh --- opensc-0.17.0/src/tests/p11test/runtest.sh 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tests/p11test/runtest.sh 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,145 @@ +#!/bin/bash +# runtest.sh: Run test on existing card with possible initialization +# +# Copyright (C) 2016, 2017 Red Hat, Inc. +# +# Author: Jakub Jelen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#set -x +SOPIN="12345678" +PIN="123456" +export GNUTLS_PIN=$PIN +GENERATE_KEYS=1 +PKCS11_TOOL="../../tools/pkcs11-tool"; + +function generate_cert() { + TYPE="$1" + ID="$2" + LABEL="$3" + + # Generate key pair + $PKCS11_TOOL --keypairgen --key-type="$TYPE" --login --pin=$PIN \ + --module="$P11LIB" --label="$LABEL" --id=$ID + + if [[ "$?" -ne "0" ]]; then + echo "Couldn't generate $TYPE key pair" + return 1 + fi + + # check type value for the PKCS#11 URI (RHEL7 is using old "object-type") + TYPE_KEY="type" + p11tool --list-all --provider="$P11LIB" --login | grep "object-type" && \ + TYPE_KEY="object-type" + + # Generate certificate + certtool --generate-self-signed --outfile="$TYPE.cert" --template=cert.cfg \ + --provider="$P11LIB" --load-privkey "pkcs11:object=$LABEL;$TYPE_KEY=private" \ + --load-pubkey "pkcs11:object=$LABEL;$TYPE_KEY=public" + # convert to DER: + openssl x509 -inform PEM -outform DER -in "$TYPE.cert" -out "$TYPE.cert.der" + # Write certificate + #p11tool --login --write --load-certificate="$TYPE.cert" --label="$LABEL" \ + # --provider="$P11LIB" + $PKCS11_TOOL --write-object "$TYPE.cert.der" --type=cert --id=$ID \ + --label="$LABEL" --module="$P11LIB" + + rm "$TYPE.cert" "$TYPE.cert.der" + + p11tool --login --provider="$P11LIB" --list-all +} + +function card_setup() { + ECC_KEYS=1 + case $1 in + "softhsm") + P11LIB="/usr/lib64/pkcs11/libsofthsm2.so" + echo "directories.tokendir = .tokens/" > .softhsm2.conf + mkdir ".tokens" + export SOFTHSM2_CONF=".softhsm2.conf" + # Init token + softhsm2-util --init-token --slot 0 --label "SC test" --so-pin="$SOPIN" --pin="$PIN" + ;; + "opencryptoki") + # Supports only RSA mechanisms + ECC_KEYS=0 + P11LIB="/usr/lib64/pkcs11/libopencryptoki.so" + SO_PIN=87654321 + SLOT_ID=3 # swtok slot + systemctl is-active pkcsslotd > /dev/null + if [[ "$?" -ne "0" ]]; then + echo "Opencryptoki needs pkcsslotd running" + exit 1 + fi + groups | grep pkcs11 > /dev/null + if [[ "$?" -ne "0" ]]; then + echo "Opencryptoki requires the user to be in pkcs11 group" + exit 1 + fi + echo "test_swtok" | /usr/sbin/pkcsconf -I -c $SLOT_ID -S $SO_PIN + /usr/sbin/pkcsconf -u -c $SLOT_ID -S $SO_PIN -n $PIN + ;; + "readonly") + GENERATE_KEYS=0 + if [[ ! -z "$2" && -f "$2" ]]; then + P11LIB="$2" + else + P11LIB="/usr/lib64/pkcs11/opensc-pkcs11.so" + P11LIB="../pkcs11/.libs/opensc-pkcs11.so" + fi + ;; + *) + echo "Error: Missing argument." + echo " Usage:" + echo " runtest.sh [softhsm|opencryptoki|readonly [pkcs-library.so]]" + exit 1; + ;; + esac + + if [[ $GENERATE_KEYS -eq 1 ]]; then + # Generate 1024b RSA Key pair + generate_cert "RSA:1024" "01" "RSA_auth" + # Generate 2048b RSA Key pair + generate_cert "RSA:2048" "02" "RSA2048" + if [[ $ECC_KEYS -eq 1 ]]; then + # Generate 256b ECC Key pair + generate_cert "EC:secp256r1" "03" "ECC_auth" + # Generate 521b ECC Key pair + generate_cert "EC:secp521r1" "04" "ECC521" + fi + fi +} + +function card_cleanup() { + case $1 in + "softhsm") + rm .softhsm2.conf + rm -rf ".tokens" + ;; + esac +} + +card_setup "$@" + +make p11test || exit +if [[ "$PKCS11SPY" -ne "" ]]; then + export PKCS11SPY="$P11LIB" + $VALGRIND ./p11test -m /usr/lib64/pkcs11/pkcs11-spy.so -p $PIN +else + #bash + $VALGRIND ./p11test -m "$P11LIB" -o test.json -p $PIN +fi + +card_cleanup "$@" diff -Nru opensc-0.17.0/src/tests/pintest.c opensc-0.19.0/src/tests/pintest.c --- opensc-0.17.0/src/tests/pintest.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tests/pintest.c 2018-09-13 11:47:21.000000000 +0000 @@ -13,6 +13,7 @@ #include #endif +#include "libopensc/internal.h" #include "libopensc/opensc.h" #include "libopensc/pkcs15.h" #include "common/compat_getpass.h" @@ -56,7 +57,7 @@ { struct sc_pkcs15_auth_info *pin_info = (struct sc_pkcs15_auth_info *) pin_obj->data; int i = 0; - char prompt[80]; + char prompt[(sizeof pin_obj->label) + 30]; u8 *pass; if (pin_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { @@ -64,7 +65,8 @@ return 0; } - sprintf(prompt, "Please enter PIN code [%.*s]: ", (int) sizeof pin_obj->label, pin_obj->label); + snprintf(prompt, sizeof(prompt), "Please enter PIN code [%.*s]: ", + (int) sizeof pin_obj->label, pin_obj->label); pass = (u8 *) getpass(prompt); if (SC_SUCCESS != sc_lock(card)) diff -Nru opensc-0.17.0/src/tools/cardos-tool.c opensc-0.19.0/src/tools/cardos-tool.c --- opensc-0.17.0/src/tools/cardos-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/cardos-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -188,6 +188,9 @@ printf(" (that's CardOS M4.4)\n"); } else if (apdu.resp[0] == 0xc9 && apdu.resp[1] == 0x01) { printf(" (that's CardOS V5.0)\n"); + } else if (apdu.resp[0] == 0xc9 && + (apdu.resp[1] == 0x02 || apdu.resp[1] == 0x03)) { + printf(" (that's CardOS V5.3)\n"); } else { printf(" (unknown Version)\n"); } @@ -462,7 +465,7 @@ memcpy(&enc_input[0],&in[5],plain_lc); for (i=0; i < 8; i++) enc_input[i+plain_lc] = des_out[i]; enc_input[plain_lc+8] = 0x80; /* iso padding */ - /* calloc already cleard the remaining bytes to 00 */ + /* calloc already cleared the remaining bytes to 00 */ if (outlen < 5 + enc_input_len) { free(mac_input); @@ -482,18 +485,18 @@ /* xor data and IV (8 bytes 00) to get input data */ for (i=0; i < 8; i++) des_in[i] = enc_input[i] ^ 00; - /* encrypt with des2 (tripple des, but using keys A-B-A) */ + /* encrypt with des2 (triple des, but using keys A-B-A) */ DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1); /* copy encrypted bytes into output */ for (i=0; i < 8; i++) out[5+i] = des_out[i]; - /* encrypt other blocks (usualy one) */ + /* encrypt other blocks (usually one) */ for (j=1; j < (enc_input_len / 8); j++) { /* xor data and prev. result to get input data */ for (i=0; i < 8; i++) des_in[i] = enc_input[i+j*8] ^ des_out[i]; - /* encrypt with des2 (tripple des, but using keys A-B-A) */ + /* encrypt with des2 (triple des, but using keys A-B-A) */ DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1); /* copy encrypted bytes into output */ @@ -1024,7 +1027,7 @@ } #endif -int main(int argc, char *const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_info = 0; diff -Nru opensc-0.17.0/src/tools/cryptoflex-tool.c opensc-0.19.0/src/tools/cryptoflex-tool.c --- opensc-0.17.0/src/tools/cryptoflex-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/cryptoflex-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -21,6 +21,7 @@ #include "config.h" #include "libopensc/sc-ossl-compat.h" +#include "libopensc/internal.h" #include #include #include @@ -331,7 +332,7 @@ fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r)); return 2; } - bufsize = file->size; + bufsize = MIN(file->size, sizeof buf); sc_file_free(file); r = sc_read_binary(card, 0, buf, bufsize, 0); if (r < 0) { @@ -382,7 +383,7 @@ e = sc_file_get_acl_entry(file, SC_AC_OP_READ); if (e == NULL || e->method == SC_AC_NEVER) return 10; - bufsize = file->size; + bufsize = MIN(file->size, sizeof buf); sc_file_free(file); r = sc_read_binary(card, 0, buf, bufsize, 0); if (r < 0) { @@ -978,7 +979,7 @@ return create_pin_file(&path, opt_pin_num, ""); } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int action_count = 0; diff -Nru opensc-0.17.0/src/tools/dnie-tool.c opensc-0.19.0/src/tools/dnie-tool.c --- opensc-0.17.0/src/tools/dnie-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/dnie-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -171,7 +171,7 @@ } if ( strcmp(card->name,"dnie") ) { - fprintf(stderr, "Error: Card sems not to be a DNIe\n"); + fprintf(stderr, "Error: Card seems not to be a DNIe\n"); err=-1; goto dnie_tool_end; } @@ -211,12 +211,12 @@ } if (opt_operation & OP_GET_IDESP) { if (data[3]==NULL) - printf("IDESP: (No disponible)\n"); + printf("IDESP: (Not available)\n"); else printf("IDESP: %s\n",data[3]); } if (opt_operation & OP_GET_VERSION) { if (data[4]==NULL) - printf("DNIe Version: (No disponible)\n"); + printf("DNIe Version: (Not available)\n"); else printf("DNIe Version: %s\n",data[4]); } if (opt_operation & OP_GET_SERIALNR) { diff -Nru opensc-0.17.0/src/tools/egk-tool.c opensc-0.19.0/src/tools/egk-tool.c --- opensc-0.17.0/src/tools/egk-tool.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/egk-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2017 Frank Morgner + * + * This file is part of OpenSC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "egk-tool-cmdline.h" +#include "libopensc/log.h" +#include "libopensc/opensc.h" +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef ENABLE_ZLIB +#include + +int uncompress_gzip(void* uncompressed, size_t *uncompressed_len, + const void* compressed, size_t compressed_len) +{ + z_stream stream; + memset(&stream, 0, sizeof stream); + stream.total_in = compressed_len; + stream.avail_in = compressed_len; + stream.total_out = *uncompressed_len; + stream.avail_out = *uncompressed_len; + stream.next_in = (Bytef *) compressed; + stream.next_out = (Bytef *) uncompressed; + + /* 15 window bits, and the +32 tells zlib to to detect if using gzip or zlib */ + if (Z_OK == inflateInit2(&stream, (15 + 32)) + && Z_STREAM_END == inflate(&stream, Z_FINISH)) { + *uncompressed_len = stream.total_out; + } else { + return SC_ERROR_INVALID_DATA; + } + inflateEnd(&stream); + + return SC_SUCCESS; +} +#else +int uncompress_gzip(void* uncompressed, size_t *uncompressed_len, + const void* compressed, size_t compressed_len) +{ + return SC_ERROR_NOT_SUPPORTED; +} +#endif + +#define PRINT(c) (isprint(c) ? c : '?') + +void dump_binary(void *buf, size_t buf_len) +{ +#ifdef _WIN32 + _setmode(fileno(stdout), _O_BINARY); +#endif + fwrite(buf, 1, buf_len, stdout); +#ifdef _WIN32 + _setmode(fileno(stdout), _O_TEXT); +#endif +} + +const unsigned char aid_hca[] = {0xD2, 0x76, 0x00, 0x00, 0x01, 0x02}; + +static int initialize(int reader_id, int verbose, + sc_context_t **ctx, sc_reader_t **reader) +{ + unsigned int i, reader_count; + int r; + + if (!ctx || !reader) + return SC_ERROR_INVALID_ARGUMENTS; + + r = sc_establish_context(ctx, ""); + if (r < 0 || !*ctx) { + fprintf(stderr, "Failed to create initial context: %s", sc_strerror(r)); + return r; + } + + (*ctx)->debug = verbose; + (*ctx)->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER; + + reader_count = sc_ctx_get_reader_count(*ctx); + + if (reader_count == 0) { + sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No reader not found.\n"); + return SC_ERROR_NO_READERS_FOUND; + } + + if (reader_id < 0) { + /* Automatically try to skip to a reader with a card if reader not specified */ + for (i = 0; i < reader_count; i++) { + *reader = sc_ctx_get_reader(*ctx, i); + if (sc_detect_card_presence(*reader) & SC_READER_CARD_PRESENT) { + reader_id = i; + sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Using the first reader" + " with a card: %s", (*reader)->name); + break; + } + } + if ((unsigned int) reader_id >= reader_count) { + sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No card found, using the first reader."); + reader_id = 0; + } + } + + if ((unsigned int) reader_id >= reader_count) { + sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Invalid reader number " + "(%d), only %d available.\n", reader_id, reader_count); + return SC_ERROR_NO_READERS_FOUND; + } + + *reader = sc_ctx_get_reader(*ctx, reader_id); + + return SC_SUCCESS; +} + +int read_file(struct sc_card *card, char *str_path, unsigned char **data, size_t *data_len) +{ + struct sc_path path; + struct sc_file *file; + unsigned char *p; + int ok = 0; + int r; + size_t len; + + sc_format_path(str_path, &path); + if (SC_SUCCESS != sc_select_file(card, &path, &file)) { + goto err; + } + + len = file && file->size > 0 ? file->size : 4096; + p = realloc(*data, len); + if (!p) { + goto err; + } + *data = p; + *data_len = len; + + r = sc_read_binary(card, 0, p, len, 0); + if (r < 0) + goto err; + + *data_len = r; + ok = 1; + +err: + sc_file_free(file); + + return ok; +} + +void decode_version(unsigned char *bcd, unsigned int *major, unsigned int *minor, unsigned int *fix) +{ + *major = 0; + *minor = 0; + *fix = 0; + + /* decode BCD to decimal */ + if ((bcd[0]>>4) < 10 && ((bcd[0]&0xF) < 10) && ((bcd[1]>>4) < 10)) { + *major = (bcd[0]>>4)*100 + (bcd[0]&0xF)*10 + (bcd[1]>>4); + } + if (((bcd[1]&0xF) < 10) && ((bcd[2]>>4) < 10) && ((bcd[2]&0xF) < 10)) { + *minor = (bcd[1]&0xF)*100 + (bcd[2]>>4)*10 + (bcd[2]&0xF); + } + if ((bcd[3]>>4) < 10 && ((bcd[3]&0xF) < 10) + && (bcd[4]>>4) < 10 && ((bcd[4]&0xF) < 10)) { + *fix = (bcd[3]>>4)*1000 + (bcd[3]&0xF)*100 + + (bcd[4]>>4)*10 + (bcd[4]&0xF); + } +} + +int +main (int argc, char **argv) +{ + struct gengetopt_args_info cmdline; + struct sc_path path; + struct sc_context *ctx; + struct sc_reader *reader = NULL; + struct sc_card *card; + unsigned char *data = NULL; + size_t data_len = 0; + int r; + + if (cmdline_parser(argc, argv, &cmdline) != 0) + exit(1); + + r = initialize(cmdline.reader_arg, cmdline.verbose_given, &ctx, &reader); + if (r < 0) { + fprintf(stderr, "Can't initialize reader\n"); + exit(1); + } + + if (sc_connect_card(reader, &card) < 0) { + fprintf(stderr, "Could not connect to card\n"); + sc_release_context(ctx); + exit(1); + } + + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_hca, sizeof aid_hca, 0, 0); + if (SC_SUCCESS != sc_select_file(card, &path, NULL)) + goto err; + + if (cmdline.pd_flag + && read_file(card, "D001", &data, &data_len) + && data_len >= 2) { + size_t len_pd = (data[0] << 8) | data[1]; + + if (len_pd + 2 <= data_len) { + unsigned char uncompressed[1024]; + size_t uncompressed_len = sizeof uncompressed; + + if (uncompress_gzip(uncompressed, &uncompressed_len, + data + 2, len_pd) == SC_SUCCESS) { + dump_binary(uncompressed, uncompressed_len); + } else { + dump_binary(data + 2, len_pd); + } + } + } + + if ((cmdline.vd_flag || cmdline.gvd_flag) + && read_file(card, "D001", &data, &data_len) + && data_len >= 8) { + size_t off_vd = (data[0] << 8) | data[1]; + size_t end_vd = (data[2] << 8) | data[3]; + size_t off_gvd = (data[4] << 8) | data[5]; + size_t end_gvd = (data[6] << 8) | data[7]; + size_t len_vd = end_vd - off_vd + 1; + size_t len_gvd = end_gvd - off_gvd + 1; + + if (off_vd <= end_vd && end_vd < data_len + && off_gvd <= end_gvd && end_gvd < data_len) { + unsigned char uncompressed[1024]; + size_t uncompressed_len = sizeof uncompressed; + + if (cmdline.vd_flag) { + if (uncompress_gzip(uncompressed, &uncompressed_len, + data + off_vd, len_vd) == SC_SUCCESS) { + dump_binary(uncompressed, uncompressed_len); + } else { + dump_binary(data + off_vd, len_vd); + } + } + + if (cmdline.gvd_flag) { + if (uncompress_gzip(uncompressed, &uncompressed_len, + data + off_gvd, len_gvd) == SC_SUCCESS) { + dump_binary(uncompressed, uncompressed_len); + } else { + dump_binary(data + off_gvd, len_gvd); + } + } + } + } + + if (cmdline.vsd_status_flag + && read_file(card, "D00C", &data, &data_len) + && data_len >= 25) { + char *status; + unsigned int major, minor, fix; + + switch (data[0]) { + case '0': + status = "Transactions pending"; + break; + case '1': + status = "No transactions pending"; + break; + default: + status = "Unknown"; + break; + } + + decode_version(data+15, &major, &minor, &fix); + + printf( + "Status %s\n" + "Timestamp %c%c.%c%c.%c%c%c%c at %c%c:%c%c:%c%c\n" + "Version %u.%u.%u\n", + status, + PRINT(data[7]), PRINT(data[8]), + PRINT(data[5]), PRINT(data[6]), + PRINT(data[1]), PRINT(data[2]), PRINT(data[3]), PRINT(data[4]), + PRINT(data[9]), PRINT(data[10]), + PRINT(data[11]), PRINT(data[12]), + PRINT(data[13]), PRINT(data[14]), + major, minor, fix); + } + +err: + sc_disconnect_card(card); + sc_release_context(ctx); + cmdline_parser_free (&cmdline); + + return 0; +} diff -Nru opensc-0.17.0/src/tools/egk-tool-cmdline.c opensc-0.19.0/src/tools/egk-tool-cmdline.c --- opensc-0.17.0/src/tools/egk-tool-cmdline.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/egk-tool-cmdline.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1306 @@ +/* + File autogenerated by gengetopt version 2.22.6 + generated with the following command: + /usr/bin/gengetopt --include-getopt --file-name=egk-tool-cmdline --output-dir=. + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifndef FIX_UNUSED +#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ +#endif + + +#include "egk-tool-cmdline.h" + +const char *gengetopt_args_info_purpose = ""; + +const char *gengetopt_args_info_usage = "Usage: egk-tool [OPTIONS]..."; + +const char *gengetopt_args_info_versiontext = ""; + +const char *gengetopt_args_info_description = ""; + +const char *gengetopt_args_info_help[] = { + " -h, --help Print help and exit", + " -V, --version Print version and exit", + " -r, --reader=INT Number of the PC/SC reader to use (-1 for autodetect)\n (default=`-1')", + " -v, --verbose Use (several times) to be more verbose", + "\nHealth Care Application (HCA):", + " --pd Show 'Persönliche Versicherungsdaten' (XML) (default=off)", + " --vd Show 'Allgemeine Versicherungsdaten' (XML) (default=off)", + " --gvd Show 'Geschützte Versicherungsdaten' (XML) (default=off)", + " --vsd-status Show 'Versichertenstammdaten-Status' (default=off)", + "\nReport bugs to https://github.com/OpenSC/OpenSC/issues\n\nWritten by Frank Morgner ", + 0 +}; + +typedef enum {ARG_NO + , ARG_FLAG + , ARG_INT +} cmdline_parser_arg_type; + +static +void clear_given (struct gengetopt_args_info *args_info); +static +void clear_args (struct gengetopt_args_info *args_info); + +static int +cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error); + +static int +cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); + +static char * +gengetopt_strdup (const char *s); + +static +void clear_given (struct gengetopt_args_info *args_info) +{ + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->reader_given = 0 ; + args_info->verbose_given = 0 ; + args_info->pd_given = 0 ; + args_info->vd_given = 0 ; + args_info->gvd_given = 0 ; + args_info->vsd_status_given = 0 ; +} + +static +void clear_args (struct gengetopt_args_info *args_info) +{ + FIX_UNUSED (args_info); + args_info->reader_arg = -1; + args_info->reader_orig = NULL; + args_info->pd_flag = 0; + args_info->vd_flag = 0; + args_info->gvd_flag = 0; + args_info->vsd_status_flag = 0; + +} + +static +void init_args_info(struct gengetopt_args_info *args_info) +{ + + + args_info->help_help = gengetopt_args_info_help[0] ; + args_info->version_help = gengetopt_args_info_help[1] ; + args_info->reader_help = gengetopt_args_info_help[2] ; + args_info->verbose_help = gengetopt_args_info_help[3] ; + args_info->verbose_min = 0; + args_info->verbose_max = 0; + args_info->pd_help = gengetopt_args_info_help[5] ; + args_info->vd_help = gengetopt_args_info_help[6] ; + args_info->gvd_help = gengetopt_args_info_help[7] ; + args_info->vsd_status_help = gengetopt_args_info_help[8] ; + +} + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", + (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), + CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); +} + +static void print_help_common(void) { + cmdline_parser_print_version (); + + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); + + if (strlen(gengetopt_args_info_usage) > 0) + printf("\n%s\n", gengetopt_args_info_usage); + + printf("\n"); + + if (strlen(gengetopt_args_info_description) > 0) + printf("%s\n\n", gengetopt_args_info_description); +} + +void +cmdline_parser_print_help (void) +{ + int i = 0; + print_help_common(); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); +} + +void +cmdline_parser_init (struct gengetopt_args_info *args_info) +{ + clear_given (args_info); + clear_args (args_info); + init_args_info (args_info); +} + +void +cmdline_parser_params_init(struct cmdline_parser_params *params) +{ + if (params) + { + params->override = 0; + params->initialize = 1; + params->check_required = 1; + params->check_ambiguity = 0; + params->print_errors = 1; + } +} + +struct cmdline_parser_params * +cmdline_parser_params_create(void) +{ + struct cmdline_parser_params *params = + (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); + cmdline_parser_params_init(params); + return params; +} + +static void +free_string_field (char **s) +{ + if (*s) + { + free (*s); + *s = 0; + } +} + + +static void +cmdline_parser_release (struct gengetopt_args_info *args_info) +{ + + free_string_field (&(args_info->reader_orig)); + + + + clear_given (args_info); +} + + +static void +write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) +{ + FIX_UNUSED (values); + if (arg) { + fprintf(outfile, "%s=\"%s\"\n", opt, arg); + } else { + fprintf(outfile, "%s\n", opt); + } +} + +static void +write_multiple_into_file(FILE *outfile, int len, const char *opt, char **arg, const char *values[]) +{ + int i; + + for (i = 0; i < len; ++i) + write_into_file(outfile, opt, (arg ? arg[i] : 0), values); +} + +int +cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) +{ + int i = 0; + + if (!outfile) + { + fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); + return EXIT_FAILURE; + } + + if (args_info->help_given) + write_into_file(outfile, "help", 0, 0 ); + if (args_info->version_given) + write_into_file(outfile, "version", 0, 0 ); + if (args_info->reader_given) + write_into_file(outfile, "reader", args_info->reader_orig, 0); + write_multiple_into_file(outfile, args_info->verbose_given, "verbose", 0, 0); + if (args_info->pd_given) + write_into_file(outfile, "pd", 0, 0 ); + if (args_info->vd_given) + write_into_file(outfile, "vd", 0, 0 ); + if (args_info->gvd_given) + write_into_file(outfile, "gvd", 0, 0 ); + if (args_info->vsd_status_given) + write_into_file(outfile, "vsd-status", 0, 0 ); + + + i = EXIT_SUCCESS; + return i; +} + +int +cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +{ + FILE *outfile; + int i = 0; + + outfile = fopen(filename, "w"); + + if (!outfile) + { + fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } + + i = cmdline_parser_dump(outfile, args_info); + fclose (outfile); + + return i; +} + +void +cmdline_parser_free (struct gengetopt_args_info *args_info) +{ + cmdline_parser_release (args_info); +} + +/** @brief replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = 0; + if (!s) + return result; + + result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +static int +check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc); + +int +check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc) +{ + int error_occurred = 0; + + if (option_given && (min > 0 || max > 0)) + { + if (min > 0 && max > 0) + { + if (min == max) + { + /* specific occurrences */ + if (option_given != (unsigned int) min) + { + fprintf (stderr, "%s: %s option occurrences must be %d\n", + prog_name, option_desc, min); + error_occurred = 1; + } + } + else if (option_given < (unsigned int) min + || option_given > (unsigned int) max) + { + /* range occurrences */ + fprintf (stderr, "%s: %s option occurrences must be between %d and %d\n", + prog_name, option_desc, min, max); + error_occurred = 1; + } + } + else if (min > 0) + { + /* at least check */ + if (option_given < min) + { + fprintf (stderr, "%s: %s option occurrences must be at least %d\n", + prog_name, option_desc, min); + error_occurred = 1; + } + } + else if (max > 0) + { + /* at most check */ + if (option_given > max) + { + fprintf (stderr, "%s: %s option occurrences must be at most %d\n", + prog_name, option_desc, max); + error_occurred = 1; + } + } + } + + return error_occurred; +} +int +cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) +{ + return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); +} + +int +cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params) +{ + int result; + result = cmdline_parser_internal (argc, argv, args_info, params, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +{ + int result; + struct cmdline_parser_params params; + + params.override = override; + params.initialize = initialize; + params.check_required = check_required; + params.check_ambiguity = 0; + params.print_errors = 1; + + result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +{ + int result = EXIT_SUCCESS; + + if (cmdline_parser_required2(args_info, prog_name, 0) > 0) + result = EXIT_FAILURE; + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) +{ + int error_occurred = 0; + FIX_UNUSED (additional_error); + + /* checks for required options */ + if (check_multiple_option_occurrences(prog_name, args_info->verbose_given, args_info->verbose_min, args_info->verbose_max, "'--verbose' ('-v')")) + error_occurred = 1; + + + /* checks for dependences among options */ + + return error_occurred; +} + +/* + * Extracted from the glibc source tree, version 2.3.6 + * + * Licensed under the GPL as per the whole glibc source tree. + * + * This file was modified so that getopt_long can be called + * many times without risking previous memory to be spoiled. + * + * Modified by Andre Noll and Lorenzo Bettini for use in + * GNU gengetopt generated files. + * + */ + +/* + * we must include anything we need since this file is not thought to be + * inserted in a file already using getopt.h + * + * Lorenzo + */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. +*/ +/* + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `custom_optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +/* Names for the values of the `has_arg' field of `struct option'. */ +#ifndef no_argument +#define no_argument 0 +#endif + +#ifndef required_argument +#define required_argument 1 +#endif + +#ifndef optional_argument +#define optional_argument 2 +#endif + +struct custom_getopt_data { + /* + * These have exactly the same meaning as the corresponding global variables, + * except that they are used for the reentrant versions of getopt. + */ + int custom_optind; + int custom_opterr; + int custom_optopt; + char *custom_optarg; + + /* True if the internal members have been initialized. */ + int initialized; + + /* + * The next char to be scanned in the option-element in which the last option + * character we returned was found. This allows us to pick up the scan where + * we left off. If this is zero, or a null string, it means resume the scan by + * advancing to the next ARGV-element. + */ + char *nextchar; + + /* + * Describe the part of ARGV that contains non-options that have been skipped. + * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is + * the index after the last of them. + */ + int first_nonopt; + int last_nonopt; +}; + +/* + * the variables optarg, optind, opterr and optopt are renamed with + * the custom_ prefix so that they don't interfere with getopt ones. + * + * Moreover they're static so they are visible only from within the + * file where this very file will be included. + */ + +/* + * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an + * option that takes an argument, the argument value is returned here. + */ +static char *custom_optarg; + +/* + * Index in ARGV of the next element to be scanned. This is used for + * communication to and from the caller and for communication between + * successive calls to `custom_getopt'. + * + * On entry to `custom_getopt', 1 means this is the first call; initialize. + * + * When `custom_getopt' returns -1, this is the index of the first of the non-option + * elements that the caller should itself scan. + * + * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV + * has been scanned so far. + * + * 1003.2 says this must be 1 before any call. + */ +static int custom_optind = 1; + +/* + * Callers store zero here to inhibit the error message for unrecognized + * options. + */ +static int custom_opterr = 1; + +/* + * Set to an option character which was unrecognized. This must be initialized + * on some systems to avoid linking in the system's own getopt implementation. + */ +static int custom_optopt = '?'; + +/* + * Exchange two adjacent subsequences of ARGV. One subsequence is elements + * [first_nonopt,last_nonopt) which contains all the non-options that have been + * skipped so far. The other is elements [last_nonopt,custom_optind), which contains + * all the options processed since those non-options were skipped. + * `first_nonopt' and `last_nonopt' are relocated so that they describe the new + * indices of the non-options in ARGV after they are moved. + */ +static void exchange(char **argv, struct custom_getopt_data *d) +{ + int bottom = d->first_nonopt; + int middle = d->last_nonopt; + int top = d->custom_optind; + char *tem; + + /* + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. It leaves the + * longer segment in the right place overall, but it consists of two + * parts that need to be swapped next. + */ + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = + argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + /* Update records for the slots the non-options now occupy. */ + d->first_nonopt += (d->custom_optind - d->last_nonopt); + d->last_nonopt = d->custom_optind; +} + +/* Initialize the internal data when the first call is made. */ +static void custom_getopt_initialize(struct custom_getopt_data *d) +{ + /* + * Start processing options with ARGV-element 1 (since ARGV-element 0 + * is the program name); the sequence of previously skipped non-option + * ARGV-elements is empty. + */ + d->first_nonopt = d->last_nonopt = d->custom_optind; + d->nextchar = NULL; + d->initialized = 1; +} + +#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') + +/* return: zero: continue, nonzero: return given value to user */ +static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, + struct custom_getopt_data *d) +{ + /* + * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been + * moved back by the user (who may also have changed the arguments). + */ + if (d->last_nonopt > d->custom_optind) + d->last_nonopt = d->custom_optind; + if (d->first_nonopt > d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * If we have just processed some options following some + * non-options, exchange them so that the options come first. + */ + if (d->first_nonopt != d->last_nonopt && + d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->last_nonopt != d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * Skip any additional non-options and extend the range of + * non-options previously skipped. + */ + while (d->custom_optind < argc && NONOPTION_P) + d->custom_optind++; + d->last_nonopt = d->custom_optind; + /* + * The special ARGV-element `--' means premature end of options. Skip + * it like a null option, then exchange with previous non-options as if + * it were an option, then skip everything else like a non-option. + */ + if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { + d->custom_optind++; + if (d->first_nonopt != d->last_nonopt + && d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->first_nonopt == d->last_nonopt) + d->first_nonopt = d->custom_optind; + d->last_nonopt = argc; + d->custom_optind = argc; + } + /* + * If we have done all the ARGV-elements, stop the scan and back over + * any non-options that we skipped and permuted. + */ + if (d->custom_optind == argc) { + /* + * Set the next-arg-index to point at the non-options that we + * previously skipped, so the caller will digest them. + */ + if (d->first_nonopt != d->last_nonopt) + d->custom_optind = d->first_nonopt; + return -1; + } + /* + * If we have come to a non-option and did not permute it, either stop + * the scan or describe it to the caller and pass it by. + */ + if (NONOPTION_P) { + d->custom_optarg = argv[d->custom_optind++]; + return 1; + } + /* + * We have found another option-ARGV-element. Skip the initial + * punctuation. + */ + d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); + return 0; +} + +/* + * Check whether the ARGV-element is a long option. + * + * If there's a long option "fubar" and the ARGV-element is "-fu", consider + * that an abbreviation of the long option, just like "--fu", and not "-f" with + * arg "u". + * + * This distinction seems to be the most useful approach. + * + */ +static int check_long_opt(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + int print_errors, struct custom_getopt_data *d) +{ + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match or abbreviated matches */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { + if ((unsigned int) (nameend - d->nextchar) + == (unsigned int) strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' is ambiguous\n", + argv[0], argv[d->custom_optind]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optind++; + d->custom_optopt = 0; + return '?'; + } + if (pfound) { + option_index = indfound; + d->custom_optind++; + if (*nameend) { + if (pfound->has_arg != no_argument) + d->custom_optarg = nameend + 1; + else { + if (print_errors) { + if (argv[d->custom_optind - 1][1] == '-') { + /* --option */ + fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + } else { + /* +option or -option */ + fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[d->custom_optind - 1][0], pfound->name); + } + + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return '?'; + } + } else if (pfound->has_arg == required_argument) { + if (d->custom_optind < argc) + d->custom_optarg = argv[d->custom_optind++]; + else { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], + argv[d->custom_optind - 1]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->nextchar += strlen(d->nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* + * Can't find it as a long option. If this is not getopt_long_only, or + * the option starts with '--' or is not a valid short option, then + * it's an error. Otherwise interpret it as a short option. + */ + if (print_errors) { + if (argv[d->custom_optind][1] == '-') { + /* --option */ + fprintf(stderr, + "%s: unrecognized option `--%s'\n", + argv[0], d->nextchar); + } else { + /* +option or -option */ + fprintf(stderr, + "%s: unrecognized option `%c%s'\n", + argv[0], argv[d->custom_optind][0], + d->nextchar); + } + } + d->nextchar = (char *) ""; + d->custom_optind++; + d->custom_optopt = 0; + return '?'; +} + +static int check_short_opt(int argc, char *const *argv, const char *optstring, + int print_errors, struct custom_getopt_data *d) +{ + char c = *d->nextchar++; + const char *temp = strchr(optstring, c); + + /* Increment `custom_optind' when we start to process its last character. */ + if (*d->nextchar == '\0') + ++d->custom_optind; + if (!temp || c == ':') { + if (print_errors) + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + + d->custom_optopt = c; + return '?'; + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + d->custom_optind++; + } else + d->custom_optarg = NULL; + d->nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + /* + * If we end this ARGV-element by taking the + * rest as an arg, we must advance to the next + * element now. + */ + d->custom_optind++; + } else if (d->custom_optind == argc) { + if (print_errors) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], c); + } + d->custom_optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* + * We already incremented `custom_optind' once; + * increment it again when taking next ARGV-elt + * as argument. + */ + d->custom_optarg = argv[d->custom_optind++]; + d->nextchar = NULL; + } + } + return c; +} + +/* + * Scan elements of ARGV for option characters given in OPTSTRING. + * + * If an element of ARGV starts with '-', and is not exactly "-" or "--", + * then it is an option element. The characters of this element + * (aside from the initial '-') are option characters. If `getopt' + * is called repeatedly, it returns successively each of the option characters + * from each of the option elements. + * + * If `getopt' finds another option character, it returns that character, + * updating `custom_optind' and `nextchar' so that the next call to `getopt' can + * resume the scan with the following option character or ARGV-element. + * + * If there are no more option characters, `getopt' returns -1. + * Then `custom_optind' is the index in ARGV of the first ARGV-element + * that is not an option. (The ARGV-elements have been permuted + * so that those that are not options now come last.) + * + * OPTSTRING is a string containing the legitimate option characters. + * If an option character is seen that is not listed in OPTSTRING, + * return '?' after printing an error message. If you set `custom_opterr' to + * zero, the error message is suppressed but we still return '?'. + * + * If a char in OPTSTRING is followed by a colon, that means it wants an arg, + * so the following text in the same ARGV-element, or the text of the following + * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that + * wants an optional arg; if there is text in the current ARGV-element, + * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. + * + * If OPTSTRING starts with `-' or `+', it requests different methods of + * handling the non-option ARGV-elements. + * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + * + * Long-named options begin with `--' instead of `-'. + * Their names may be abbreviated as long as the abbreviation is unique + * or is an exact match for some defined option. If they have an + * argument, it follows the option name in the same ARGV-element, separated + * from the option name by a `=', or else the in next ARGV-element. + * When `getopt' finds a long-named option, it returns 0 if that option's + * `flag' field is nonzero, the value of the option's `val' field + * if the `flag' field is zero. + * + * The elements of ARGV aren't really const, because we permute them. + * But we pretend they're const in the prototype to be compatible + * with other systems. + * + * LONGOPTS is a vector of `struct option' terminated by an + * element containing a name which is zero. + * + * LONGIND returns the index in LONGOPT of the long-named option found. + * It is only valid when a long-named option has been found by the most + * recent call. + * + * Return the option character from OPTS just read. Return -1 when there are + * no more options. For unrecognized options, or options missing arguments, + * `custom_optopt' is set to the option letter, and '?' is returned. + * + * The OPTS string is a list of characters which are recognized option letters, + * optionally followed by colons, specifying that that letter takes an + * argument, to be placed in `custom_optarg'. + * + * If a letter in OPTS is followed by two colons, its argument is optional. + * This behavior is specific to the GNU `getopt'. + * + * The argument `--' causes premature termination of argument scanning, + * explicitly telling `getopt' that there are no more options. If OPTS begins + * with `--', then non-option arguments are treated as arguments to the option + * '\0'. This behavior is specific to the GNU `getopt'. + */ + +static int getopt_internal_r(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + struct custom_getopt_data *d) +{ + int ret, print_errors = d->custom_opterr; + + if (optstring[0] == ':') + print_errors = 0; + if (argc < 1) + return -1; + d->custom_optarg = NULL; + + /* + * This is a big difference with GNU getopt, since optind == 0 + * means initialization while here 1 means first call. + */ + if (d->custom_optind == 0 || !d->initialized) { + if (d->custom_optind == 0) + d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ + custom_getopt_initialize(d); + } + if (d->nextchar == NULL || *d->nextchar == '\0') { + ret = shuffle_argv(argc, argv, longopts, d); + if (ret) + return ret; + } + if (longopts && (argv[d->custom_optind][1] == '-' )) + return check_long_opt(argc, argv, optstring, longopts, + longind, print_errors, d); + return check_short_opt(argc, argv, optstring, print_errors, d); +} + +static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind) +{ + int result; + /* Keep a global copy of all internal members of d */ + static struct custom_getopt_data d; + + d.custom_optind = custom_optind; + d.custom_opterr = custom_opterr; + result = getopt_internal_r(argc, argv, optstring, longopts, + longind, &d); + custom_optind = d.custom_optind; + custom_optarg = d.custom_optarg; + custom_optopt = d.custom_optopt; + return result; +} + +static int custom_getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return custom_getopt_internal(argc, argv, options, long_options, + opt_index); +} + + +static char *package_name = 0; + +/** + * @brief updates an option + * @param field the generic pointer to the field to update + * @param orig_field the pointer to the orig field + * @param field_given the pointer to the number of occurrence of this option + * @param prev_given the pointer to the number of occurrence already seen + * @param value the argument for this option (if null no arg was specified) + * @param possible_values the possible values for this option (if specified) + * @param default_value the default value (in case the option only accepts fixed values) + * @param arg_type the type of this option + * @param check_ambiguity @see cmdline_parser_params.check_ambiguity + * @param override @see cmdline_parser_params.override + * @param no_free whether to free a possible previous value + * @param multiple_option whether this is a multiple option + * @param long_opt the corresponding long option + * @param short_opt the corresponding short option (or '-' if none) + * @param additional_error possible further error specification + */ +static +int update_arg(void *field, char **orig_field, + unsigned int *field_given, unsigned int *prev_given, + char *value, const char *possible_values[], + const char *default_value, + cmdline_parser_arg_type arg_type, + int check_ambiguity, int override, + int no_free, int multiple_option, + const char *long_opt, char short_opt, + const char *additional_error) +{ + char *stop_char = 0; + const char *val = value; + int found; + FIX_UNUSED (field); + + stop_char = 0; + found = 0; + + if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) + { + if (short_opt != '-') + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + package_name, long_opt, short_opt, + (additional_error ? additional_error : "")); + else + fprintf (stderr, "%s: `--%s' option given more than once%s\n", + package_name, long_opt, + (additional_error ? additional_error : "")); + return 1; /* failure */ + } + + FIX_UNUSED (default_value); + + if (field_given && *field_given && ! override) + return 0; + if (prev_given) + (*prev_given)++; + if (field_given) + (*field_given)++; + if (possible_values) + val = possible_values[found]; + + switch(arg_type) { + case ARG_FLAG: + *((int *)field) = !*((int *)field); + break; + case ARG_INT: + if (val) *((int *)field) = strtol (val, &stop_char, 0); + break; + default: + break; + }; + + /* check numeric conversion */ + switch(arg_type) { + case ARG_INT: + if (val && !(stop_char && *stop_char == '\0')) { + fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); + return 1; /* failure */ + } + break; + default: + ; + }; + + /* store the original value */ + switch(arg_type) { + case ARG_NO: + case ARG_FLAG: + break; + default: + if (value && orig_field) { + if (no_free) { + *orig_field = value; + } else { + if (*orig_field) + free (*orig_field); /* free previous string */ + *orig_field = gengetopt_strdup (value); + } + } + }; + + return 0; /* OK */ +} + + +int +cmdline_parser_internal ( + int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error) +{ + int c; /* Character of the parsed option. */ + + int error_occurred = 0; + struct gengetopt_args_info local_args_info; + + int override; + int initialize; + int check_required; + int check_ambiguity; + + char *optarg; + int optind; + int opterr; + int optopt; + + package_name = argv[0]; + + override = params->override; + initialize = params->initialize; + check_required = params->check_required; + check_ambiguity = params->check_ambiguity; + + if (initialize) + cmdline_parser_init (args_info); + + cmdline_parser_init (&local_args_info); + + optarg = 0; + optind = 0; + opterr = params->print_errors; + optopt = '?'; + + while (1) + { + int option_index = 0; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "reader", 1, NULL, 'r' }, + { "verbose", 0, NULL, 'v' }, + { "pd", 0, NULL, 0 }, + { "vd", 0, NULL, 0 }, + { "gvd", 0, NULL, 0 }, + { "vsd-status", 0, NULL, 0 }, + { 0, 0, 0, 0 } + }; + + custom_optarg = optarg; + custom_optind = optind; + custom_opterr = opterr; + custom_optopt = optopt; + + c = custom_getopt_long (argc, argv, "hVr:v", long_options, &option_index); + + optarg = custom_optarg; + optind = custom_optind; + opterr = custom_opterr; + optopt = custom_optopt; + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + cmdline_parser_print_version (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'r': /* Number of the PC/SC reader to use (-1 for autodetect). */ + + + if (update_arg( (void *)&(args_info->reader_arg), + &(args_info->reader_orig), &(args_info->reader_given), + &(local_args_info.reader_given), optarg, 0, "-1", ARG_INT, + check_ambiguity, override, 0, 0, + "reader", 'r', + additional_error)) + goto failure; + + break; + case 'v': /* Use (several times) to be more verbose. */ + + local_args_info.verbose_given++; + + break; + + case 0: /* Long option with no short option */ + /* Show 'Persönliche Versicherungsdaten' (XML). */ + if (strcmp (long_options[option_index].name, "pd") == 0) + { + + + if (update_arg((void *)&(args_info->pd_flag), 0, &(args_info->pd_given), + &(local_args_info.pd_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "pd", '-', + additional_error)) + goto failure; + + } + /* Show 'Allgemeine Versicherungsdaten' (XML). */ + else if (strcmp (long_options[option_index].name, "vd") == 0) + { + + + if (update_arg((void *)&(args_info->vd_flag), 0, &(args_info->vd_given), + &(local_args_info.vd_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "vd", '-', + additional_error)) + goto failure; + + } + /* Show 'Geschützte Versicherungsdaten' (XML). */ + else if (strcmp (long_options[option_index].name, "gvd") == 0) + { + + + if (update_arg((void *)&(args_info->gvd_flag), 0, &(args_info->gvd_given), + &(local_args_info.gvd_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "gvd", '-', + additional_error)) + goto failure; + + } + /* Show 'Versichertenstammdaten-Status'. */ + else if (strcmp (long_options[option_index].name, "vsd-status") == 0) + { + + + if (update_arg((void *)&(args_info->vsd_status_flag), 0, &(args_info->vsd_status_given), + &(local_args_info.vsd_status_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "vsd-status", '-', + additional_error)) + goto failure; + + } + + break; + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); + abort (); + } /* switch */ + } /* while */ + + + + args_info->verbose_given += local_args_info.verbose_given; + local_args_info.verbose_given = 0; + + if (check_required) + { + error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); + } + + cmdline_parser_release (&local_args_info); + + if ( error_occurred ) + return (EXIT_FAILURE); + + return 0; + +failure: + + cmdline_parser_release (&local_args_info); + return (EXIT_FAILURE); +} diff -Nru opensc-0.17.0/src/tools/egk-tool-cmdline.h opensc-0.19.0/src/tools/egk-tool-cmdline.h --- opensc-0.17.0/src/tools/egk-tool-cmdline.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/egk-tool-cmdline.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,193 @@ +/** @file egk-tool-cmdline.h + * @brief The header file for the command line option parser + * generated by GNU Gengetopt version 2.22.6 + * http://www.gnu.org/software/gengetopt. + * DO NOT modify this file, since it can be overwritten + * @author GNU Gengetopt by Lorenzo Bettini */ + +#ifndef EGK_TOOL_CMDLINE_H +#define EGK_TOOL_CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* for FILE */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +/** @brief the program name (used for printing errors) */ +#define CMDLINE_PARSER_PACKAGE "egk-tool" +#endif + +#ifndef CMDLINE_PARSER_PACKAGE_NAME +/** @brief the complete program name (used for help and version) */ +#define CMDLINE_PARSER_PACKAGE_NAME "egk-tool" +#endif + +#ifndef CMDLINE_PARSER_VERSION +/** @brief the program version */ +#define CMDLINE_PARSER_VERSION VERSION +#endif + +/** @brief Where the command line options are stored */ +struct gengetopt_args_info +{ + const char *help_help; /**< @brief Print help and exit help description. */ + const char *version_help; /**< @brief Print version and exit help description. */ + int reader_arg; /**< @brief Number of the PC/SC reader to use (-1 for autodetect) (default='-1'). */ + char * reader_orig; /**< @brief Number of the PC/SC reader to use (-1 for autodetect) original value given at command line. */ + const char *reader_help; /**< @brief Number of the PC/SC reader to use (-1 for autodetect) help description. */ + unsigned int verbose_min; /**< @brief Use (several times) to be more verbose's minimum occurreces */ + unsigned int verbose_max; /**< @brief Use (several times) to be more verbose's maximum occurreces */ + const char *verbose_help; /**< @brief Use (several times) to be more verbose help description. */ + int pd_flag; /**< @brief Show 'Persönliche Versicherungsdaten' (XML) (default=off). */ + const char *pd_help; /**< @brief Show 'Persönliche Versicherungsdaten' (XML) help description. */ + int vd_flag; /**< @brief Show 'Allgemeine Versicherungsdaten' (XML) (default=off). */ + const char *vd_help; /**< @brief Show 'Allgemeine Versicherungsdaten' (XML) help description. */ + int gvd_flag; /**< @brief Show 'Geschützte Versicherungsdaten' (XML) (default=off). */ + const char *gvd_help; /**< @brief Show 'Geschützte Versicherungsdaten' (XML) help description. */ + int vsd_status_flag; /**< @brief Show 'Versichertenstammdaten-Status' (default=off). */ + const char *vsd_status_help; /**< @brief Show 'Versichertenstammdaten-Status' help description. */ + + unsigned int help_given ; /**< @brief Whether help was given. */ + unsigned int version_given ; /**< @brief Whether version was given. */ + unsigned int reader_given ; /**< @brief Whether reader was given. */ + unsigned int verbose_given ; /**< @brief Whether verbose was given. */ + unsigned int pd_given ; /**< @brief Whether pd was given. */ + unsigned int vd_given ; /**< @brief Whether vd was given. */ + unsigned int gvd_given ; /**< @brief Whether gvd was given. */ + unsigned int vsd_status_given ; /**< @brief Whether vsd-status was given. */ + +} ; + +/** @brief The additional parameters to pass to parser functions */ +struct cmdline_parser_params +{ + int override; /**< @brief whether to override possibly already present options (default 0) */ + int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ + int check_required; /**< @brief whether to check that all required options were provided (default 1) */ + int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ + int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ +} ; + +/** @brief the purpose string of the program */ +extern const char *gengetopt_args_info_purpose; +/** @brief the usage string of the program */ +extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; +/** @brief all the lines making the help output */ +extern const char *gengetopt_args_info_help[]; + +/** + * The command line parser + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser (int argc, char **argv, + struct gengetopt_args_info *args_info); + +/** + * The command line parser (version with additional parameters - deprecated) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param override whether to override possibly already present options + * @param initialize whether to initialize the option structure my_args_info + * @param check_required whether to check that all required options were provided + * @return 0 if everything went fine, NON 0 if an error took place + * @deprecated use cmdline_parser_ext() instead + */ +int cmdline_parser2 (int argc, char **argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + +/** + * The command line parser (version with additional parameters) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param params additional parameters for the parser + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_ext (int argc, char **argv, + struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params); + +/** + * Save the contents of the option struct into an already open FILE stream. + * @param outfile the stream where to dump options + * @param args_info the option struct to dump + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_dump(FILE *outfile, + struct gengetopt_args_info *args_info); + +/** + * Save the contents of the option struct into a (text) file. + * This file can be read by the config file parser (if generated by gengetopt) + * @param filename the file where to save + * @param args_info the option struct to save + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); + +/** + * Print the help + */ +void cmdline_parser_print_help(void); +/** + * Print the version + */ +void cmdline_parser_print_version(void); + +/** + * Initializes all the fields a cmdline_parser_params structure + * to their default values + * @param params the structure to initialize + */ +void cmdline_parser_params_init(struct cmdline_parser_params *params); + +/** + * Allocates dynamically a cmdline_parser_params structure and initializes + * all its fields to their default values + * @return the created and initialized cmdline_parser_params structure + */ +struct cmdline_parser_params *cmdline_parser_params_create(void); + +/** + * Initializes the passed gengetopt_args_info structure's fields + * (also set default values for options that have a default) + * @param args_info the structure to initialize + */ +void cmdline_parser_init (struct gengetopt_args_info *args_info); +/** + * Deallocates the string fields of the gengetopt_args_info structure + * (but does not deallocate the structure itself) + * @param args_info the structure to deallocate + */ +void cmdline_parser_free (struct gengetopt_args_info *args_info); + +/** + * Checks that all the required options were specified + * @param args_info the structure to check + * @param prog_name the name of the program that will be used to print + * possible errors + * @return + */ +int cmdline_parser_required (struct gengetopt_args_info *args_info, + const char *prog_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* EGK_TOOL_CMDLINE_H */ diff -Nru opensc-0.17.0/src/tools/egk-tool.ggo.in opensc-0.19.0/src/tools/egk-tool.ggo.in --- opensc-0.17.0/src/tools/egk-tool.ggo.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/egk-tool.ggo.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,31 @@ +package "egk-tool" +purpose "@PACKAGE_SUMMARY@" + +option "reader" r + "Number of the PC/SC reader to use (-1 for autodetect)" + int + default="-1" + optional +option "verbose" v + "Use (several times) to be more verbose" + multiple + optional + +section "Health Care Application (HCA)" +option "pd" - + "Show 'Persönliche Versicherungsdaten' (@VDFORMAT@)" + flag off +option "vd" - + "Show 'Allgemeine Versicherungsdaten' (@VDFORMAT@)" + flag off +option "gvd" - + "Show 'Geschützte Versicherungsdaten' (@VDFORMAT@)" + flag off +option "vsd-status" - + "Show 'Versichertenstammdaten-Status'" + flag off + +text " +Report bugs to @PACKAGE_BUGREPORT@ + +Written by Frank Morgner " diff -Nru opensc-0.17.0/src/tools/eidenv.c opensc-0.19.0/src/tools/eidenv.c --- opensc-0.17.0/src/tools/eidenv.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/eidenv.c 2018-09-13 11:47:21.000000000 +0000 @@ -23,6 +23,8 @@ #include #ifndef _WIN32 #include +#else +#include #endif #include #include @@ -156,6 +158,8 @@ /* print the counters */ for (i = 1; i <= 4; i++) { r = sc_read_record(card, i, buff, 128, SC_RECORD_BY_REC_NR); + if (r < 0) + goto out; key_used[i - 1] = 0xffffff - ((unsigned char) buff[0xc] * 65536 + (unsigned char) buff[0xd] * 256 + (unsigned char) buff[0xe]); diff -Nru opensc-0.17.0/src/tools/exe.manifest opensc-0.19.0/src/tools/exe.manifest --- opensc-0.17.0/src/tools/exe.manifest 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/exe.manifest 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + diff -Nru opensc-0.17.0/src/tools/fread_to_eof.h opensc-0.19.0/src/tools/fread_to_eof.h --- opensc-0.17.0/src/tools/fread_to_eof.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/fread_to_eof.h 2018-09-13 11:47:21.000000000 +0000 @@ -20,6 +20,8 @@ #ifndef _FREAD_TO_EOF_H #define _FREAD_TO_EOF_H +#include + int fread_to_eof(const char *file, unsigned char **buf, size_t *buflen); #endif diff -Nru opensc-0.17.0/src/tools/gids-tool.c opensc-0.19.0/src/tools/gids-tool.c --- opensc-0.17.0/src/tools/gids-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/gids-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -88,7 +88,7 @@ "Define serial number", "Unblock the user PIN after an administrator authentication", "Change the administrator key", - "Define the new adminastrator key", + "Define the new administrator key", "Uses reader number [0]", "Wait for a card to be inserted", "Verbose operation. Use several times to enable debug output.", @@ -241,7 +241,7 @@ fprintf(stderr, "reset pin failed with %s\n", sc_strerror(r)); return -1; } - printf("Unblock PIN done successfuly\n"); + printf("Unblock PIN done successfully\n"); // the card should have deauthenticated the admin, but to be sure: sc_logout(card); return 0; @@ -345,7 +345,9 @@ if (datasize > *responselen) { return SC_ERROR_BUFFER_TOO_SMALL; } - memcpy(response, p, datasize); + if (response) { + memcpy(response, p, datasize); + } *responselen = datasize; return SC_SUCCESS; } @@ -466,7 +468,7 @@ return SC_SUCCESS; } -int main(int argc, char * const argv[]) +int main(int argc, char * argv[]) { int err = 0, r, c, long_optind = 0; int action_count = 0; diff -Nru opensc-0.17.0/src/tools/iasecc-tool.c opensc-0.19.0/src/tools/iasecc-tool.c --- opensc-0.17.0/src/tools/iasecc-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/iasecc-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -197,7 +197,7 @@ return 0; } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_list_sdos = 0; diff -Nru opensc-0.17.0/src/tools/Makefile.am opensc-0.19.0/src/tools/Makefile.am --- opensc-0.17.0/src/tools/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,6 +1,13 @@ include $(top_srcdir)/win32/ltrc.inc +if ENABLE_ZLIB +VDFORMAT=XML +else +VDFORMAT=GZIP +endif + do_subst = $(SED) \ + -e 's,[@]bindir[@],$(bindir),g' \ -e 's,[@]CVCDIR[@],$(CVCDIR),g' \ -e 's,[@]PACKAGE[@],$(PACKAGE),g' \ -e 's,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g' \ @@ -9,29 +16,30 @@ -e 's,[@]PACKAGE_URL[@],$(PACKAGE_URL),g' \ -e 's,[@]PACKAGE_SUMMARY[@],$(PACKAGE_SUMMARY),g' \ -e 's,[@]PACKAGE_VERSION[@],"$(PACKAGE_VERSION)",g' \ + -e 's,[@]VDFORMAT[@],$(VDFORMAT),g' \ -e 's,[@]X509DIR[@],$(X509DIR),g' +EGK_TOOL_BUILT_SOURCES = egk-tool-cmdline.h egk-tool-cmdline.c NPA_TOOL_BUILT_SOURCES = npa-tool-cmdline.h npa-tool-cmdline.c +OPENSC_NOTIFY_BUILT_SOURCES = opensc-notify-cmdline.h opensc-notify-cmdline.c +OPENSC_ASN1_BUILT_SOURCES = opensc-asn1-cmdline.h opensc-asn1-cmdline.c -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-tools.rc -EXTRA_DIST = Makefile.mak versioninfo-tools.rc.in npa-tool.ggo.in npa-tool.1 +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-tools.rc $(srcdir)/versioninfo-opensc-notify.rc +EXTRA_DIST = Makefile.mak versioninfo-tools.rc.in versioninfo-opensc-notify.rc.in npa-tool.ggo.in opensc-notify.ggo.in egk-tool.ggo.in opensc-asn1.ggo.in org.opensc.notify.desktop.in exe.manifest noinst_HEADERS = util.h fread_to_eof.h noinst_PROGRAMS = sceac-example -bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \ - pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool +bin_PROGRAMS = opensc-tool opensc-explorer opensc-notify \ + pkcs15-tool pkcs15-crypt pkcs11-tool \ + cardos-tool eidenv openpgp-tool iasecc-tool egk-tool opensc-asn1 if ENABLE_OPENSSL bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool \ westcos-tool sc-hsm-tool dnie-tool gids-tool npa-tool endif -if ENABLE_MAN -dist_man1_MANS = npa-tool.1 -endif - # compile with $(PTHREAD_CFLAGS) to allow debugging with gdb AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS) $(PTHREAD_CFLAGS) -AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CPPFLAGS = -I$(top_srcdir)/src -D'DEFAULT_PKCS11_PROVIDER="$(DEFAULT_PKCS11_PROVIDER)"' LIBS = \ $(top_builddir)/src/libopensc/libopensc.la \ $(top_builddir)/src/common/libscdl.la \ @@ -91,14 +99,56 @@ $(abs_builddir)/npa-tool.ggo: npa-tool.ggo.in $(do_subst) < $(abs_srcdir)/npa-tool.ggo.in > $@ -# We only want npa-tool.1 to be generated when it has explicitly been removed. -npa-tool.1: - $(MAKE) npa-tool$(EXEEXT) - $(HELP2MAN) \ - --output=$@ \ - --no-info \ - --source='$(PACKAGE_STRING)' \ - $(builddir)/npa-tool$(EXEEXT) +opensc_notify_SOURCES = opensc-notify.c $(OPENSC_NOTIFY_BUILT_SOURCES) +opensc_notify_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_NOTIFY_LIBS) +opensc_notify_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_NOTIFY_CFLAGS) +opensc_notify_CFLAGS += -Wno-unused-but-set-variable +if HAVE_UNKNOWN_WARNING_OPTION +opensc_notify_CFLAGS += -Wno-unknown-warning-option +endif + +opensc-notify.c: $(abs_builddir)/opensc-notify.ggo $(OPENSC_NOTIFY_BUILT_SOURCES) + +# We only want *cmdline* to be generated when they have explicitly been removed. +$(OPENSC_NOTIFY_BUILT_SOURCES): + $(MAKE) $(abs_builddir)/opensc-notify.ggo + $(GENGETOPT) --include-getopt --file-name=opensc-notify-cmdline --output-dir=$(builddir) < $(abs_builddir)/opensc-notify.ggo + +$(abs_builddir)/opensc-notify.ggo: opensc-notify.ggo.in + $(do_subst) < $(abs_srcdir)/opensc-notify.ggo.in > $@ + +egk_tool_SOURCES = egk-tool.c $(EGK_TOOL_BUILT_SOURCES) +egk_tool_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_ZLIB_LIBS) +egk_tool_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_ZLIB_CFLAGS) +egk_tool_CFLAGS += -Wno-unused-but-set-variable +if HAVE_UNKNOWN_WARNING_OPTION +egk_tool_CFLAGS += -Wno-unknown-warning-option +endif + +egk-tool.c: $(abs_builddir)/egk-tool.ggo $(EGK_TOOL_BUILT_SOURCES) + +# We only want *cmdline* to be generated when they have explicitly been removed. +$(EGK_TOOL_BUILT_SOURCES): + $(MAKE) $(abs_builddir)/egk-tool.ggo + $(GENGETOPT) --include-getopt --file-name=egk-tool-cmdline --output-dir=$(builddir) < $(abs_builddir)/egk-tool.ggo + +$(abs_builddir)/egk-tool.ggo: egk-tool.ggo.in + $(do_subst) < $(abs_srcdir)/egk-tool.ggo.in > $@ + +opensc_asn1_SOURCES = opensc-asn1.c fread_to_eof.c $(OPENSC_ASN1_BUILT_SOURCES) +opensc_asn1_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_ZLIB_LIBS) +opensc_asn1_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_ZLIB_CFLAGS) +opensc_asn1_CFLAGS += -Wno-unused-but-set-variable -Wno-unknown-warning-option + +opensc-asn1.c: $(abs_builddir)/opensc-asn1.ggo $(OPENSC_ASN1_BUILT_SOURCES) + +# We only want *cmdline* to be generated when they have explicitly been removed. +$(OPENSC_ASN1_BUILT_SOURCES): + $(MAKE) $(abs_builddir)/opensc-asn1.ggo + $(GENGETOPT) --include-getopt --file-name=opensc-asn1-cmdline --output-dir=$(builddir) < $(abs_builddir)/opensc-asn1.ggo --unamed-opts + +$(abs_builddir)/opensc-asn1.ggo: opensc-asn1.ggo.in + $(do_subst) < $(abs_srcdir)/opensc-asn1.ggo.in > $@ if WIN32 opensc_tool_SOURCES += versioninfo-tools.rc @@ -117,7 +167,14 @@ iasecc_tool_SOURCES += versioninfo-tools.rc sc_hsm_tool_SOURCES += versioninfo-tools.rc gids_tool_SOURCES += versioninfo-tools.rc +opensc_notify_SOURCES += versioninfo-opensc-notify.rc endif +applicationsdir = $(datadir)/applications +applications_DATA = org.opensc.notify.desktop + +org.opensc.notify.desktop: org.opensc.notify.desktop.in + $(do_subst) < $(abs_srcdir)/org.opensc.notify.desktop.in > $@ + clean-local: - rm -f $(abs_builddir)/npa-tool.ggo + rm -f $(abs_builddir)/npa-tool.ggo $(abs_builddir)/opensc-notify.ggo $(abs_builddir)/opensc-asn1.ggo $(abs_builddir)/egk-tool.ggo org.opensc.notify.desktop diff -Nru opensc-0.17.0/src/tools/Makefile.mak opensc-0.19.0/src/tools/Makefile.mak --- opensc-0.17.0/src/tools/Makefile.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -6,9 +6,11 @@ TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \ pkcs11-tool.exe cardos-tool.exe eidenv.exe openpgp-tool.exe iasecc-tool.exe \ + opensc-notify.exe egk-tool.exe opensc-asn1.exe \ $(PROGRAMS_OPENSSL) -OBJECTS = util.obj npa-tool-cmdline.obj fread_to_eof.obj versioninfo-tools.res +OBJECTS = util.obj versioninfo-tools.res + LIBS = $(TOPDIR)\src\common\common.lib \ $(TOPDIR)\src\scconf\scconf.lib \ $(TOPDIR)\src\libopensc\opensc.lib \ @@ -20,7 +22,27 @@ $(TARGETS): $(OBJECTS) $(LIBS) +opensc-notify.exe: opensc-notify-cmdline.obj versioninfo-opensc-notify.res $(LIBS) + cl $(COPTS) /c $*.c + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-notify-cmdline.obj versioninfo-opensc-notify.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + +npa-tool.exe: npa-tool-cmdline.obj fread_to_eof.obj $(LIBS) + cl $(COPTS) /c $*.c + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj npa-tool-cmdline.obj fread_to_eof.obj $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + +egk-tool.exe: egk-tool-cmdline.obj $(LIBS) + cl $(COPTS) /c $*.c + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj egk-tool-cmdline.obj $(LIBS) $(ZLIB_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + +opensc-asn1.exe: opensc-asn1-cmdline.obj fread_to_eof.obj $(LIBS) + cl $(COPTS) /c $*.c + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-asn1-cmdline.obj fread_to_eof.obj $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + .c.exe: cl $(COPTS) /c $< - link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib ws2_32.lib - if EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;1 + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 diff -Nru opensc-0.17.0/src/tools/netkey-tool.c opensc-0.19.0/src/tools/netkey-tool.c --- opensc-0.17.0/src/tools/netkey-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/netkey-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -81,7 +81,7 @@ if(f->type!=SC_FILE_TYPE_WORKING_EF || f->ef_structure!=SC_FILE_EF_LINEAR_VARIABLE_TLV || f->prop_attr_len!=5 || f->prop_attr[0]!=0x01 || f->prop_attr[1]!=0x80 ){ - printf("\nInvald PIN-file: Type=%d, EF-Structure=%d, Prop-Len=%lu %02X:%02X:%02X\n", + printf("\nInvalid PIN-file: Type=%d, EF-Structure=%d, Prop-Len=%lu %02X:%02X:%02X\n", f->type, f->ef_structure, (unsigned long) f->prop_attr_len, f->prop_attr[0], f->prop_attr[1], f->prop_attr[2] ); @@ -130,7 +130,7 @@ continue; } if(f->type!=SC_FILE_TYPE_WORKING_EF || f->ef_structure!=SC_FILE_EF_TRANSPARENT){ - printf(", Invald Cert-file: Type=%d, EF-Structure=%d\n", f->type, f->ef_structure); + printf(", Invalid Cert-file: Type=%d, EF-Structure=%d\n", f->type, f->ef_structure); continue; } if((j=sc_read_binary(card,0,buf,f->size,0))<0){ @@ -219,7 +219,7 @@ if(file->type!=SC_FILE_TYPE_WORKING_EF || file->ef_structure!=SC_FILE_EF_TRANSPARENT || file->size!=12 || (len=sc_read_binary(card,0,buf,12,0))!=12 || buf[0]!=0x5A || buf[1]!=0x0A ){ - printf("\nInvald Serial-Number: Type=%d, EF-Structure=%d, Size=%lu\n", + printf("\nInvalid Serial-Number: Type=%d, EF-Structure=%d, Size=%lu\n", file->type, file->ef_structure, (unsigned long) file->size ); return; @@ -488,7 +488,7 @@ fprintf(stderr,"\nstore Certificate into card at position 2 and read it back into file\n"); fprintf(stderr," %s --pin1 123456 cert /tmp/cert1 2\n", argv[0]); fprintf(stderr," %s cert 2 /tmp/cert2\n", argv[0]); - fprintf(stderr,"\nBe carful - this tool may destroy your card\n"); + fprintf(stderr,"\nBe careful - this tool may destroy your card\n"); fprintf(stderr,"\nQuestions? Comments? ==> opensc-user@opensc-project.org\n"); exit(1); } diff -Nru opensc-0.17.0/src/tools/npa-tool.1 opensc-0.19.0/src/tools/npa-tool.1 --- opensc-0.17.0/src/tools/npa-tool.1 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/npa-tool.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4. -.TH NPA-TOOL "1" "July 2016" "OpenSC 0.16.0" "User Commands" -.SH NAME -npa-tool \- manual page for npa-tool 0.16.0 -.SH SYNOPSIS -.B npa-tool -[\fI\,OPTIONS\/\fR]... -.SH DESCRIPTION -npa\-tool 0.16.0 -.TP -\fB\-h\fR, \fB\-\-help\fR -Print help and exit -.TP -\fB\-V\fR, \fB\-\-version\fR -Print version and exit -.TP -\fB\-r\fR, \fB\-\-reader\fR=\fI\,INT\/\fR -Number of the PC/SC reader to use (\fB\-1\fR for -autodetect) (default=`\-1') -.TP -\fB\-v\fR, \fB\-\-verbose\fR -Use (several times) to be more verbose -.SS "Password Authenticated Connection Establishment (PACE):" -.TP -\fB\-p\fR, \fB\-\-pin\fR[=\fI\,STRING\/\fR] -Run PACE with (transport) eID\-PIN -.TP -\fB\-u\fR, \fB\-\-puk\fR[=\fI\,STRING\/\fR] -Run PACE with PUK -.TP -\fB\-c\fR, \fB\-\-can\fR[=\fI\,STRING\/\fR] -Run PACE with CAN -.TP -\fB\-m\fR, \fB\-\-mrz\fR[=\fI\,STRING\/\fR] -Run PACE with MRZ (insert MRZ without newlines) -.TP -\fB\-\-env\fR -Whether to use environment variables PIN, PUK, -CAN, MRZ and NEWPIN. You may want to clean -your environment before enabling this. -(default=off) -.SS "PIN management:" -.TP -\fB\-N\fR, \fB\-\-new\-pin\fR[=\fI\,STRING\/\fR] -Install a new PIN -.TP -\fB\-R\fR, \fB\-\-resume\fR -Resume eID\-PIN (uses CAN to activate last -retry) (default=off) -.TP -\fB\-U\fR, \fB\-\-unblock\fR -Unblock PIN (uses PUK to activate three more -retries) (default=off) -.SS "Terminal Authentication (TA) and Chip Authentication (CA):" -.TP -\fB\-C\fR, \fB\-\-cv\-certificate\fR=\fI\,FILENAME\/\fR Card Verifiable Certificate to create a -certificate chain. Can be used multiple times -(order is important). -.TP -\fB\-\-cert\-desc\fR=\fI\,HEX_STRING\/\fR -Certificate description to show for Terminal -Authentication -.TP -\fB\-\-chat\fR=\fI\,HEX_STRING\/\fR -Card holder authorization template to use -(default is terminal's CHAT). Use -7F4C0E060904007F000703010203530103 to trigger -EAC on the CAT\-C (Komfortleser). -.TP -\fB\-A\fR, \fB\-\-auxiliary\-data\fR=\fI\,HEX_STRING\/\fR -Terminal's auxiliary data (default is -.TP -determined by verification of validity, age -and community ID). -.TP -\fB\-P\fR, \fB\-\-private\-key\fR=\fI\,FILENAME\/\fR -Terminal's private key -.TP -\fB\-\-cvc\-dir\fR=\fI\,DIRECTORY\/\fR -Where to look for the CVCA's certificate -(default=`/home/fm/.local/etc/eac/cvc') -.TP -\fB\-\-x509\-dir\fR=\fI\,DIRECTORY\/\fR -Where to look for the CSCA's certificate -(default=`/home/fm/.local/etc/eac/x509') -.TP -\fB\-\-disable\-ta\-checks\fR -Disable checking the validity period of CV -certifcates (default=off) -.TP -\fB\-\-disable\-ca\-checks\fR -Disable passive authentication (default=off) -.SS "Read and write data groups:" -.TP -\fB\-\-read\-dg1\fR -Read DG 1 (Document Type) (default=off) -.TP -\fB\-\-read\-dg2\fR -Read DG 2 (Issuing State) (default=off) -.TP -\fB\-\-read\-dg3\fR -Read DG 3 (Date of Expiry) (default=off) -.TP -\fB\-\-read\-dg4\fR -Read DG 4 (Given Names) (default=off) -.TP -\fB\-\-read\-dg5\fR -Read DG 5 (Family Names) (default=off) -.TP -\fB\-\-read\-dg6\fR -Read DG 6 (Religious/Artistic Name) -(default=off) -.TP -\fB\-\-read\-dg7\fR -Read DG 7 (Academic Title) (default=off) -.TP -\fB\-\-read\-dg8\fR -Read DG 8 (Date of Birth) (default=off) -.TP -\fB\-\-read\-dg9\fR -Read DG 9 (Place of Birth) (default=off) -.TP -\fB\-\-read\-dg10\fR -Read DG 10 (Nationality) (default=off) -.TP -\fB\-\-read\-dg11\fR -Read DG 11 (Sex) (default=off) -.TP -\fB\-\-read\-dg12\fR -Read DG 12 (Optional Data) (default=off) -.TP -\fB\-\-read\-dg13\fR -Read DG 13 (Birth Name) (default=off) -.TP -\fB\-\-read\-dg14\fR -Read DG 14 (default=off) -.TP -\fB\-\-read\-dg15\fR -Read DG 15 (default=off) -.TP -\fB\-\-read\-dg16\fR -Read DG 16 (default=off) -.TP -\fB\-\-read\-dg17\fR -Read DG 17 (Normal Place of Residence) -(default=off) -.TP -\fB\-\-read\-dg18\fR -Read DG 18 (Community ID) (default=off) -.TP -\fB\-\-read\-dg19\fR -Read DG 19 (Residence Permit I) (default=off) -.TP -\fB\-\-read\-dg20\fR -Read DG 20 (Residence Permit II) -(default=off) -.TP -\fB\-\-read\-dg21\fR -Read DG 21 (Optional Data) (default=off) -.TP -\fB\-\-write\-dg17\fR=\fI\,HEX_STRING\/\fR -Write DG 17 (Normal Place of Residence) -.TP -\fB\-\-write\-dg18\fR=\fI\,HEX_STRING\/\fR -Write DG 18 (Community ID) -.TP -\fB\-\-write\-dg19\fR=\fI\,HEX_STRING\/\fR -Write DG 19 (Residence Permit I) -.TP -\fB\-\-write\-dg20\fR=\fI\,HEX_STRING\/\fR -Write DG 20 (Residence Permit II) -.TP -\fB\-\-write\-dg21\fR=\fI\,HEX_STRING\/\fR -Write DG 21 (Optional Data) -.SS "Verification of validity, age and community ID:" -.TP -\fB\-\-verify\-validity\fR=\fI\,YYYYMMDD\/\fR -Verify chip's validity with a reference date -.TP -\fB\-\-older\-than\fR=\fI\,YYYYMMDD\/\fR -Verify age with a reference date -.TP -\fB\-\-verify\-community\fR=\fI\,HEX_STRING\/\fR -Verify community ID with a reference ID -.SS "Special options, not always useful:" -.TP -\fB\-b\fR, \fB\-\-break\fR -Brute force PIN, CAN or PUK. Use together with -\fB\-p\fR, \fB\-a\fR or \fB\-u\fR (default=off) -.TP -\fB\-t\fR, \fB\-\-translate\fR=\fI\,FILENAME\/\fR -File with APDUs of HEX_STRINGs to send through -the secure channel (default=`stdin') -.TP -\fB\-\-tr\-03110v201\fR -Force compliance to BSI TR\-03110 version 2.01 -(default=off) -.TP -\fB\-\-disable\-all\-checks\fR -Disable all checking of fly\-by\-data -(default=off) -.SH AUTHOR -Written by Frank Morgner -.SH "REPORTING BUGS" -Report bugs to opensc\-devel@lists.sourceforge.net diff -Nru opensc-0.17.0/src/tools/npa-tool.c opensc-0.19.0/src/tools/npa-tool.c --- opensc-0.17.0/src/tools/npa-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/npa-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Frank Morgner + * Copyright (C) 2010-2018 Frank Morgner * * This file is part of OpenSC. * @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -172,7 +173,7 @@ sfid, dg_str, sc_strerror(r)); else { char buf[0x200]; - sc_hex_dump(NULL, 0, *dg, *dg_len, buf, sizeof buf); + sc_hex_dump(*dg, *dg_len, buf, sizeof buf); fprintf(stdout, "Read %s", buf); } } @@ -319,7 +320,7 @@ if (data && data_len) { template->discretionary_data3 = ASN1_OCTET_STRING_new(); if (!template->discretionary_data3 - || !M_ASN1_OCTET_STRING_set( + || !ASN1_OCTET_STRING_set( template->discretionary_data3, data, data_len)) { r = SC_ERROR_INTERNAL; goto err; @@ -359,7 +360,7 @@ sc_context_t *ctx = NULL; sc_card_t *card = NULL; - sc_reader_t *reader; + sc_reader_t *reader = NULL; int r, tr_version = EAC_TR_VERSION_2_02; struct establish_pace_channel_input pace_input; @@ -390,12 +391,13 @@ pin = getenv("PIN"); puk = getenv("PUK"); newpin = getenv("NEWPIN"); + } else { + can = cmdline.can_arg; + mrz = cmdline.mrz_arg; + pin = cmdline.pin_arg; + puk = cmdline.puk_arg; + newpin = cmdline.new_pin_arg; } - can = cmdline.can_arg; - mrz = cmdline.mrz_arg; - pin = cmdline.pin_arg; - puk = cmdline.puk_arg; - newpin = cmdline.new_pin_arg; if (cmdline.chat_given) { pace_input.chat = chat; pace_input.chat_length = sizeof chat; @@ -418,11 +420,11 @@ if (cmdline.tr_03110v201_flag) tr_version = EAC_TR_VERSION_2_01; if (cmdline.disable_all_checks_flag) - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_ALL; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_ALL; if (cmdline.disable_ta_checks_flag) - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_TA; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_TA; if (cmdline.disable_ca_checks_flag) - npa_default_flags |= NPA_FLAG_DISABLE_CHECK_CA; + eac_default_flags |= EAC_FLAG_DISABLE_CHECK_CA; r = initialize(cmdline.reader_arg, cmdline.verbose_given, &ctx, &reader); @@ -441,7 +443,7 @@ if (cmdline.cvc_dir_given) EAC_set_cvc_default_dir(cmdline.cvc_dir_arg); if (cmdline.x509_dir_given) - EAC_set_x509_default_dir(cmdline.cvc_dir_arg); + EAC_set_x509_default_dir(cmdline.x509_dir_arg); if (cmdline.break_flag) { /* The biggest number sprintf could write with "%llu is 18446744073709551615 */ @@ -456,12 +458,12 @@ if (pin) { if (sscanf(pin, "%llu", &secret) != 1) { fprintf(stderr, "%s is not an unsigned long long.\n", - npa_secret_name(pace_input.pin_id)); + eac_secret_name(pace_input.pin_id)); exit(2); } if (strlen(pin) > pace_input.pin_length) { fprintf(stderr, "%s too big, only %u digits allowed.\n", - npa_secret_name(pace_input.pin_id), + eac_secret_name(pace_input.pin_id), (unsigned int) pace_input.pin_length); exit(2); } @@ -473,12 +475,12 @@ if (can) { if (sscanf(can, "%llu", &secret) != 1) { fprintf(stderr, "%s is not an unsigned long long.\n", - npa_secret_name(pace_input.pin_id)); + eac_secret_name(pace_input.pin_id)); exit(2); } if (strlen(can) > pace_input.pin_length) { fprintf(stderr, "%s too big, only %u digits allowed.\n", - npa_secret_name(pace_input.pin_id), + eac_secret_name(pace_input.pin_id), (unsigned int) pace_input.pin_length); exit(2); } @@ -490,12 +492,12 @@ if (puk) { if (sscanf(puk, "%llu", &secret) != 1) { fprintf(stderr, "%s is not an unsigned long long.\n", - npa_secret_name(pace_input.pin_id)); + eac_secret_name(pace_input.pin_id)); exit(2); } if (strlen(puk) > pace_input.pin_length) { fprintf(stderr, "%s too big, only %u digits allowed.\n", - npa_secret_name(pace_input.pin_id), + eac_secret_name(pace_input.pin_id), (unsigned int) pace_input.pin_length); exit(2); } @@ -514,7 +516,7 @@ gettimeofday(&tv, NULL); printf("%u,%06u: Trying %s=%s\n", (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec, - npa_secret_name(pace_input.pin_id), pace_input.pin); + eac_secret_name(pace_input.pin_id), pace_input.pin); r = perform_pace(card, pace_input, &pace_output, tr_version); @@ -525,12 +527,12 @@ if (0 > r) { printf("%u,%06u: Tried breaking %s without success.\n", (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec, - npa_secret_name(pace_input.pin_id)); + eac_secret_name(pace_input.pin_id)); goto err; } else { printf("%u,%06u: Tried breaking %s with success (=%s).\n", (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec, - npa_secret_name(pace_input.pin_id), + eac_secret_name(pace_input.pin_id), pace_input.pin); } } @@ -749,7 +751,7 @@ if (r < 0) goto err; printf("Established PACE channel with %s.\n", - npa_secret_name(pace_input.pin_id)); + eac_secret_name(pace_input.pin_id)); nopace: if (cmdline.cv_certificate_given || cmdline.private_key_given) { diff -Nru opensc-0.17.0/src/tools/npa-tool-cmdline.c opensc-0.19.0/src/tools/npa-tool-cmdline.c --- opensc-0.17.0/src/tools/npa-tool-cmdline.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/npa-tool-cmdline.c 2018-09-13 11:47:21.000000000 +0000 @@ -55,7 +55,7 @@ " -P, --private-key=FILENAME Terminal's private key", " --cvc-dir=DIRECTORY Where to look for the CVCA's certificate\n (default=`/home/fm/.local/etc/eac/cvc')", " --x509-dir=DIRECTORY Where to look for the CSCA's certificate\n (default=`/home/fm/.local/etc/eac/x509')", - " --disable-ta-checks Disable checking the validity period of CV\n certifcates (default=off)", + " --disable-ta-checks Disable checking the validity period of CV\n certificates (default=off)", " --disable-ca-checks Disable passive authentication (default=off)", "\nRead and write data groups:", " --read-dg1 Read DG 1 (Document Type) (default=off)", @@ -93,7 +93,7 @@ " -t, --translate=FILENAME File with APDUs of HEX_STRINGs to send through\n the secure channel (default=`stdin')", " --tr-03110v201 Force compliance to BSI TR-03110 version 2.01\n (default=off)", " --disable-all-checks Disable all checking of fly-by-data\n (default=off)", - "\nReport bugs to opensc-devel@lists.sourceforge.net\n\nWritten by Frank Morgner ", + "\nReport bugs to https://github.com/OpenSC/OpenSC/issues\n\nWritten by Frank Morgner ", 0 }; @@ -2085,7 +2085,7 @@ goto failure; } - /* Disable checking the validity period of CV certifcates. */ + /* Disable checking the validity period of CV certificates. */ else if (strcmp (long_options[option_index].name, "disable-ta-checks") == 0) { diff -Nru opensc-0.17.0/src/tools/npa-tool-cmdline.h opensc-0.19.0/src/tools/npa-tool-cmdline.h --- opensc-0.17.0/src/tools/npa-tool-cmdline.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/npa-tool-cmdline.h 2018-09-13 11:47:21.000000000 +0000 @@ -89,8 +89,8 @@ char * x509_dir_arg; /**< @brief Where to look for the CSCA's certificate (default='/home/fm/.local/etc/eac/x509'). */ char * x509_dir_orig; /**< @brief Where to look for the CSCA's certificate original value given at command line. */ const char *x509_dir_help; /**< @brief Where to look for the CSCA's certificate help description. */ - int disable_ta_checks_flag; /**< @brief Disable checking the validity period of CV certifcates (default=off). */ - const char *disable_ta_checks_help; /**< @brief Disable checking the validity period of CV certifcates help description. */ + int disable_ta_checks_flag; /**< @brief Disable checking the validity period of CV certificates (default=off). */ + const char *disable_ta_checks_help; /**< @brief Disable checking the validity period of CV certificates help description. */ int disable_ca_checks_flag; /**< @brief Disable passive authentication (default=off). */ const char *disable_ca_checks_help; /**< @brief Disable passive authentication help description. */ int read_dg1_flag; /**< @brief Read DG 1 (Document Type) (default=off). */ diff -Nru opensc-0.17.0/src/tools/npa-tool.ggo.in opensc-0.19.0/src/tools/npa-tool.ggo.in --- opensc-0.17.0/src/tools/npa-tool.ggo.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/npa-tool.ggo.in 2018-09-13 11:47:21.000000000 +0000 @@ -89,7 +89,7 @@ default="@X509DIR@" optional option "disable-ta-checks" - - "Disable checking the validity period of CV certifcates" + "Disable checking the validity period of CV certificates" flag off option "disable-ca-checks" - "Disable passive authentication" diff -Nru opensc-0.17.0/src/tools/openpgp-tool.c opensc-0.19.0/src/tools/openpgp-tool.c --- opensc-0.17.0/src/tools/openpgp-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/openpgp-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -88,8 +88,8 @@ static const char *pin = NULL; static int opt_erase = 0; static int opt_delkey = 0; -static int opt_dump_do = 0; -static u8 do_dump_idx; +static size_t opt_dump_do = 0; +static unsigned int do_dump_idx[200]; /* large enough and checked on input */ static const char *app_name = "openpgp-tool"; @@ -131,7 +131,7 @@ "Verify PIN (CHV1, CHV2, CHV3...)", "PIN string", "Delete key (1, 2, 3 or all)", -/* d */ "Dump private data object number (i.e. PRIVATE-DO-)", +/* d */ "Dump private data object number (i.e. DO )", }; static const struct ef_name_map openpgp_data[] = { @@ -247,6 +247,8 @@ static int decode_options(int argc, char **argv) { int c; + char *endptr; + unsigned long val; while ((c = getopt_long(argc, argv,"r:x:CUG:L:EhwvVd:", options, (int *) 0)) != EOF) { switch (c) { @@ -316,10 +318,19 @@ key_id = optarg[0] - '0'; else /* Arg string is 'all' */ key_id = 'a'; + actions++; break; case 'd': - do_dump_idx = optarg[0] - '0'; - opt_dump_do++; + endptr = NULL; + val = strtoul(optarg, &endptr, 16); + if (endptr == NULL || endptr == optarg || *endptr != '\0') { + printf("Unable to parse DO identifier\n"); + return 1; + } + if (opt_dump_do < sizeof(do_dump_idx) / sizeof(*do_dump_idx)) { + do_dump_idx[opt_dump_do] = (unsigned int) (val | 0x100); + opt_dump_do++; + } actions++; break; default: @@ -380,46 +391,54 @@ static int do_dump_do(sc_card_t *card, unsigned int tag) { - int r, tmp; - FILE *fp; + int r; + size_t length; + unsigned char buffer[254]; // Private DO are specified up to 254 bytes - // Private DO are specified up to 254 bytes - unsigned char buffer[254]; memset(buffer, '\0', sizeof(buffer)); + if (tag < 0x101 || tag > 0x104) { + printf("Illegal DO identifier\n"); + return 1; + } + r = sc_get_data(card, tag, buffer, sizeof(buffer)); if (r < 0) { printf("Failed to get data object: %s\n", sc_strerror(r)); - if(SC_ERROR_SECURITY_STATUS_NOT_SATISFIED == r) { + if (SC_ERROR_SECURITY_STATUS_NOT_SATISFIED == r) { printf("Make sure the 'verify' and 'pin' parameters are correct.\n"); } return r; } + length = (size_t) r; /* r is guaranteed to be non-negative */ - if(opt_raw) { - r = 0; - #ifndef _WIN32 + if (opt_raw) { + int tmp; + FILE *fp; + +#ifndef _WIN32 tmp = dup(fileno(stdout)); - #else +#else tmp = _dup(_fileno(stdout)); - #endif +#endif if (tmp < 0) return EXIT_FAILURE; fp = freopen(NULL, "wb", stdout); if (fp) { - r = (int)fwrite(buffer, sizeof(char), sizeof(buffer), fp); + r = (int) fwrite(buffer, sizeof(char), length, fp); } - #ifndef _WIN32 +#ifndef _WIN32 dup2(tmp, fileno(stdout)); - #else +#else _dup2(tmp, _fileno(stdout)); - #endif +#endif clearerr(stdout); close(tmp); - if (sizeof(buffer) != r) + + if (length != (size_t) r) /* fail on write errors */ return EXIT_FAILURE; } else { - util_hex_dump_asc(stdout, buffer, sizeof(buffer), -1); + util_hex_dump_asc(stdout, buffer, length, -1); } return EXIT_SUCCESS; @@ -449,6 +468,10 @@ } sc_format_path("006E007300C5", &path); r = sc_select_file(card, &path, &file); + if (r < 0) { + printf("Failed to retrieve fingerprints. Error %s.\n", sc_strerror(r)); + return 1; + } r = sc_read_binary(card, 0, fingerprints, 60, 0); if (r < 0) { printf("Failed to retrieve fingerprints. Error %s.\n", sc_strerror(r)); @@ -527,7 +550,7 @@ /* Send APDU to card */ r = sc_transmit_apdu(card, &apdu); if (r) { - fprintf(stderr, "Transmiting APDU failed: %s\n", sc_strerror(r)); + fprintf(stderr, "Transmitting APDU failed: %s\n", sc_strerror(r)); return r; } } @@ -568,14 +591,8 @@ int do_erase(sc_card_t *card) { - int r; - /* Check card version */ - if (card->type != SC_CARD_TYPE_OPENPGP_V2) { - printf("Do not erase card which is not OpenPGP v2\n"); - } printf("Erase card\n"); - r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); - return r; + return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); } int main(int argc, char **argv) @@ -615,9 +632,11 @@ } /* check card type */ - if ((card->type != SC_CARD_TYPE_OPENPGP_V1) && - (card->type != SC_CARD_TYPE_OPENPGP_V2) && - (card->type != SC_CARD_TYPE_OPENPGP_GNUK)) { + if ((card->type != SC_CARD_TYPE_OPENPGP_BASE) && + (card->type != SC_CARD_TYPE_OPENPGP_V1) && + (card->type != SC_CARD_TYPE_OPENPGP_V2) && + (card->type != SC_CARD_TYPE_OPENPGP_V3) && + (card->type != SC_CARD_TYPE_OPENPGP_GNUK)) { util_error("not an OpenPGP card"); fprintf(stderr, "Card type %X\n", card->type); exit_status = EXIT_FAILURE; @@ -640,7 +659,11 @@ } if (opt_dump_do) { - exit_status |= do_dump_do(card, 0x0100 + do_dump_idx); + size_t n; + + for (n = 0; n < opt_dump_do; n++) { + exit_status |= do_dump_do(card, do_dump_idx[n]); + } } if (opt_genkey) diff -Nru opensc-0.17.0/src/tools/opensc-asn1.c opensc-0.19.0/src/tools/opensc-asn1.c --- opensc-0.17.0/src/tools/opensc-asn1.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-asn1.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 Frank Morgner + * + * This file is part of OpenSC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "fread_to_eof.h" +#include "libopensc/asn1.h" +#include "opensc-asn1-cmdline.h" +#include + +int +main (int argc, char **argv) +{ + struct gengetopt_args_info cmdline; + unsigned char *buf = NULL; + size_t buflen = 0, i; + + if (cmdline_parser(argc, argv, &cmdline) != 0) + return 1; + + for (i = 0; i < cmdline.inputs_num; i++) { + if (!fread_to_eof(cmdline.inputs[i], &buf, &buflen)) + continue; + + printf("Parsing '%s' (%"SC_FORMAT_LEN_SIZE_T"u byte%s)\n", + cmdline.inputs[i], buflen, buflen == 1 ? "" : "s"); + sc_asn1_print_tags(buf, buflen); + } + + free(buf); + cmdline_parser_free (&cmdline); + + return 0; +} diff -Nru opensc-0.17.0/src/tools/opensc-asn1-cmdline.c opensc-0.19.0/src/tools/opensc-asn1-cmdline.c --- opensc-0.17.0/src/tools/opensc-asn1-cmdline.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-asn1-cmdline.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1007 @@ +/* + File autogenerated by gengetopt version 2.22.6 + generated with the following command: + /usr/bin/gengetopt --include-getopt --file-name=opensc-asn1-cmdline --output-dir=. --unamed-opts + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifndef FIX_UNUSED +#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ +#endif + + +#include "opensc-asn1-cmdline.h" + +const char *gengetopt_args_info_purpose = ""; + +const char *gengetopt_args_info_usage = "Usage: opensc-asn1 [OPTIONS]... [FILES]..."; + +const char *gengetopt_args_info_versiontext = ""; + +const char *gengetopt_args_info_description = "Parse ASN.1 data."; + +const char *gengetopt_args_info_help[] = { + " -h, --help Print help and exit", + " -V, --version Print version and exit", + "\nReport bugs to https://github.com/OpenSC/OpenSC/issues\n\nWritten by Frank Morgner ", + 0 +}; + +typedef enum {ARG_NO +} cmdline_parser_arg_type; + +static +void clear_given (struct gengetopt_args_info *args_info); +static +void clear_args (struct gengetopt_args_info *args_info); + +static int +cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error); + + +static char * +gengetopt_strdup (const char *s); + +static +void clear_given (struct gengetopt_args_info *args_info) +{ + args_info->help_given = 0 ; + args_info->version_given = 0 ; +} + +static +void clear_args (struct gengetopt_args_info *args_info) +{ + FIX_UNUSED (args_info); + +} + +static +void init_args_info(struct gengetopt_args_info *args_info) +{ + + + args_info->help_help = gengetopt_args_info_help[0] ; + args_info->version_help = gengetopt_args_info_help[1] ; + +} + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", + (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), + CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); +} + +static void print_help_common(void) { + cmdline_parser_print_version (); + + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); + + if (strlen(gengetopt_args_info_usage) > 0) + printf("\n%s\n", gengetopt_args_info_usage); + + printf("\n"); + + if (strlen(gengetopt_args_info_description) > 0) + printf("%s\n\n", gengetopt_args_info_description); +} + +void +cmdline_parser_print_help (void) +{ + int i = 0; + print_help_common(); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); +} + +void +cmdline_parser_init (struct gengetopt_args_info *args_info) +{ + clear_given (args_info); + clear_args (args_info); + init_args_info (args_info); + + args_info->inputs = 0; + args_info->inputs_num = 0; +} + +void +cmdline_parser_params_init(struct cmdline_parser_params *params) +{ + if (params) + { + params->override = 0; + params->initialize = 1; + params->check_required = 1; + params->check_ambiguity = 0; + params->print_errors = 1; + } +} + +struct cmdline_parser_params * +cmdline_parser_params_create(void) +{ + struct cmdline_parser_params *params = + (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); + cmdline_parser_params_init(params); + return params; +} + + + +static void +cmdline_parser_release (struct gengetopt_args_info *args_info) +{ + unsigned int i; + + + for (i = 0; i < args_info->inputs_num; ++i) + free (args_info->inputs [i]); + + if (args_info->inputs_num) + free (args_info->inputs); + + clear_given (args_info); +} + + +static void +write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) +{ + FIX_UNUSED (values); + if (arg) { + fprintf(outfile, "%s=\"%s\"\n", opt, arg); + } else { + fprintf(outfile, "%s\n", opt); + } +} + + +int +cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) +{ + int i = 0; + + if (!outfile) + { + fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); + return EXIT_FAILURE; + } + + if (args_info->help_given) + write_into_file(outfile, "help", 0, 0 ); + if (args_info->version_given) + write_into_file(outfile, "version", 0, 0 ); + + + i = EXIT_SUCCESS; + return i; +} + +int +cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +{ + FILE *outfile; + int i = 0; + + outfile = fopen(filename, "w"); + + if (!outfile) + { + fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } + + i = cmdline_parser_dump(outfile, args_info); + fclose (outfile); + + return i; +} + +void +cmdline_parser_free (struct gengetopt_args_info *args_info) +{ + cmdline_parser_release (args_info); +} + +/** @brief replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = 0; + if (!s) + return result; + + result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) +{ + return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); +} + +int +cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params) +{ + int result; + result = cmdline_parser_internal (argc, argv, args_info, params, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +{ + int result; + struct cmdline_parser_params params; + + params.override = override; + params.initialize = initialize; + params.check_required = check_required; + params.check_ambiguity = 0; + params.print_errors = 1; + + result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +{ + FIX_UNUSED (args_info); + FIX_UNUSED (prog_name); + return EXIT_SUCCESS; +} + +/* + * Extracted from the glibc source tree, version 2.3.6 + * + * Licensed under the GPL as per the whole glibc source tree. + * + * This file was modified so that getopt_long can be called + * many times without risking previous memory to be spoiled. + * + * Modified by Andre Noll and Lorenzo Bettini for use in + * GNU gengetopt generated files. + * + */ + +/* + * we must include anything we need since this file is not thought to be + * inserted in a file already using getopt.h + * + * Lorenzo + */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. +*/ +/* + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `custom_optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +/* Names for the values of the `has_arg' field of `struct option'. */ +#ifndef no_argument +#define no_argument 0 +#endif + +#ifndef required_argument +#define required_argument 1 +#endif + +#ifndef optional_argument +#define optional_argument 2 +#endif + +struct custom_getopt_data { + /* + * These have exactly the same meaning as the corresponding global variables, + * except that they are used for the reentrant versions of getopt. + */ + int custom_optind; + int custom_opterr; + int custom_optopt; + char *custom_optarg; + + /* True if the internal members have been initialized. */ + int initialized; + + /* + * The next char to be scanned in the option-element in which the last option + * character we returned was found. This allows us to pick up the scan where + * we left off. If this is zero, or a null string, it means resume the scan by + * advancing to the next ARGV-element. + */ + char *nextchar; + + /* + * Describe the part of ARGV that contains non-options that have been skipped. + * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is + * the index after the last of them. + */ + int first_nonopt; + int last_nonopt; +}; + +/* + * the variables optarg, optind, opterr and optopt are renamed with + * the custom_ prefix so that they don't interfere with getopt ones. + * + * Moreover they're static so they are visible only from within the + * file where this very file will be included. + */ + +/* + * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an + * option that takes an argument, the argument value is returned here. + */ +static char *custom_optarg; + +/* + * Index in ARGV of the next element to be scanned. This is used for + * communication to and from the caller and for communication between + * successive calls to `custom_getopt'. + * + * On entry to `custom_getopt', 1 means this is the first call; initialize. + * + * When `custom_getopt' returns -1, this is the index of the first of the non-option + * elements that the caller should itself scan. + * + * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV + * has been scanned so far. + * + * 1003.2 says this must be 1 before any call. + */ +static int custom_optind = 1; + +/* + * Callers store zero here to inhibit the error message for unrecognized + * options. + */ +static int custom_opterr = 1; + +/* + * Set to an option character which was unrecognized. This must be initialized + * on some systems to avoid linking in the system's own getopt implementation. + */ +static int custom_optopt = '?'; + +/* + * Exchange two adjacent subsequences of ARGV. One subsequence is elements + * [first_nonopt,last_nonopt) which contains all the non-options that have been + * skipped so far. The other is elements [last_nonopt,custom_optind), which contains + * all the options processed since those non-options were skipped. + * `first_nonopt' and `last_nonopt' are relocated so that they describe the new + * indices of the non-options in ARGV after they are moved. + */ +static void exchange(char **argv, struct custom_getopt_data *d) +{ + int bottom = d->first_nonopt; + int middle = d->last_nonopt; + int top = d->custom_optind; + char *tem; + + /* + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. It leaves the + * longer segment in the right place overall, but it consists of two + * parts that need to be swapped next. + */ + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = + argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + /* Update records for the slots the non-options now occupy. */ + d->first_nonopt += (d->custom_optind - d->last_nonopt); + d->last_nonopt = d->custom_optind; +} + +/* Initialize the internal data when the first call is made. */ +static void custom_getopt_initialize(struct custom_getopt_data *d) +{ + /* + * Start processing options with ARGV-element 1 (since ARGV-element 0 + * is the program name); the sequence of previously skipped non-option + * ARGV-elements is empty. + */ + d->first_nonopt = d->last_nonopt = d->custom_optind; + d->nextchar = NULL; + d->initialized = 1; +} + +#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') + +/* return: zero: continue, nonzero: return given value to user */ +static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, + struct custom_getopt_data *d) +{ + /* + * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been + * moved back by the user (who may also have changed the arguments). + */ + if (d->last_nonopt > d->custom_optind) + d->last_nonopt = d->custom_optind; + if (d->first_nonopt > d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * If we have just processed some options following some + * non-options, exchange them so that the options come first. + */ + if (d->first_nonopt != d->last_nonopt && + d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->last_nonopt != d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * Skip any additional non-options and extend the range of + * non-options previously skipped. + */ + while (d->custom_optind < argc && NONOPTION_P) + d->custom_optind++; + d->last_nonopt = d->custom_optind; + /* + * The special ARGV-element `--' means premature end of options. Skip + * it like a null option, then exchange with previous non-options as if + * it were an option, then skip everything else like a non-option. + */ + if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { + d->custom_optind++; + if (d->first_nonopt != d->last_nonopt + && d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->first_nonopt == d->last_nonopt) + d->first_nonopt = d->custom_optind; + d->last_nonopt = argc; + d->custom_optind = argc; + } + /* + * If we have done all the ARGV-elements, stop the scan and back over + * any non-options that we skipped and permuted. + */ + if (d->custom_optind == argc) { + /* + * Set the next-arg-index to point at the non-options that we + * previously skipped, so the caller will digest them. + */ + if (d->first_nonopt != d->last_nonopt) + d->custom_optind = d->first_nonopt; + return -1; + } + /* + * If we have come to a non-option and did not permute it, either stop + * the scan or describe it to the caller and pass it by. + */ + if (NONOPTION_P) { + d->custom_optarg = argv[d->custom_optind++]; + return 1; + } + /* + * We have found another option-ARGV-element. Skip the initial + * punctuation. + */ + d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); + return 0; +} + +/* + * Check whether the ARGV-element is a long option. + * + * If there's a long option "fubar" and the ARGV-element is "-fu", consider + * that an abbreviation of the long option, just like "--fu", and not "-f" with + * arg "u". + * + * This distinction seems to be the most useful approach. + * + */ +static int check_long_opt(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + int print_errors, struct custom_getopt_data *d) +{ + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match or abbreviated matches */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { + if ((unsigned int) (nameend - d->nextchar) + == (unsigned int) strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' is ambiguous\n", + argv[0], argv[d->custom_optind]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optind++; + d->custom_optopt = 0; + return '?'; + } + if (pfound) { + option_index = indfound; + d->custom_optind++; + if (*nameend) { + if (pfound->has_arg != no_argument) + d->custom_optarg = nameend + 1; + else { + if (print_errors) { + if (argv[d->custom_optind - 1][1] == '-') { + /* --option */ + fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + } else { + /* +option or -option */ + fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[d->custom_optind - 1][0], pfound->name); + } + + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return '?'; + } + } else if (pfound->has_arg == required_argument) { + if (d->custom_optind < argc) + d->custom_optarg = argv[d->custom_optind++]; + else { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], + argv[d->custom_optind - 1]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->nextchar += strlen(d->nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* + * Can't find it as a long option. If this is not getopt_long_only, or + * the option starts with '--' or is not a valid short option, then + * it's an error. Otherwise interpret it as a short option. + */ + if (print_errors) { + if (argv[d->custom_optind][1] == '-') { + /* --option */ + fprintf(stderr, + "%s: unrecognized option `--%s'\n", + argv[0], d->nextchar); + } else { + /* +option or -option */ + fprintf(stderr, + "%s: unrecognized option `%c%s'\n", + argv[0], argv[d->custom_optind][0], + d->nextchar); + } + } + d->nextchar = (char *) ""; + d->custom_optind++; + d->custom_optopt = 0; + return '?'; +} + +static int check_short_opt(int argc, char *const *argv, const char *optstring, + int print_errors, struct custom_getopt_data *d) +{ + char c = *d->nextchar++; + const char *temp = strchr(optstring, c); + + /* Increment `custom_optind' when we start to process its last character. */ + if (*d->nextchar == '\0') + ++d->custom_optind; + if (!temp || c == ':') { + if (print_errors) + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + + d->custom_optopt = c; + return '?'; + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + d->custom_optind++; + } else + d->custom_optarg = NULL; + d->nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + /* + * If we end this ARGV-element by taking the + * rest as an arg, we must advance to the next + * element now. + */ + d->custom_optind++; + } else if (d->custom_optind == argc) { + if (print_errors) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], c); + } + d->custom_optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* + * We already incremented `custom_optind' once; + * increment it again when taking next ARGV-elt + * as argument. + */ + d->custom_optarg = argv[d->custom_optind++]; + d->nextchar = NULL; + } + } + return c; +} + +/* + * Scan elements of ARGV for option characters given in OPTSTRING. + * + * If an element of ARGV starts with '-', and is not exactly "-" or "--", + * then it is an option element. The characters of this element + * (aside from the initial '-') are option characters. If `getopt' + * is called repeatedly, it returns successively each of the option characters + * from each of the option elements. + * + * If `getopt' finds another option character, it returns that character, + * updating `custom_optind' and `nextchar' so that the next call to `getopt' can + * resume the scan with the following option character or ARGV-element. + * + * If there are no more option characters, `getopt' returns -1. + * Then `custom_optind' is the index in ARGV of the first ARGV-element + * that is not an option. (The ARGV-elements have been permuted + * so that those that are not options now come last.) + * + * OPTSTRING is a string containing the legitimate option characters. + * If an option character is seen that is not listed in OPTSTRING, + * return '?' after printing an error message. If you set `custom_opterr' to + * zero, the error message is suppressed but we still return '?'. + * + * If a char in OPTSTRING is followed by a colon, that means it wants an arg, + * so the following text in the same ARGV-element, or the text of the following + * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that + * wants an optional arg; if there is text in the current ARGV-element, + * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. + * + * If OPTSTRING starts with `-' or `+', it requests different methods of + * handling the non-option ARGV-elements. + * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + * + * Long-named options begin with `--' instead of `-'. + * Their names may be abbreviated as long as the abbreviation is unique + * or is an exact match for some defined option. If they have an + * argument, it follows the option name in the same ARGV-element, separated + * from the option name by a `=', or else the in next ARGV-element. + * When `getopt' finds a long-named option, it returns 0 if that option's + * `flag' field is nonzero, the value of the option's `val' field + * if the `flag' field is zero. + * + * The elements of ARGV aren't really const, because we permute them. + * But we pretend they're const in the prototype to be compatible + * with other systems. + * + * LONGOPTS is a vector of `struct option' terminated by an + * element containing a name which is zero. + * + * LONGIND returns the index in LONGOPT of the long-named option found. + * It is only valid when a long-named option has been found by the most + * recent call. + * + * Return the option character from OPTS just read. Return -1 when there are + * no more options. For unrecognized options, or options missing arguments, + * `custom_optopt' is set to the option letter, and '?' is returned. + * + * The OPTS string is a list of characters which are recognized option letters, + * optionally followed by colons, specifying that that letter takes an + * argument, to be placed in `custom_optarg'. + * + * If a letter in OPTS is followed by two colons, its argument is optional. + * This behavior is specific to the GNU `getopt'. + * + * The argument `--' causes premature termination of argument scanning, + * explicitly telling `getopt' that there are no more options. If OPTS begins + * with `--', then non-option arguments are treated as arguments to the option + * '\0'. This behavior is specific to the GNU `getopt'. + */ + +static int getopt_internal_r(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + struct custom_getopt_data *d) +{ + int ret, print_errors = d->custom_opterr; + + if (optstring[0] == ':') + print_errors = 0; + if (argc < 1) + return -1; + d->custom_optarg = NULL; + + /* + * This is a big difference with GNU getopt, since optind == 0 + * means initialization while here 1 means first call. + */ + if (d->custom_optind == 0 || !d->initialized) { + if (d->custom_optind == 0) + d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ + custom_getopt_initialize(d); + } + if (d->nextchar == NULL || *d->nextchar == '\0') { + ret = shuffle_argv(argc, argv, longopts, d); + if (ret) + return ret; + } + if (longopts && (argv[d->custom_optind][1] == '-' )) + return check_long_opt(argc, argv, optstring, longopts, + longind, print_errors, d); + return check_short_opt(argc, argv, optstring, print_errors, d); +} + +static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind) +{ + int result; + /* Keep a global copy of all internal members of d */ + static struct custom_getopt_data d; + + d.custom_optind = custom_optind; + d.custom_opterr = custom_opterr; + result = getopt_internal_r(argc, argv, optstring, longopts, + longind, &d); + custom_optind = d.custom_optind; + custom_optarg = d.custom_optarg; + custom_optopt = d.custom_optopt; + return result; +} + +static int custom_getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return custom_getopt_internal(argc, argv, options, long_options, + opt_index); +} + + +static char *package_name = 0; + + + +int +cmdline_parser_internal ( + int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error) +{ + int c; /* Character of the parsed option. */ + + int error_occurred = 0; + struct gengetopt_args_info local_args_info; + + int override; + int initialize; + int check_required; + int check_ambiguity; + + char *optarg; + int optind; + int opterr; + int optopt; + + package_name = argv[0]; + + override = params->override; + initialize = params->initialize; + check_required = params->check_required; + check_ambiguity = params->check_ambiguity; + + if (initialize) + cmdline_parser_init (args_info); + + cmdline_parser_init (&local_args_info); + + optarg = 0; + optind = 0; + opterr = params->print_errors; + optopt = '?'; + + while (1) + { + int option_index = 0; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { 0, 0, 0, 0 } + }; + + custom_optarg = optarg; + custom_optind = optind; + custom_opterr = opterr; + custom_optopt = optopt; + + c = custom_getopt_long (argc, argv, "hV", long_options, &option_index); + + optarg = custom_optarg; + optind = custom_optind; + opterr = custom_opterr; + optopt = custom_optopt; + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + cmdline_parser_print_version (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + + case 0: /* Long option with no short option */ + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); + abort (); + } /* switch */ + } /* while */ + + + + + cmdline_parser_release (&local_args_info); + + if ( error_occurred ) + return (EXIT_FAILURE); + + if (optind < argc) + { + int i = 0 ; + int found_prog_name = 0; + /* whether program name, i.e., argv[0], is in the remaining args + (this may happen with some implementations of getopt, + but surely not with the one included by gengetopt) */ + + + args_info->inputs_num = argc - optind - found_prog_name; + args_info->inputs = + (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; + while (optind < argc) + args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; + } + + return 0; + +failure: + + cmdline_parser_release (&local_args_info); + return (EXIT_FAILURE); +} diff -Nru opensc-0.17.0/src/tools/opensc-asn1-cmdline.h opensc-0.19.0/src/tools/opensc-asn1-cmdline.h --- opensc-0.17.0/src/tools/opensc-asn1-cmdline.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-asn1-cmdline.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,175 @@ +/** @file opensc-asn1-cmdline.h + * @brief The header file for the command line option parser + * generated by GNU Gengetopt version 2.22.6 + * http://www.gnu.org/software/gengetopt. + * DO NOT modify this file, since it can be overwritten + * @author GNU Gengetopt by Lorenzo Bettini */ + +#ifndef OPENSC_ASN1_CMDLINE_H +#define OPENSC_ASN1_CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* for FILE */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +/** @brief the program name (used for printing errors) */ +#define CMDLINE_PARSER_PACKAGE "opensc-asn1" +#endif + +#ifndef CMDLINE_PARSER_PACKAGE_NAME +/** @brief the complete program name (used for help and version) */ +#define CMDLINE_PARSER_PACKAGE_NAME "opensc-asn1" +#endif + +#ifndef CMDLINE_PARSER_VERSION +/** @brief the program version */ +#define CMDLINE_PARSER_VERSION VERSION +#endif + +/** @brief Where the command line options are stored */ +struct gengetopt_args_info +{ + const char *help_help; /**< @brief Print help and exit help description. */ + const char *version_help; /**< @brief Print version and exit help description. */ + + unsigned int help_given ; /**< @brief Whether help was given. */ + unsigned int version_given ; /**< @brief Whether version was given. */ + + char **inputs ; /**< @brief unamed options (options without names) */ + unsigned inputs_num ; /**< @brief unamed options number */ +} ; + +/** @brief The additional parameters to pass to parser functions */ +struct cmdline_parser_params +{ + int override; /**< @brief whether to override possibly already present options (default 0) */ + int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ + int check_required; /**< @brief whether to check that all required options were provided (default 1) */ + int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ + int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ +} ; + +/** @brief the purpose string of the program */ +extern const char *gengetopt_args_info_purpose; +/** @brief the usage string of the program */ +extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; +/** @brief all the lines making the help output */ +extern const char *gengetopt_args_info_help[]; + +/** + * The command line parser + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser (int argc, char **argv, + struct gengetopt_args_info *args_info); + +/** + * The command line parser (version with additional parameters - deprecated) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param override whether to override possibly already present options + * @param initialize whether to initialize the option structure my_args_info + * @param check_required whether to check that all required options were provided + * @return 0 if everything went fine, NON 0 if an error took place + * @deprecated use cmdline_parser_ext() instead + */ +int cmdline_parser2 (int argc, char **argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + +/** + * The command line parser (version with additional parameters) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param params additional parameters for the parser + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_ext (int argc, char **argv, + struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params); + +/** + * Save the contents of the option struct into an already open FILE stream. + * @param outfile the stream where to dump options + * @param args_info the option struct to dump + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_dump(FILE *outfile, + struct gengetopt_args_info *args_info); + +/** + * Save the contents of the option struct into a (text) file. + * This file can be read by the config file parser (if generated by gengetopt) + * @param filename the file where to save + * @param args_info the option struct to save + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); + +/** + * Print the help + */ +void cmdline_parser_print_help(void); +/** + * Print the version + */ +void cmdline_parser_print_version(void); + +/** + * Initializes all the fields a cmdline_parser_params structure + * to their default values + * @param params the structure to initialize + */ +void cmdline_parser_params_init(struct cmdline_parser_params *params); + +/** + * Allocates dynamically a cmdline_parser_params structure and initializes + * all its fields to their default values + * @return the created and initialized cmdline_parser_params structure + */ +struct cmdline_parser_params *cmdline_parser_params_create(void); + +/** + * Initializes the passed gengetopt_args_info structure's fields + * (also set default values for options that have a default) + * @param args_info the structure to initialize + */ +void cmdline_parser_init (struct gengetopt_args_info *args_info); +/** + * Deallocates the string fields of the gengetopt_args_info structure + * (but does not deallocate the structure itself) + * @param args_info the structure to deallocate + */ +void cmdline_parser_free (struct gengetopt_args_info *args_info); + +/** + * Checks that all the required options were specified + * @param args_info the structure to check + * @param prog_name the name of the program that will be used to print + * possible errors + * @return + */ +int cmdline_parser_required (struct gengetopt_args_info *args_info, + const char *prog_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* OPENSC_ASN1_CMDLINE_H */ diff -Nru opensc-0.17.0/src/tools/opensc-asn1.ggo.in opensc-0.19.0/src/tools/opensc-asn1.ggo.in --- opensc-0.17.0/src/tools/opensc-asn1.ggo.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-asn1.ggo.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,8 @@ +package "opensc-asn1" +purpose "@PACKAGE_SUMMARY@" +description "Parse ASN.1 data." + +text " +Report bugs to @PACKAGE_BUGREPORT@ + +Written by Frank Morgner " diff -Nru opensc-0.17.0/src/tools/opensc-explorer.c opensc-0.19.0/src/tools/opensc-explorer.c --- opensc-0.17.0/src/tools/opensc-explorer.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-explorer.c 2018-09-13 11:47:21.000000000 +0000 @@ -262,7 +262,6 @@ { sc_file_free(current_file); if (card) { - sc_unlock(card); sc_disconnect_card(card); } if (ctx) @@ -273,7 +272,10 @@ static void select_current_path_or_die(void) { if (current_path.type || current_path.len) { - int r = sc_select_file(card, ¤t_path, NULL); + int r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, ¤t_path, NULL); + sc_unlock(card); if (r) { printf("unable to select parent DF: %s\n", sc_strerror(r)); die(1); @@ -430,7 +432,7 @@ return 0; while (*pattern != '\0' && *string != '\0') { - /* wildcard matching multple characters */ + /* wildcard matching multiple characters */ if (*pattern == '*') { for (pattern++; *string != '\0' ; string++) if (pattern_match(pattern, string)) @@ -470,7 +472,10 @@ u8 buf[256], *cur = buf; int r, count; - r = sc_list_files(card, buf, sizeof(buf)); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_list_files(card, buf, sizeof(buf)); + sc_unlock(card); if (r < 0) { check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file); return -1; @@ -507,7 +512,10 @@ } } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { printf(" %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r)); } else { @@ -565,7 +573,10 @@ } } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); switch (r) { case SC_SUCCESS: file->id = (fid[0] << 8) | fid[1]; @@ -620,7 +631,10 @@ printf("(%04X)\r", tag); fflush(stdout); - r = sc_get_data(card, tag, rbuf, sizeof rbuf); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_get_data(card, tag, rbuf, sizeof rbuf); + sc_unlock(card); if (r >= 0) { printf(" %04X ", tag); if (tag == 0) @@ -678,7 +692,10 @@ path.len -= 2; } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { printf("unable to go up: %s\n", sc_strerror(r)); return -1; @@ -691,7 +708,10 @@ if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_cd); - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select DF", current_file); return -1; @@ -712,7 +732,7 @@ static int read_and_util_print_binary_file(sc_file_t *file) { unsigned char *buf = NULL; - int r; + int r, ret = -1; size_t size; if (file->size) { @@ -724,18 +744,23 @@ if (!buf) return -1; - r = sc_read_binary(card, 0, buf, size, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_read_binary(card, 0, buf, size, 0); + sc_unlock(card); if (r < 0) { check_ret(r, SC_AC_OP_READ, "read failed", file); - return -1; + goto err; } if ((r == 0) && (card->type == SC_CARD_TYPE_BELPIC_EID)) - return -1; + goto err; util_hex_dump_asc(stdout, buf, r, 0); + ret = 0; +err: free(buf); - return 0; + return ret; } static int read_and_print_record_file(sc_file_t *file, unsigned char sfi) @@ -744,8 +769,11 @@ int rec, r; for (rec = 1; ; rec++) { - r = sc_read_record(card, rec, buf, sizeof(buf), - SC_RECORD_BY_REC_NR | sfi); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_read_record(card, rec, buf, sizeof(buf), + SC_RECORD_BY_REC_NR | sfi); + sc_unlock(card); if (r == SC_ERROR_RECORD_NOT_FOUND) return 0; if (r < 0) { @@ -794,7 +822,10 @@ if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_cat); - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); @@ -839,7 +870,10 @@ if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_info); - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { printf("unable to select file: %s\n", sc_strerror(r)); return -1; @@ -952,7 +986,10 @@ { int r; - r = sc_create_file(card, file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_create_file(card, file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file); return -1; @@ -1035,7 +1072,10 @@ if (path.len != 2) return usage(do_delete); path.type = SC_PATH_TYPE_FILE_ID; - r = sc_delete_file(card, &path); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_delete_file(card, &path); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_DELETE, "DELETE FILE failed", current_file); return -1; @@ -1116,7 +1156,10 @@ data.pin1.data = buf; data.pin1.len = buflen; } - r = sc_pin_cmd(card, &data, &tries_left); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_pin_cmd(card, &data, &tries_left); + sc_unlock(card); if (r) { if (r == SC_ERROR_PIN_CODE_INCORRECT) { @@ -1178,7 +1221,10 @@ data.pin2.data = newpinlen ? newpin : NULL; data.pin2.len = newpinlen; - r = sc_pin_cmd(card, &data, &tries_left); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_pin_cmd(card, &data, &tries_left); + sc_unlock(card); if (r) { if (r == SC_ERROR_PIN_CODE_INCORRECT) { if (tries_left >= 0) @@ -1240,7 +1286,10 @@ data.pin2.data = newpinlen ? newpin : NULL; data.pin2.len = newpinlen; - r = sc_pin_cmd(card, &data, NULL); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_pin_cmd(card, &data, NULL); + sc_unlock(card); if (r) { if (r == SC_ERROR_PIN_CODE_INCORRECT) printf("Incorrect code.\n"); @@ -1275,7 +1324,10 @@ perror(filename); goto err; } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); goto err; @@ -1344,7 +1396,10 @@ return -1; } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); return -1; @@ -1355,7 +1410,10 @@ goto err; } - r = sc_update_binary(card, offs, buf, buflen, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_update_binary(card, offs, buf, buflen, 0); + sc_unlock(card); if (r < 0) { printf("Cannot update %04X; return %i\n", file->id, r); goto err; @@ -1389,7 +1447,10 @@ printf("in: %i; %i; %s\n", rec, offs, argv[3]); - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); return -1; @@ -1416,7 +1477,10 @@ goto err; } - r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR); + sc_unlock(card); if (r<0) { printf("Cannot update record %i; return %i\n", rec, r); goto err; @@ -1455,7 +1519,10 @@ perror(filename); goto err; } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); goto err; @@ -1471,7 +1538,10 @@ } if (r != c) count = c = r; - r = sc_update_binary(card, idx, buf, c, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_update_binary(card, idx, buf, c, 0); + sc_unlock(card); if (r < 0) { check_ret(r, SC_AC_OP_READ, "update failed", file); goto err; @@ -1520,7 +1590,10 @@ if (argc != 0) return usage(do_erase); - r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); + sc_unlock(card); if (r) { printf("Failed to erase card: %s\n", sc_strerror (r)); return -1; @@ -1530,19 +1603,23 @@ static int do_random(int argc, char **argv) { - unsigned char buffer[256]; + unsigned char buffer[SC_MAX_EXT_APDU_BUFFER_SIZE]; int r, count; if (argc != 1) return usage(do_random); count = atoi(argv[0]); - if (count < 0 || count > 256) { - printf("Number must be in range 0..256\n"); + if (count < 0 || (size_t) count > sizeof buffer) { + printf("Number must be in range 0..%"SC_FORMAT_LEN_SIZE_T"u\n", + sizeof buffer); return -1; } - r = sc_get_challenge(card, buffer, count); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_get_challenge(card, buffer, count); + sc_unlock(card); if (r < 0) { printf("Failed to get random bytes: %s\n", sc_strerror(r)); return -1; @@ -1563,7 +1640,10 @@ return usage(do_get_data); tag = strtoul(argv[0], NULL, 16); - r = sc_get_data(card, tag, buffer, sizeof(buffer)); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_get_data(card, tag, buffer, sizeof(buffer)); + sc_unlock(card); if (r < 0) { printf("Failed to get data object: %s\n", sc_strerror(r)); return -1; @@ -1611,7 +1691,10 @@ } /* Call OpenSC to do put data */ - r = sc_put_data(card, tag, buf, buflen); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_put_data(card, tag, buf, buflen); + sc_unlock(card); if (r < 0) { printf("Cannot put data to %04X; return %i\n", tag, r); return -1; @@ -1625,8 +1708,8 @@ static int do_apdu(int argc, char **argv) { sc_apdu_t apdu; - u8 buf[SC_MAX_APDU_BUFFER_SIZE * 2]; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE * 2]; + u8 buf[SC_MAX_EXT_APDU_BUFFER_SIZE * 2]; + u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; size_t len, i; int r; @@ -1655,7 +1738,10 @@ printf("Sending: "); util_hex_dump(stdout, buf, len, " "); printf("\n"); - r = sc_transmit_apdu(card, &apdu); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_transmit_apdu(card, &apdu); + sc_unlock(card); if (r) { fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r)); return 1; @@ -1692,7 +1778,10 @@ puts("Invalid file path"); return -1; } - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); goto err; @@ -1717,7 +1806,10 @@ if (!buf) { goto err; } - r = sc_read_binary(card, 0, buf, len, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_read_binary(card, 0, buf, len, 0); + sc_unlock(card); if (r < 0) { check_ret(r, SC_AC_OP_READ, "read failed", file); goto err; @@ -1867,7 +1959,7 @@ return buf; } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int r, c, long_optind = 0, err = 0; char *line; @@ -1930,7 +2022,7 @@ } } - err = util_connect_card(ctx, &card, opt_reader, opt_wait, 0); + err = util_connect_card_ex(ctx, &card, opt_reader, opt_wait, 0, 0); if (err) goto end; @@ -1949,14 +2041,20 @@ } } else { sc_format_path("3F00", ¤t_path); - r = sc_select_file(card, ¤t_path, ¤t_file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, ¤t_path, ¤t_file); + sc_unlock(card); if (r) { printf("unable to select MF: %s\n", sc_strerror(r)); return 1; } } - r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle); + sc_unlock(card); if (r && r != SC_ERROR_NOT_SUPPORTED) printf("unable to change lifecycle: %s\n", sc_strerror(r)); diff -Nru opensc-0.17.0/src/tools/opensc-notify.c opensc-0.19.0/src/tools/opensc-notify.c --- opensc-0.17.0/src/tools/opensc-notify.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-notify.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2017 Frank Morgner + * + * This file is part of OpenSC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "libopensc/log.h" +#include "ui/notify.h" +#include +#include +#include + +static int run_daemon = 0; +static struct sc_context *ctx = NULL; + +#ifndef _WIN32 +#include + +void Sleep(unsigned int Milliseconds) +{ + struct timespec req, rem; + + if (Milliseconds > 999) { + req.tv_sec = Milliseconds / 1000; /* Must be Non-Negative */ + req.tv_nsec = (Milliseconds - (req.tv_sec * 1000)) * 1000000; /* Must be in range of 0 to 999999999 */ + } else { + req.tv_sec = 0; /* Must be Non-Negative */ + req.tv_nsec = Milliseconds * 1000000; /* Must be in range of 0 to 999999999 */ + } + + nanosleep(&req , &rem); +} +#endif + +void stop_daemon() +{ +#ifdef PCSCLITE_GOOD + sc_cancel(ctx); +#endif + run_daemon = 0; +} + +void notify_daemon() +{ + int r; + const unsigned int event_mask = SC_EVENT_CARD_EVENTS; + unsigned int event; + struct sc_reader *event_reader = NULL; + size_t error_count = 0; + /* timeout adjusted to the maximum response time for WM_CLOSE in case + * canceling doesn't work */ + const int timeout = 20000; + struct sc_atr old_atr; + void *reader_states = NULL; + + r = sc_establish_context(&ctx, "opensc-notify"); + if (r < 0 || !ctx) { + fprintf(stderr, "Failed to create initial context: %s", sc_strerror(r)); + return; + } + + while (run_daemon && error_count < 1000) { + r = sc_wait_for_event(ctx, event_mask, + &event_reader, &event, timeout, &reader_states); + if (r < 0) { + if (r == SC_ERROR_NO_READERS_FOUND) { + /* No readers available, PnP notification not supported */ + Sleep(200); + } else { + error_count++; + } + continue; + } + + error_count = 0; + + if (event & SC_EVENT_CARD_REMOVED) { + sc_notify_id(ctx, &old_atr, NULL, NOTIFY_CARD_REMOVED); + } + if (event & SC_EVENT_CARD_INSERTED) { + if (event_reader) { + /* FIXME `pcsc_wait_for_event` has all the information that's + * requested again with `pcsc_detect_card_presence`, but it + * doesn't use the ATR, for example, to refresh the reader's + * attributes. To get the ATR we need to call + * sc_detect_card_presence. Eventually this should be fixed. */ + sc_detect_card_presence(event_reader); + memcpy(old_atr.value, event_reader->atr.value, + event_reader->atr.len); + old_atr.len = event_reader->atr.len; + } else { + old_atr.len = 0; + } + sc_notify_id(ctx, old_atr.len ? &old_atr : NULL, NULL, + NOTIFY_CARD_INSERTED); + } + } + + if (ctx) { + if (error_count >= 1000) { + sc_log(ctx, "Too many errors; aborting."); + } + /* free `reader_states` */ + sc_wait_for_event(ctx, 0, NULL, NULL, 0, &reader_states); + reader_states = NULL; + sc_release_context(ctx); + ctx = NULL; + } +} + +#ifdef _WIN32 +#include "ui/invisible_window.h" +#include + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_CLOSE || message == WM_QUIT) { + stop_daemon(); + return TRUE; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) +{ + notify_daemon(); + return 0; +} + +/* This application shall be executable without a console. Therefor we're + * creating a windows application that requires `WinMain()` rather than + * `main()` as entry point. As benefit, we can properly handle `WM_CLOSE`. */ +int WINAPI +WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + LPCTSTR lpszClassName = "OPENSC_NOTIFY_CLASS"; + HWND hwnd = create_invisible_window(lpszClassName, WndProc, hInstance); + + sc_notify_init(); + run_daemon = 1; + HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); + + MSG msg; + BOOL bRet = FALSE; + while((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { + if (bRet == -1) { + // handle the error and possibly exit + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (msg.message == WM_COMMAND && LOWORD(msg.wParam) == WMAPP_EXIT) { + break; + } + } + + CloseHandle(hThread); + sc_notify_close(); + + delete_invisible_window(hwnd, lpszClassName, hInstance); + + return 0; +} + +#else + +#ifdef HAVE_SIGACTION +#include + +void sig_handler(int sig) { + stop_daemon(); +} + +void set_sa_handler(void) +{ + struct sigaction new_sig, old_sig; + + /* Register signal handlers */ + new_sig.sa_handler = sig_handler; + sigemptyset(&new_sig.sa_mask); + new_sig.sa_flags = SA_RESTART; + if ((sigaction(SIGINT, &new_sig, &old_sig) < 0) + || (sigaction(SIGTERM, &new_sig, &old_sig) < 0)) { + fprintf(stderr, "Failed to create signal handler: %s", strerror(errno)); + } +} + +#else + +void set_sa_handler(void) +{ +} +#endif + +#include "opensc-notify-cmdline.h" + +int +main (int argc, char **argv) +{ + struct gengetopt_args_info cmdline; + memset(&cmdline, 0, sizeof cmdline); + + sc_notify_init(); + + if (cmdline_parser(argc, argv, &cmdline) != 0) + goto err; + + if (cmdline.customized_mode_counter) { + sc_notify(cmdline.title_arg, cmdline.message_arg); + } + + if (cmdline.standard_mode_counter) { + if (cmdline.notify_card_inserted_flag) { + sc_notify_id(NULL, NULL, NULL, NOTIFY_CARD_INSERTED); + } + if (cmdline.notify_card_removed_flag) { + sc_notify_id(NULL, NULL, NULL, NOTIFY_CARD_REMOVED); + } + if (cmdline.notify_pin_good_flag) { + sc_notify_id(NULL, NULL, NULL, NOTIFY_PIN_GOOD); + } + if (cmdline.notify_pin_bad_flag) { + sc_notify_id(NULL, NULL, NULL, NOTIFY_PIN_BAD); + } + } + + if ((!cmdline.customized_mode_counter && !cmdline.standard_mode_counter) + || cmdline.daemon_mode_counter) { + set_sa_handler(); + run_daemon = 1; + notify_daemon(); + } else { + /* give the notification process some time to spawn */ + Sleep(100); + } + +err: + sc_notify_close(); + cmdline_parser_free (&cmdline); + + return 0; +} +#endif diff -Nru opensc-0.17.0/src/tools/opensc-notify-cmdline.c opensc-0.19.0/src/tools/opensc-notify-cmdline.c --- opensc-0.17.0/src/tools/opensc-notify-cmdline.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-notify-cmdline.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,1246 @@ +/* + File autogenerated by gengetopt version 2.22.6 + generated with the following command: + /usr/bin/gengetopt --include-getopt --file-name=opensc-notify-cmdline --output-dir=. + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifndef FIX_UNUSED +#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ +#endif + + +#include "opensc-notify-cmdline.h" + +const char *gengetopt_args_info_purpose = ""; + +const char *gengetopt_args_info_usage = "Usage: opensc-notify [OPTIONS]..."; + +const char *gengetopt_args_info_versiontext = ""; + +const char *gengetopt_args_info_description = "If no arguments are given, monitor smart card events and send the appropriate\nnotification."; + +const char *gengetopt_args_info_help[] = { + " -h, --help Print help and exit", + " -V, --version Print version and exit", + "\n Mode: customized\n Send customized notifications.", + " -t, --title[=STRING] Title of the notification", + " -m, --message[=STRING] Main text of the notification", + "\n Mode: standard\n Manually send standard notifications.", + " -I, --notify-card-inserted See notify_card_inserted in opensc.conf\n (default=off)", + " -R, --notify-card-removed See notify_card_removed in opensc.conf\n (default=off)", + " -G, --notify-pin-good See notify_pin_good in opensc.conf (default=off)", + " -B, --notify-pin-bad See notify_pin_bad in opensc.conf (default=off)", + "\nReport bugs to https://github.com/OpenSC/OpenSC/issues\n\nWritten by Frank Morgner ", + 0 +}; + +typedef enum {ARG_NO + , ARG_FLAG + , ARG_STRING +} cmdline_parser_arg_type; + +static +void clear_given (struct gengetopt_args_info *args_info); +static +void clear_args (struct gengetopt_args_info *args_info); + +static int +cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error); + + +static char * +gengetopt_strdup (const char *s); + +static +void clear_given (struct gengetopt_args_info *args_info) +{ + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->title_given = 0 ; + args_info->message_given = 0 ; + args_info->notify_card_inserted_given = 0 ; + args_info->notify_card_removed_given = 0 ; + args_info->notify_pin_good_given = 0 ; + args_info->notify_pin_bad_given = 0 ; + args_info->customized_mode_counter = 0 ; + args_info->daemon_mode_counter = 0 ; + args_info->standard_mode_counter = 0 ; +} + +static +void clear_args (struct gengetopt_args_info *args_info) +{ + FIX_UNUSED (args_info); + args_info->title_arg = NULL; + args_info->title_orig = NULL; + args_info->message_arg = NULL; + args_info->message_orig = NULL; + args_info->notify_card_inserted_flag = 0; + args_info->notify_card_removed_flag = 0; + args_info->notify_pin_good_flag = 0; + args_info->notify_pin_bad_flag = 0; + +} + +static +void init_args_info(struct gengetopt_args_info *args_info) +{ + + + args_info->help_help = gengetopt_args_info_help[0] ; + args_info->version_help = gengetopt_args_info_help[1] ; + args_info->title_help = gengetopt_args_info_help[3] ; + args_info->message_help = gengetopt_args_info_help[4] ; + args_info->notify_card_inserted_help = gengetopt_args_info_help[6] ; + args_info->notify_card_removed_help = gengetopt_args_info_help[7] ; + args_info->notify_pin_good_help = gengetopt_args_info_help[8] ; + args_info->notify_pin_bad_help = gengetopt_args_info_help[9] ; + +} + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", + (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), + CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); +} + +static void print_help_common(void) { + cmdline_parser_print_version (); + + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); + + if (strlen(gengetopt_args_info_usage) > 0) + printf("\n%s\n", gengetopt_args_info_usage); + + printf("\n"); + + if (strlen(gengetopt_args_info_description) > 0) + printf("%s\n\n", gengetopt_args_info_description); +} + +void +cmdline_parser_print_help (void) +{ + int i = 0; + print_help_common(); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); +} + +void +cmdline_parser_init (struct gengetopt_args_info *args_info) +{ + clear_given (args_info); + clear_args (args_info); + init_args_info (args_info); +} + +void +cmdline_parser_params_init(struct cmdline_parser_params *params) +{ + if (params) + { + params->override = 0; + params->initialize = 1; + params->check_required = 1; + params->check_ambiguity = 0; + params->print_errors = 1; + } +} + +struct cmdline_parser_params * +cmdline_parser_params_create(void) +{ + struct cmdline_parser_params *params = + (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); + cmdline_parser_params_init(params); + return params; +} + +static void +free_string_field (char **s) +{ + if (*s) + { + free (*s); + *s = 0; + } +} + + +static void +cmdline_parser_release (struct gengetopt_args_info *args_info) +{ + + free_string_field (&(args_info->title_arg)); + free_string_field (&(args_info->title_orig)); + free_string_field (&(args_info->message_arg)); + free_string_field (&(args_info->message_orig)); + + + + clear_given (args_info); +} + + +static void +write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) +{ + FIX_UNUSED (values); + if (arg) { + fprintf(outfile, "%s=\"%s\"\n", opt, arg); + } else { + fprintf(outfile, "%s\n", opt); + } +} + + +int +cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) +{ + int i = 0; + + if (!outfile) + { + fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); + return EXIT_FAILURE; + } + + if (args_info->help_given) + write_into_file(outfile, "help", 0, 0 ); + if (args_info->version_given) + write_into_file(outfile, "version", 0, 0 ); + if (args_info->title_given) + write_into_file(outfile, "title", args_info->title_orig, 0); + if (args_info->message_given) + write_into_file(outfile, "message", args_info->message_orig, 0); + if (args_info->notify_card_inserted_given) + write_into_file(outfile, "notify-card-inserted", 0, 0 ); + if (args_info->notify_card_removed_given) + write_into_file(outfile, "notify-card-removed", 0, 0 ); + if (args_info->notify_pin_good_given) + write_into_file(outfile, "notify-pin-good", 0, 0 ); + if (args_info->notify_pin_bad_given) + write_into_file(outfile, "notify-pin-bad", 0, 0 ); + + + i = EXIT_SUCCESS; + return i; +} + +int +cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +{ + FILE *outfile; + int i = 0; + + outfile = fopen(filename, "w"); + + if (!outfile) + { + fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } + + i = cmdline_parser_dump(outfile, args_info); + fclose (outfile); + + return i; +} + +void +cmdline_parser_free (struct gengetopt_args_info *args_info) +{ + cmdline_parser_release (args_info); +} + +/** @brief replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = 0; + if (!s) + return result; + + result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) +{ + return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); +} + +int +cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params) +{ + int result; + result = cmdline_parser_internal (argc, argv, args_info, params, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +{ + int result; + struct cmdline_parser_params params; + + params.override = override; + params.initialize = initialize; + params.check_required = check_required; + params.check_ambiguity = 0; + params.print_errors = 1; + + result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +{ + FIX_UNUSED (args_info); + FIX_UNUSED (prog_name); + return EXIT_SUCCESS; +} + +/* + * Extracted from the glibc source tree, version 2.3.6 + * + * Licensed under the GPL as per the whole glibc source tree. + * + * This file was modified so that getopt_long can be called + * many times without risking previous memory to be spoiled. + * + * Modified by Andre Noll and Lorenzo Bettini for use in + * GNU gengetopt generated files. + * + */ + +/* + * we must include anything we need since this file is not thought to be + * inserted in a file already using getopt.h + * + * Lorenzo + */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. +*/ +/* + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `custom_optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +/* Names for the values of the `has_arg' field of `struct option'. */ +#ifndef no_argument +#define no_argument 0 +#endif + +#ifndef required_argument +#define required_argument 1 +#endif + +#ifndef optional_argument +#define optional_argument 2 +#endif + +struct custom_getopt_data { + /* + * These have exactly the same meaning as the corresponding global variables, + * except that they are used for the reentrant versions of getopt. + */ + int custom_optind; + int custom_opterr; + int custom_optopt; + char *custom_optarg; + + /* True if the internal members have been initialized. */ + int initialized; + + /* + * The next char to be scanned in the option-element in which the last option + * character we returned was found. This allows us to pick up the scan where + * we left off. If this is zero, or a null string, it means resume the scan by + * advancing to the next ARGV-element. + */ + char *nextchar; + + /* + * Describe the part of ARGV that contains non-options that have been skipped. + * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is + * the index after the last of them. + */ + int first_nonopt; + int last_nonopt; +}; + +/* + * the variables optarg, optind, opterr and optopt are renamed with + * the custom_ prefix so that they don't interfere with getopt ones. + * + * Moreover they're static so they are visible only from within the + * file where this very file will be included. + */ + +/* + * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an + * option that takes an argument, the argument value is returned here. + */ +static char *custom_optarg; + +/* + * Index in ARGV of the next element to be scanned. This is used for + * communication to and from the caller and for communication between + * successive calls to `custom_getopt'. + * + * On entry to `custom_getopt', 1 means this is the first call; initialize. + * + * When `custom_getopt' returns -1, this is the index of the first of the non-option + * elements that the caller should itself scan. + * + * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV + * has been scanned so far. + * + * 1003.2 says this must be 1 before any call. + */ +static int custom_optind = 1; + +/* + * Callers store zero here to inhibit the error message for unrecognized + * options. + */ +static int custom_opterr = 1; + +/* + * Set to an option character which was unrecognized. This must be initialized + * on some systems to avoid linking in the system's own getopt implementation. + */ +static int custom_optopt = '?'; + +/* + * Exchange two adjacent subsequences of ARGV. One subsequence is elements + * [first_nonopt,last_nonopt) which contains all the non-options that have been + * skipped so far. The other is elements [last_nonopt,custom_optind), which contains + * all the options processed since those non-options were skipped. + * `first_nonopt' and `last_nonopt' are relocated so that they describe the new + * indices of the non-options in ARGV after they are moved. + */ +static void exchange(char **argv, struct custom_getopt_data *d) +{ + int bottom = d->first_nonopt; + int middle = d->last_nonopt; + int top = d->custom_optind; + char *tem; + + /* + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. It leaves the + * longer segment in the right place overall, but it consists of two + * parts that need to be swapped next. + */ + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = + argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + /* Update records for the slots the non-options now occupy. */ + d->first_nonopt += (d->custom_optind - d->last_nonopt); + d->last_nonopt = d->custom_optind; +} + +/* Initialize the internal data when the first call is made. */ +static void custom_getopt_initialize(struct custom_getopt_data *d) +{ + /* + * Start processing options with ARGV-element 1 (since ARGV-element 0 + * is the program name); the sequence of previously skipped non-option + * ARGV-elements is empty. + */ + d->first_nonopt = d->last_nonopt = d->custom_optind; + d->nextchar = NULL; + d->initialized = 1; +} + +#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') + +/* return: zero: continue, nonzero: return given value to user */ +static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, + struct custom_getopt_data *d) +{ + /* + * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been + * moved back by the user (who may also have changed the arguments). + */ + if (d->last_nonopt > d->custom_optind) + d->last_nonopt = d->custom_optind; + if (d->first_nonopt > d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * If we have just processed some options following some + * non-options, exchange them so that the options come first. + */ + if (d->first_nonopt != d->last_nonopt && + d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->last_nonopt != d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * Skip any additional non-options and extend the range of + * non-options previously skipped. + */ + while (d->custom_optind < argc && NONOPTION_P) + d->custom_optind++; + d->last_nonopt = d->custom_optind; + /* + * The special ARGV-element `--' means premature end of options. Skip + * it like a null option, then exchange with previous non-options as if + * it were an option, then skip everything else like a non-option. + */ + if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { + d->custom_optind++; + if (d->first_nonopt != d->last_nonopt + && d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->first_nonopt == d->last_nonopt) + d->first_nonopt = d->custom_optind; + d->last_nonopt = argc; + d->custom_optind = argc; + } + /* + * If we have done all the ARGV-elements, stop the scan and back over + * any non-options that we skipped and permuted. + */ + if (d->custom_optind == argc) { + /* + * Set the next-arg-index to point at the non-options that we + * previously skipped, so the caller will digest them. + */ + if (d->first_nonopt != d->last_nonopt) + d->custom_optind = d->first_nonopt; + return -1; + } + /* + * If we have come to a non-option and did not permute it, either stop + * the scan or describe it to the caller and pass it by. + */ + if (NONOPTION_P) { + d->custom_optarg = argv[d->custom_optind++]; + return 1; + } + /* + * We have found another option-ARGV-element. Skip the initial + * punctuation. + */ + d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); + return 0; +} + +/* + * Check whether the ARGV-element is a long option. + * + * If there's a long option "fubar" and the ARGV-element is "-fu", consider + * that an abbreviation of the long option, just like "--fu", and not "-f" with + * arg "u". + * + * This distinction seems to be the most useful approach. + * + */ +static int check_long_opt(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + int print_errors, struct custom_getopt_data *d) +{ + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match or abbreviated matches */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { + if ((unsigned int) (nameend - d->nextchar) + == (unsigned int) strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' is ambiguous\n", + argv[0], argv[d->custom_optind]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optind++; + d->custom_optopt = 0; + return '?'; + } + if (pfound) { + option_index = indfound; + d->custom_optind++; + if (*nameend) { + if (pfound->has_arg != no_argument) + d->custom_optarg = nameend + 1; + else { + if (print_errors) { + if (argv[d->custom_optind - 1][1] == '-') { + /* --option */ + fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + } else { + /* +option or -option */ + fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[d->custom_optind - 1][0], pfound->name); + } + + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return '?'; + } + } else if (pfound->has_arg == required_argument) { + if (d->custom_optind < argc) + d->custom_optarg = argv[d->custom_optind++]; + else { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], + argv[d->custom_optind - 1]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->nextchar += strlen(d->nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* + * Can't find it as a long option. If this is not getopt_long_only, or + * the option starts with '--' or is not a valid short option, then + * it's an error. Otherwise interpret it as a short option. + */ + if (print_errors) { + if (argv[d->custom_optind][1] == '-') { + /* --option */ + fprintf(stderr, + "%s: unrecognized option `--%s'\n", + argv[0], d->nextchar); + } else { + /* +option or -option */ + fprintf(stderr, + "%s: unrecognized option `%c%s'\n", + argv[0], argv[d->custom_optind][0], + d->nextchar); + } + } + d->nextchar = (char *) ""; + d->custom_optind++; + d->custom_optopt = 0; + return '?'; +} + +static int check_short_opt(int argc, char *const *argv, const char *optstring, + int print_errors, struct custom_getopt_data *d) +{ + char c = *d->nextchar++; + const char *temp = strchr(optstring, c); + + /* Increment `custom_optind' when we start to process its last character. */ + if (*d->nextchar == '\0') + ++d->custom_optind; + if (!temp || c == ':') { + if (print_errors) + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + + d->custom_optopt = c; + return '?'; + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + d->custom_optind++; + } else + d->custom_optarg = NULL; + d->nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + /* + * If we end this ARGV-element by taking the + * rest as an arg, we must advance to the next + * element now. + */ + d->custom_optind++; + } else if (d->custom_optind == argc) { + if (print_errors) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], c); + } + d->custom_optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* + * We already incremented `custom_optind' once; + * increment it again when taking next ARGV-elt + * as argument. + */ + d->custom_optarg = argv[d->custom_optind++]; + d->nextchar = NULL; + } + } + return c; +} + +/* + * Scan elements of ARGV for option characters given in OPTSTRING. + * + * If an element of ARGV starts with '-', and is not exactly "-" or "--", + * then it is an option element. The characters of this element + * (aside from the initial '-') are option characters. If `getopt' + * is called repeatedly, it returns successively each of the option characters + * from each of the option elements. + * + * If `getopt' finds another option character, it returns that character, + * updating `custom_optind' and `nextchar' so that the next call to `getopt' can + * resume the scan with the following option character or ARGV-element. + * + * If there are no more option characters, `getopt' returns -1. + * Then `custom_optind' is the index in ARGV of the first ARGV-element + * that is not an option. (The ARGV-elements have been permuted + * so that those that are not options now come last.) + * + * OPTSTRING is a string containing the legitimate option characters. + * If an option character is seen that is not listed in OPTSTRING, + * return '?' after printing an error message. If you set `custom_opterr' to + * zero, the error message is suppressed but we still return '?'. + * + * If a char in OPTSTRING is followed by a colon, that means it wants an arg, + * so the following text in the same ARGV-element, or the text of the following + * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that + * wants an optional arg; if there is text in the current ARGV-element, + * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. + * + * If OPTSTRING starts with `-' or `+', it requests different methods of + * handling the non-option ARGV-elements. + * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + * + * Long-named options begin with `--' instead of `-'. + * Their names may be abbreviated as long as the abbreviation is unique + * or is an exact match for some defined option. If they have an + * argument, it follows the option name in the same ARGV-element, separated + * from the option name by a `=', or else the in next ARGV-element. + * When `getopt' finds a long-named option, it returns 0 if that option's + * `flag' field is nonzero, the value of the option's `val' field + * if the `flag' field is zero. + * + * The elements of ARGV aren't really const, because we permute them. + * But we pretend they're const in the prototype to be compatible + * with other systems. + * + * LONGOPTS is a vector of `struct option' terminated by an + * element containing a name which is zero. + * + * LONGIND returns the index in LONGOPT of the long-named option found. + * It is only valid when a long-named option has been found by the most + * recent call. + * + * Return the option character from OPTS just read. Return -1 when there are + * no more options. For unrecognized options, or options missing arguments, + * `custom_optopt' is set to the option letter, and '?' is returned. + * + * The OPTS string is a list of characters which are recognized option letters, + * optionally followed by colons, specifying that that letter takes an + * argument, to be placed in `custom_optarg'. + * + * If a letter in OPTS is followed by two colons, its argument is optional. + * This behavior is specific to the GNU `getopt'. + * + * The argument `--' causes premature termination of argument scanning, + * explicitly telling `getopt' that there are no more options. If OPTS begins + * with `--', then non-option arguments are treated as arguments to the option + * '\0'. This behavior is specific to the GNU `getopt'. + */ + +static int getopt_internal_r(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + struct custom_getopt_data *d) +{ + int ret, print_errors = d->custom_opterr; + + if (optstring[0] == ':') + print_errors = 0; + if (argc < 1) + return -1; + d->custom_optarg = NULL; + + /* + * This is a big difference with GNU getopt, since optind == 0 + * means initialization while here 1 means first call. + */ + if (d->custom_optind == 0 || !d->initialized) { + if (d->custom_optind == 0) + d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ + custom_getopt_initialize(d); + } + if (d->nextchar == NULL || *d->nextchar == '\0') { + ret = shuffle_argv(argc, argv, longopts, d); + if (ret) + return ret; + } + if (longopts && (argv[d->custom_optind][1] == '-' )) + return check_long_opt(argc, argv, optstring, longopts, + longind, print_errors, d); + return check_short_opt(argc, argv, optstring, print_errors, d); +} + +static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind) +{ + int result; + /* Keep a global copy of all internal members of d */ + static struct custom_getopt_data d; + + d.custom_optind = custom_optind; + d.custom_opterr = custom_opterr; + result = getopt_internal_r(argc, argv, optstring, longopts, + longind, &d); + custom_optind = d.custom_optind; + custom_optarg = d.custom_optarg; + custom_optopt = d.custom_optopt; + return result; +} + +static int custom_getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return custom_getopt_internal(argc, argv, options, long_options, + opt_index); +} + + +static char *package_name = 0; + +/** + * @brief updates an option + * @param field the generic pointer to the field to update + * @param orig_field the pointer to the orig field + * @param field_given the pointer to the number of occurrence of this option + * @param prev_given the pointer to the number of occurrence already seen + * @param value the argument for this option (if null no arg was specified) + * @param possible_values the possible values for this option (if specified) + * @param default_value the default value (in case the option only accepts fixed values) + * @param arg_type the type of this option + * @param check_ambiguity @see cmdline_parser_params.check_ambiguity + * @param override @see cmdline_parser_params.override + * @param no_free whether to free a possible previous value + * @param multiple_option whether this is a multiple option + * @param long_opt the corresponding long option + * @param short_opt the corresponding short option (or '-' if none) + * @param additional_error possible further error specification + */ +static +int update_arg(void *field, char **orig_field, + unsigned int *field_given, unsigned int *prev_given, + char *value, const char *possible_values[], + const char *default_value, + cmdline_parser_arg_type arg_type, + int check_ambiguity, int override, + int no_free, int multiple_option, + const char *long_opt, char short_opt, + const char *additional_error) +{ + char *stop_char = 0; + const char *val = value; + int found; + char **string_field; + FIX_UNUSED (field); + + stop_char = 0; + found = 0; + + if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) + { + if (short_opt != '-') + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + package_name, long_opt, short_opt, + (additional_error ? additional_error : "")); + else + fprintf (stderr, "%s: `--%s' option given more than once%s\n", + package_name, long_opt, + (additional_error ? additional_error : "")); + return 1; /* failure */ + } + + FIX_UNUSED (default_value); + + if (field_given && *field_given && ! override) + return 0; + if (prev_given) + (*prev_given)++; + if (field_given) + (*field_given)++; + if (possible_values) + val = possible_values[found]; + + switch(arg_type) { + case ARG_FLAG: + *((int *)field) = !*((int *)field); + break; + case ARG_STRING: + if (val) { + string_field = (char **)field; + if (!no_free && *string_field) + free (*string_field); /* free previous string */ + *string_field = gengetopt_strdup (val); + } + break; + default: + break; + }; + + + /* store the original value */ + switch(arg_type) { + case ARG_NO: + case ARG_FLAG: + break; + default: + if (value && orig_field) { + if (no_free) { + *orig_field = value; + } else { + if (*orig_field) + free (*orig_field); /* free previous string */ + *orig_field = gengetopt_strdup (value); + } + } + }; + + return 0; /* OK */ +} + + +static int check_modes( + int given1[], const char *options1[], + int given2[], const char *options2[]) +{ + int i = 0, j = 0, errors = 0; + + while (given1[i] >= 0) { + if (given1[i]) { + while (given2[j] >= 0) { + if (given2[j]) { + ++errors; + fprintf(stderr, "%s: option %s conflicts with option %s\n", + package_name, options1[i], options2[j]); + } + ++j; + } + } + ++i; + } + + return errors; +} + +int +cmdline_parser_internal ( + int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error) +{ + int c; /* Character of the parsed option. */ + + int error_occurred = 0; + struct gengetopt_args_info local_args_info; + + int override; + int initialize; + int check_required; + int check_ambiguity; + + char *optarg; + int optind; + int opterr; + int optopt; + + package_name = argv[0]; + + override = params->override; + initialize = params->initialize; + check_required = params->check_required; + check_ambiguity = params->check_ambiguity; + + if (initialize) + cmdline_parser_init (args_info); + + cmdline_parser_init (&local_args_info); + + optarg = 0; + optind = 0; + opterr = params->print_errors; + optopt = '?'; + + while (1) + { + int option_index = 0; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "title", 2, NULL, 't' }, + { "message", 2, NULL, 'm' }, + { "notify-card-inserted", 0, NULL, 'I' }, + { "notify-card-removed", 0, NULL, 'R' }, + { "notify-pin-good", 0, NULL, 'G' }, + { "notify-pin-bad", 0, NULL, 'B' }, + { 0, 0, 0, 0 } + }; + + custom_optarg = optarg; + custom_optind = optind; + custom_opterr = opterr; + custom_optopt = optopt; + + c = custom_getopt_long (argc, argv, "hVt::m::IRGB", long_options, &option_index); + + optarg = custom_optarg; + optind = custom_optind; + opterr = custom_opterr; + optopt = custom_optopt; + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + cmdline_parser_print_version (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 't': /* Title of the notification. */ + args_info->customized_mode_counter += 1; + + + if (update_arg( (void *)&(args_info->title_arg), + &(args_info->title_orig), &(args_info->title_given), + &(local_args_info.title_given), optarg, 0, 0, ARG_STRING, + check_ambiguity, override, 0, 0, + "title", 't', + additional_error)) + goto failure; + + break; + case 'm': /* Main text of the notification. */ + args_info->customized_mode_counter += 1; + + + if (update_arg( (void *)&(args_info->message_arg), + &(args_info->message_orig), &(args_info->message_given), + &(local_args_info.message_given), optarg, 0, 0, ARG_STRING, + check_ambiguity, override, 0, 0, + "message", 'm', + additional_error)) + goto failure; + + break; + case 'I': /* See notify_card_inserted in opensc.conf. */ + args_info->standard_mode_counter += 1; + + + if (update_arg((void *)&(args_info->notify_card_inserted_flag), 0, &(args_info->notify_card_inserted_given), + &(local_args_info.notify_card_inserted_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "notify-card-inserted", 'I', + additional_error)) + goto failure; + + break; + case 'R': /* See notify_card_inserted in opensc.conf. */ + args_info->standard_mode_counter += 1; + + + if (update_arg((void *)&(args_info->notify_card_removed_flag), 0, &(args_info->notify_card_removed_given), + &(local_args_info.notify_card_removed_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "notify-card-removed", 'R', + additional_error)) + goto failure; + + break; + case 'G': /* See notify_pin_good in opensc.conf. */ + args_info->standard_mode_counter += 1; + + + if (update_arg((void *)&(args_info->notify_pin_good_flag), 0, &(args_info->notify_pin_good_given), + &(local_args_info.notify_pin_good_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "notify-pin-good", 'G', + additional_error)) + goto failure; + + break; + case 'B': /* See notify_pin_bad in opensc.conf. */ + args_info->standard_mode_counter += 1; + + + if (update_arg((void *)&(args_info->notify_pin_bad_flag), 0, &(args_info->notify_pin_bad_given), + &(local_args_info.notify_pin_bad_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "notify-pin-bad", 'B', + additional_error)) + goto failure; + + break; + + case 0: /* Long option with no short option */ + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); + abort (); + } /* switch */ + } /* while */ + + + + if (args_info->customized_mode_counter && args_info->standard_mode_counter) { + int customized_given[] = {args_info->title_given, args_info->message_given, -1}; + const char *customized_desc[] = {"--title", "--message", 0}; + int standard_given[] = {args_info->notify_card_inserted_given, args_info->notify_card_removed_given, args_info->notify_pin_good_given, args_info->notify_pin_bad_given, -1}; + const char *standard_desc[] = {"--notify-card-inserted", "--notify-card-removed", "--notify-pin-good", "--notify-pin-bad", 0}; + error_occurred += check_modes(customized_given, customized_desc, standard_given, standard_desc); + } + + + cmdline_parser_release (&local_args_info); + + if ( error_occurred ) + return (EXIT_FAILURE); + + return 0; + +failure: + + cmdline_parser_release (&local_args_info); + return (EXIT_FAILURE); +} diff -Nru opensc-0.17.0/src/tools/opensc-notify-cmdline.h opensc-0.19.0/src/tools/opensc-notify-cmdline.h --- opensc-0.17.0/src/tools/opensc-notify-cmdline.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-notify-cmdline.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,196 @@ +/** @file opensc-notify-cmdline.h + * @brief The header file for the command line option parser + * generated by GNU Gengetopt version 2.22.6 + * http://www.gnu.org/software/gengetopt. + * DO NOT modify this file, since it can be overwritten + * @author GNU Gengetopt by Lorenzo Bettini */ + +#ifndef OPENSC_NOTIFY_CMDLINE_H +#define OPENSC_NOTIFY_CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* for FILE */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +/** @brief the program name (used for printing errors) */ +#define CMDLINE_PARSER_PACKAGE "opensc-notify" +#endif + +#ifndef CMDLINE_PARSER_PACKAGE_NAME +/** @brief the complete program name (used for help and version) */ +#define CMDLINE_PARSER_PACKAGE_NAME "opensc-notify" +#endif + +#ifndef CMDLINE_PARSER_VERSION +/** @brief the program version */ +#define CMDLINE_PARSER_VERSION VERSION +#endif + +/** @brief Where the command line options are stored */ +struct gengetopt_args_info +{ + const char *help_help; /**< @brief Print help and exit help description. */ + const char *version_help; /**< @brief Print version and exit help description. */ + char * title_arg; /**< @brief Title of the notification. */ + char * title_orig; /**< @brief Title of the notification original value given at command line. */ + const char *title_help; /**< @brief Title of the notification help description. */ + char * message_arg; /**< @brief Main text of the notification. */ + char * message_orig; /**< @brief Main text of the notification original value given at command line. */ + const char *message_help; /**< @brief Main text of the notification help description. */ + int notify_card_inserted_flag; /**< @brief See notify_card_inserted in opensc.conf (default=off). */ + const char *notify_card_inserted_help; /**< @brief See notify_card_inserted in opensc.conf help description. */ + int notify_card_removed_flag; /**< @brief See notify_card_inserted in opensc.conf (default=off). */ + const char *notify_card_removed_help; /**< @brief See notify_card_inserted in opensc.conf help description. */ + int notify_pin_good_flag; /**< @brief See notify_pin_good in opensc.conf (default=off). */ + const char *notify_pin_good_help; /**< @brief See notify_pin_good in opensc.conf help description. */ + int notify_pin_bad_flag; /**< @brief See notify_pin_bad in opensc.conf (default=off). */ + const char *notify_pin_bad_help; /**< @brief See notify_pin_bad in opensc.conf help description. */ + + unsigned int help_given ; /**< @brief Whether help was given. */ + unsigned int version_given ; /**< @brief Whether version was given. */ + unsigned int title_given ; /**< @brief Whether title was given. */ + unsigned int message_given ; /**< @brief Whether message was given. */ + unsigned int notify_card_inserted_given ; /**< @brief Whether notify-card-inserted was given. */ + unsigned int notify_card_removed_given ; /**< @brief Whether notify-card-removed was given. */ + unsigned int notify_pin_good_given ; /**< @brief Whether notify-pin-good was given. */ + unsigned int notify_pin_bad_given ; /**< @brief Whether notify-pin-bad was given. */ + + int customized_mode_counter; /**< @brief Counter for mode customized */ + int daemon_mode_counter; /**< @brief Counter for mode daemon */ + int standard_mode_counter; /**< @brief Counter for mode standard */ +} ; + +/** @brief The additional parameters to pass to parser functions */ +struct cmdline_parser_params +{ + int override; /**< @brief whether to override possibly already present options (default 0) */ + int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ + int check_required; /**< @brief whether to check that all required options were provided (default 1) */ + int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ + int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ +} ; + +/** @brief the purpose string of the program */ +extern const char *gengetopt_args_info_purpose; +/** @brief the usage string of the program */ +extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; +/** @brief all the lines making the help output */ +extern const char *gengetopt_args_info_help[]; + +/** + * The command line parser + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser (int argc, char **argv, + struct gengetopt_args_info *args_info); + +/** + * The command line parser (version with additional parameters - deprecated) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param override whether to override possibly already present options + * @param initialize whether to initialize the option structure my_args_info + * @param check_required whether to check that all required options were provided + * @return 0 if everything went fine, NON 0 if an error took place + * @deprecated use cmdline_parser_ext() instead + */ +int cmdline_parser2 (int argc, char **argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + +/** + * The command line parser (version with additional parameters) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param params additional parameters for the parser + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_ext (int argc, char **argv, + struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params); + +/** + * Save the contents of the option struct into an already open FILE stream. + * @param outfile the stream where to dump options + * @param args_info the option struct to dump + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_dump(FILE *outfile, + struct gengetopt_args_info *args_info); + +/** + * Save the contents of the option struct into a (text) file. + * This file can be read by the config file parser (if generated by gengetopt) + * @param filename the file where to save + * @param args_info the option struct to save + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); + +/** + * Print the help + */ +void cmdline_parser_print_help(void); +/** + * Print the version + */ +void cmdline_parser_print_version(void); + +/** + * Initializes all the fields a cmdline_parser_params structure + * to their default values + * @param params the structure to initialize + */ +void cmdline_parser_params_init(struct cmdline_parser_params *params); + +/** + * Allocates dynamically a cmdline_parser_params structure and initializes + * all its fields to their default values + * @return the created and initialized cmdline_parser_params structure + */ +struct cmdline_parser_params *cmdline_parser_params_create(void); + +/** + * Initializes the passed gengetopt_args_info structure's fields + * (also set default values for options that have a default) + * @param args_info the structure to initialize + */ +void cmdline_parser_init (struct gengetopt_args_info *args_info); +/** + * Deallocates the string fields of the gengetopt_args_info structure + * (but does not deallocate the structure itself) + * @param args_info the structure to deallocate + */ +void cmdline_parser_free (struct gengetopt_args_info *args_info); + +/** + * Checks that all the required options were specified + * @param args_info the structure to check + * @param prog_name the name of the program that will be used to print + * possible errors + * @return + */ +int cmdline_parser_required (struct gengetopt_args_info *args_info, + const char *prog_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* OPENSC_NOTIFY_CMDLINE_H */ diff -Nru opensc-0.17.0/src/tools/opensc-notify.ggo.in opensc-0.19.0/src/tools/opensc-notify.ggo.in --- opensc-0.17.0/src/tools/opensc-notify.ggo.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-notify.ggo.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,45 @@ +package "opensc-notify" +purpose "@PACKAGE_SUMMARY@" +description "If no arguments are given, monitor smart card events and send the appropriate notification." + +defmode "daemon" + modedesc="Monitor smart card events to send notifications." +defmode "standard" + modedesc="Manually send standard notifications." +defmode "customized" + modedesc="Send customized notifications." + +modeoption "title" t + "Title of the notification" + string + mode="customized" + argoptional + optional +modeoption "message" m + "Main text of the notification" + string + mode="customized" + argoptional + optional + +modeoption "notify-card-inserted" I + "See notify_card_inserted in opensc.conf" + flag off + mode="standard" +modeoption "notify-card-removed" R + "See notify_card_removed in opensc.conf" + flag off + mode="standard" +modeoption "notify-pin-good" G + "See notify_pin_good in opensc.conf" + flag off + mode="standard" +modeoption "notify-pin-bad" B + "See notify_pin_bad in opensc.conf" + flag off + mode="standard" + +text " +Report bugs to @PACKAGE_BUGREPORT@ + +Written by Frank Morgner " diff -Nru opensc-0.17.0/src/tools/opensc-tool.c opensc-0.19.0/src/tools/opensc-tool.c --- opensc-0.17.0/src/tools/opensc-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/opensc-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -429,7 +429,10 @@ return 1; } - r = sc_read_binary(in_card, 0, buf, file->size, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_read_binary(in_card, 0, buf, file->size, 0); + sc_unlock(card); if (r > 0) util_hex_dump_asc(stdout, buf, r, 0); free(buf); @@ -439,7 +442,10 @@ for (i=0; i < file->record_count; i++) { printf("Record %d\n", i); - r = sc_read_record(in_card, i, buf, 256, 0); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_read_record(in_card, i, buf, 256, 0); + sc_unlock(card); if (r > 0) util_hex_dump_asc(stdout, buf, r, 0); } @@ -451,9 +457,12 @@ { sc_file_t *file; int r, file_type; - u8 files[SC_MAX_APDU_BUFFER_SIZE]; + u8 files[SC_MAX_EXT_APDU_BUFFER_SIZE]; - r = sc_select_file(card, &path, &file); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); if (r) { fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r)); return 1; @@ -464,22 +473,26 @@ if (file_type == SC_FILE_TYPE_DF) { int i; - r = sc_list_files(card, files, sizeof(files)); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_list_files(card, files, sizeof(files)); + sc_unlock(card); if (r < 0) { fprintf(stderr, "sc_list_files() failed: %s\n", sc_strerror(r)); return 1; } if (r == 0) { printf("Empty directory\n"); - } else - for (i = 0; i < r/2; i++) { - sc_path_t tmppath; - - memset(&tmppath, 0, sizeof(tmppath)); - memcpy(&tmppath, &path, sizeof(path)); - memcpy(tmppath.value + tmppath.len, files + 2*i, 2); - tmppath.len += 2; - enum_dir(tmppath, depth + 1); + } else { + for (i = 0; i < r/2; i++) { + sc_path_t tmppath; + + memset(&tmppath, 0, sizeof(tmppath)); + memcpy(&tmppath, &path, sizeof(path)); + memcpy(tmppath.value + tmppath.len, files + 2*i, 2); + tmppath.len += 2; + enum_dir(tmppath, depth + 1); + } } } return 0; @@ -498,8 +511,8 @@ static int send_apdu(void) { sc_apdu_t apdu; - u8 buf[SC_MAX_APDU_BUFFER_SIZE], - rbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 buf[SC_MAX_EXT_APDU_BUFFER_SIZE], + rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; size_t len0, r; int c; @@ -520,7 +533,10 @@ for (r = 0; r < len0; r++) printf("%02X ", buf[r]); printf("\n"); - r = sc_transmit_apdu(card, &apdu); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_transmit_apdu(card, &apdu); + sc_unlock(card); if (r) { fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r)); return 1; @@ -538,7 +554,10 @@ int r; sc_serial_number_t serial; - r = sc_card_ctl(in_card, SC_CARDCTL_GET_SERIALNR, &serial); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_card_ctl(in_card, SC_CARDCTL_GET_SERIALNR, &serial); + sc_unlock(card); if (r) fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_GET_SERIALNR, *) failed\n"); else @@ -573,6 +592,7 @@ const id2str_t rsa_flag_names[] = { { SC_ALGORITHM_RSA_PAD_PKCS1, "pkcs1" }, { SC_ALGORITHM_RSA_PAD_ANSI, "ansi" }, + { SC_ALGORITHM_RSA_PAD_PSS, "pss" }, { SC_ALGORITHM_RSA_PAD_ISO9796, "iso9796" }, { SC_ALGORITHM_RSA_HASH_SHA1, "sha1" }, { SC_ALGORITHM_RSA_HASH_MD5, "MD5" }, @@ -658,7 +678,10 @@ cold_reset = !reset_type || strcmp(reset_type, "cold") == 0; - r = sc_reset(card, cold_reset); + r = sc_lock(card); + if (r == SC_SUCCESS) + r = sc_reset(card, cold_reset); + sc_unlock(card); if (r) { fprintf(stderr, "sc_reset(%s) failed: %d\n", cold_reset ? "cold" : "warm", r); @@ -668,7 +691,7 @@ return 0; } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_info = 0; @@ -843,7 +866,7 @@ } } - err = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); + err = util_connect_card_ex(ctx, &card, opt_reader, opt_wait, 0, verbose); if (err) goto end; @@ -895,7 +918,6 @@ } end: if (card) { - sc_unlock(card); sc_disconnect_card(card); } if (ctx) diff -Nru opensc-0.17.0/src/tools/org.opensc.notify.desktop.in opensc-0.19.0/src/tools/org.opensc.notify.desktop.in --- opensc-0.17.0/src/tools/org.opensc.notify.desktop.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/org.opensc.notify.desktop.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=OpenSC Notify +GenericName=Smard card notification +Type=Application +Comment=Monitor smart card events to send notifications. +Exec=@bindir@/opensc-notify +Icon=utilities-system-monitor +Categories=Security;System; +NoDisplay=true diff -Nru opensc-0.17.0/src/tools/piv-tool.c opensc-0.19.0/src/tools/piv-tool.c --- opensc-0.17.0/src/tools/piv-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/piv-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -2,7 +2,7 @@ * piv-tool.c: Tool for accessing smart cards with libopensc * * Copyright (C) 2001 Juha Yrjölä - * Copyright (C) 2005,2010 Douglas E. Engert + * Copyright (C) 2005,2010 Douglas E. Engert * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -194,7 +194,7 @@ cert_file, strerror(errno)); goto err; } - if (compress) { /* file is gziped already */ + if (compress) { /* file is gzipped already */ struct stat stat_buf; if (0 != stat(cert_file, &stat_buf)) { @@ -459,7 +459,7 @@ util_hex_dump_asc(stdout, serial.value, serial.len, -1); } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_send_apdu = 0; diff -Nru opensc-0.17.0/src/tools/pkcs11-tool.c opensc-0.19.0/src/tools/pkcs11-tool.c --- opensc-0.17.0/src/tools/pkcs11-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/pkcs11-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -26,10 +26,11 @@ #include #ifndef _WIN32 -#include #include #include +#include #else +#include #include #endif @@ -108,6 +109,8 @@ {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224}, {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256}, {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320}, + {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384}, + {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512}, {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192}, {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256}, @@ -133,6 +136,7 @@ OPT_KEY_USAGE_DECRYPT, OPT_KEY_USAGE_DERIVE, OPT_PRIVATE, + OPT_SENSITIVE, OPT_TEST_HOTPLUG, OPT_UNLOCK_PIN, OPT_PUK, @@ -145,6 +149,9 @@ OPT_TEST_FORK, OPT_GENERATE_KEY, OPT_GENERATE_RANDOM, + OPT_HASH_ALGORITHM, + OPT_MGF, + OPT_SALT, }; static const struct option options[] = { @@ -161,6 +168,9 @@ { "derive", 0, NULL, OPT_DERIVE }, { "derive-pass-der", 0, NULL, OPT_DERIVE_PASS_DER }, { "mechanism", 1, NULL, 'm' }, + { "hash-algorithm", 1, NULL, OPT_HASH_ALGORITHM }, + { "mgf", 1, NULL, OPT_MGF }, + { "salt-len", 1, NULL, OPT_SALT }, { "login", 0, NULL, 'l' }, { "login-type", 1, NULL, OPT_LOGIN_TYPE }, @@ -203,6 +213,7 @@ { "moz-cert", 1, NULL, 'z' }, { "verbose", 0, NULL, 'v' }, { "private", 0, NULL, OPT_PRIVATE }, + { "sensitive", 0, NULL, OPT_SENSITIVE }, { "test-ec", 0, NULL, OPT_TEST_EC }, #ifndef _WIN32 { "test-fork", 0, NULL, OPT_TEST_FORK }, @@ -225,7 +236,10 @@ "Hash some data", "Derive a secret key using another key and some data", "Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations", - "Specify mechanism (use -M for a list of supported mechanisms)", + "Specify mechanism (use -M for a list of supported mechanisms), or by hexadecimal, e.g., 0x80001234", + "Specify hash algorithm used with RSA-PKCS-PSS signature and RSA-PKCS-OAEP decryption", + "Specify MGF (Message Generation Function) used for RSA-PSS signature and RSA-OAEP decryption (possible values are MGF1-SHA1 to MGF1-SHA512)", + "Specify how many bytes should be used for salt in RSA-PSS signatures (default is digest size)", "Log into the token first", "Specify login type ('so', 'user', 'context-specific'; default:'user')", @@ -268,6 +282,7 @@ "Test Mozilla-like keypair gen and cert req, =certfile", "Verbose operation. (Set OPENSC_DEBUG to enable OpenSC specific debugging)", "Set the CKA_PRIVATE attribute (object is only viewable after a login)", + "Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext)", "Test EC (best used with the --login or --pin option)", #ifndef _WIN32 "Test forking and calling C_Initialize() in the child", @@ -307,6 +322,7 @@ static char * opt_key_type = NULL; static char * opt_sig_format = NULL; static int opt_is_private = 0; +static int opt_is_sensitive = 0; static int opt_test_hotplug = 0; static int opt_login_type = -1; static int opt_key_usage_sign = 0; @@ -315,6 +331,10 @@ static int opt_key_usage_default = 1; /* uses defaults if no opt_key_usage options */ static int opt_derive_pass_der = 0; static unsigned long opt_random_bytes = 0; +static CK_MECHANISM_TYPE opt_hash_alg = 0; +static unsigned long opt_mgf = 0; +static long salt_len = 0; +static int salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */ static void *module = NULL; static CK_FUNCTION_LIST_PTR p11 = NULL; @@ -332,9 +352,9 @@ const char * short_name; }; struct x509cert_info { - unsigned char subject[256]; + unsigned char subject[512]; int subject_len; - unsigned char issuer[256]; + unsigned char issuer[512]; int issuer_len; unsigned char serialnum[128]; int serialnum_len; @@ -405,6 +425,8 @@ static const char * p11_flag_names(struct flag_info *, CK_FLAGS); static const char * p11_mechanism_to_name(CK_MECHANISM_TYPE); static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *); +static const char * p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE); +static CK_MECHANISM_TYPE p11_name_to_mgf(const char *); static void p11_perror(const char *, CK_RV); static const char * CKR2Str(CK_ULONG res); static int p11_test(CK_SESSION_HANDLE session); @@ -470,34 +492,35 @@ /* * Define attribute accessors */ -ATTR_METHOD(CLASS, CK_OBJECT_CLASS); -ATTR_METHOD(ALWAYS_AUTHENTICATE, CK_BBOOL); -ATTR_METHOD(PRIVATE, CK_BBOOL); -ATTR_METHOD(MODIFIABLE, CK_BBOOL); -ATTR_METHOD(ENCRYPT, CK_BBOOL); -ATTR_METHOD(DECRYPT, CK_BBOOL); -ATTR_METHOD(SIGN, CK_BBOOL); -ATTR_METHOD(VERIFY, CK_BBOOL); -ATTR_METHOD(WRAP, CK_BBOOL); -ATTR_METHOD(UNWRAP, CK_BBOOL); -ATTR_METHOD(DERIVE, CK_BBOOL); -ATTR_METHOD(OPENSC_NON_REPUDIATION, CK_BBOOL); -ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); -ATTR_METHOD(CERTIFICATE_TYPE, CK_CERTIFICATE_TYPE); -ATTR_METHOD(MODULUS_BITS, CK_ULONG); -ATTR_METHOD(VALUE_LEN, CK_ULONG); -VARATTR_METHOD(LABEL, char); -VARATTR_METHOD(APPLICATION, char); -VARATTR_METHOD(ID, unsigned char); -VARATTR_METHOD(OBJECT_ID, unsigned char); -VARATTR_METHOD(MODULUS, CK_BYTE); +ATTR_METHOD(CLASS, CK_OBJECT_CLASS); /* getCLASS */ +ATTR_METHOD(ALWAYS_AUTHENTICATE, CK_BBOOL); /* getALWAYS_AUTHENTICATE */ +ATTR_METHOD(PRIVATE, CK_BBOOL); /* getPRIVATE */ +ATTR_METHOD(MODIFIABLE, CK_BBOOL); /* getMODIFIABLE */ +ATTR_METHOD(ENCRYPT, CK_BBOOL); /* getENCRYPT */ +ATTR_METHOD(DECRYPT, CK_BBOOL); /* getDECRYPT */ +ATTR_METHOD(SIGN, CK_BBOOL); /* getSIGN */ +ATTR_METHOD(VERIFY, CK_BBOOL); /* getVERIFY */ +ATTR_METHOD(WRAP, CK_BBOOL); /* getWRAP */ +ATTR_METHOD(UNWRAP, CK_BBOOL); /* getUNWRAP */ +ATTR_METHOD(DERIVE, CK_BBOOL); /* getDERIVE */ +ATTR_METHOD(OPENSC_NON_REPUDIATION, CK_BBOOL); /* getOPENSC_NON_REPUDIATION */ +ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); /* getKEY_TYPE */ +ATTR_METHOD(CERTIFICATE_TYPE, CK_CERTIFICATE_TYPE); /* getCERTIFICATE_TYPE */ +ATTR_METHOD(MODULUS_BITS, CK_ULONG); /* getMODULUS_BITS */ +ATTR_METHOD(VALUE_LEN, CK_ULONG); /* getVALUE_LEN */ +VARATTR_METHOD(LABEL, char); /* getLABEL */ +VARATTR_METHOD(APPLICATION, char); /* getAPPLICATION */ +VARATTR_METHOD(ID, unsigned char); /* getID */ +VARATTR_METHOD(OBJECT_ID, unsigned char); /* getOBJECT_ID */ +VARATTR_METHOD(MODULUS, CK_BYTE); /* getMODULUS */ #ifdef ENABLE_OPENSSL -VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE); +VARATTR_METHOD(SUBJECT, unsigned char); /* getSUBJECT */ +VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE); /* getPUBLIC_EXPONENT */ #endif -VARATTR_METHOD(VALUE, unsigned char); -VARATTR_METHOD(GOSTR3410_PARAMS, unsigned char); -VARATTR_METHOD(EC_POINT, unsigned char); -VARATTR_METHOD(EC_PARAMS, unsigned char); +VARATTR_METHOD(VALUE, unsigned char); /* getVALUE */ +VARATTR_METHOD(GOSTR3410_PARAMS, unsigned char); /* getGOSTR3410_PARAMS */ +VARATTR_METHOD(EC_POINT, unsigned char); /* getEC_POINT */ +VARATTR_METHOD(EC_PARAMS, unsigned char); /* getEC_PARAMS */ int main(int argc, char * argv[]) @@ -537,6 +560,9 @@ CK_RV rv; #ifdef _WIN32 + char expanded_val[PATH_MAX]; + DWORD expanded_len; + if(_setmode(_fileno(stdout), _O_BINARY ) == -1) util_fatal("Cannot set FMODE to O_BINARY"); if(_setmode(_fileno(stdin), _O_BINARY ) == -1) @@ -669,6 +695,16 @@ opt_mechanism_used = 1; opt_mechanism = p11_name_to_mechanism(optarg); break; + case OPT_HASH_ALGORITHM: + opt_hash_alg = p11_name_to_mechanism(optarg); + break; + case OPT_MGF: + opt_mgf = p11_name_to_mgf(optarg); + break; + case OPT_SALT: + salt_len = (CK_ULONG) strtoul(optarg, NULL, 0); + salt_len_given = 1; + break; case 'o': opt_output = optarg; break; @@ -804,6 +840,9 @@ case OPT_PRIVATE: opt_is_private = 1; break; + case OPT_SENSITIVE: + opt_is_sensitive = 1; + break; case OPT_TEST_HOTPLUG: opt_test_hotplug = 1; action_count++; @@ -844,6 +883,13 @@ if (action_count == 0) util_print_usage_and_die(app_name, options, option_help, NULL); +#ifdef _WIN32 + expanded_len = PATH_MAX; + expanded_len = ExpandEnvironmentStringsA(opt_module, expanded_val, expanded_len); + if (0 < expanded_len && expanded_len < sizeof expanded_val) + opt_module = expanded_val; +#endif + module = C_LoadModule(opt_module, &p11); if (module == NULL) util_fatal("Failed to load pkcs11 module"); @@ -1318,7 +1364,7 @@ pin_flags=info.flags & ( CKF_SO_PIN_COUNT_LOW | CKF_SO_PIN_FINAL_TRY | - CKF_SO_PIN_LOCKED | + CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED); if(pin_flags) printf("WARNING: %s\n",p11_token_info_flags(pin_flags)); @@ -1329,7 +1375,7 @@ pin_flags=info.flags & ( CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | - CKF_USER_PIN_LOCKED | + CKF_USER_PIN_LOCKED | CKF_USER_PIN_TO_BE_CHANGED); if(pin_flags) printf("WARNING: %s\n",p11_token_info_flags(pin_flags)); @@ -1591,15 +1637,45 @@ return 0; } +/* return digest length in bytes */ +static unsigned long figure_pss_salt_length(const int hash) { + unsigned long sLen = 0; + switch (hash) { + case CKM_SHA_1: + sLen = 20; + break; + case CKM_SHA224: + sLen = 28; + break; + case CKM_SHA256: + sLen = 32; + break; + case CKM_SHA384: + sLen = 48; + break; + case CKM_SHA512: + sLen = 64; + break; + default: + util_fatal("Unknown hash algorithm '%s' for RSA-PSS signatures", + p11_mechanism_to_name(hash)); + break; + } + return sLen; +} + static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) { unsigned char in_buffer[1025], sig_buffer[512]; CK_MECHANISM mech; + CK_RSA_PKCS_PSS_PARAMS pss_params; CK_RV rv; CK_ULONG sig_len; int fd, r; + unsigned long hashlen = 0, modlen = 0; + if (!opt_mechanism_used) if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism)) util_fatal("Sign mechanism not supported"); @@ -1607,6 +1683,102 @@ fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); memset(&mech, 0, sizeof(mech)); mech.mechanism = opt_mechanism; + pss_params.hashAlg = 0; + + if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_PSS) + util_fatal("The hash-algorithm is applicable only to " + "RSA-PKCS-PSS mechanism"); + + /* set "default" MGF and hash algorithms. We can overwrite MGF later */ + switch (opt_mechanism) { + case CKM_RSA_PKCS_PSS: + pss_params.hashAlg = opt_hash_alg; + + switch (opt_hash_alg) { + case CKM_SHA224: + pss_params.mgf = CKG_MGF1_SHA224; + break; + case CKM_SHA256: + pss_params.mgf = CKG_MGF1_SHA256; + break; + case CKM_SHA384: + pss_params.mgf = CKG_MGF1_SHA384; + break; + case CKM_SHA512: + pss_params.mgf = CKG_MGF1_SHA512; + break; + default: + /* the PSS should use SHA-1 if not specified */ + pss_params.hashAlg = CKM_SHA_1; + /* fallthrough */ + case CKM_SHA_1: + pss_params.mgf = CKG_MGF1_SHA1; + } + break; + + case CKM_SHA1_RSA_PKCS_PSS: + pss_params.hashAlg = CKM_SHA_1; + pss_params.mgf = CKG_MGF1_SHA1; + break; + + case CKM_SHA224_RSA_PKCS_PSS: + pss_params.hashAlg = CKM_SHA224; + pss_params.mgf = CKG_MGF1_SHA224; + break; + + case CKM_SHA256_RSA_PKCS_PSS: + pss_params.hashAlg = CKM_SHA256; + pss_params.mgf = CKG_MGF1_SHA256; + break; + + case CKM_SHA384_RSA_PKCS_PSS: + pss_params.hashAlg = CKM_SHA384; + pss_params.mgf = CKG_MGF1_SHA384; + break; + + case CKM_SHA512_RSA_PKCS_PSS: + pss_params.hashAlg = CKM_SHA512; + pss_params.mgf = CKG_MGF1_SHA512; + break; + } + + /* One of RSA-PSS mechanisms above: They need parameters */ + if (pss_params.hashAlg) { + if (opt_mgf != 0) + pss_params.mgf = opt_mgf; + + hashlen = figure_pss_salt_length(pss_params.hashAlg); + + if (salt_len_given == 1) { /* salt size explicitly given */ + if (salt_len < 0 && salt_len != -1 && salt_len != -2) + util_fatal("Salt length must be greater or equal \ +to zero, or equal to -1 (meaning: use digest size) or to -2 \ +(meaning: use maximum permissible size"); + + modlen = (get_private_key_length(session, key) + 7) / 8; + switch(salt_len) { + case -1: /* salt size equals to digest size */ + pss_params.sLen = hashlen; + break; + case -2: /* maximum permissible salt len */ + pss_params.sLen = modlen - hashlen -2; + break; + default: /* use given size but its value must be >= 0 */ + pss_params.sLen = salt_len; + break; + } /* end switch (salt_len_given) */ + } else { /* use default: salt len of digest size */ + pss_params.sLen = hashlen; + } + + mech.pParameter = &pss_params; + mech.ulParameterLen = sizeof(pss_params); + + fprintf(stderr, "PSS parameters: hashAlg=%s, mgf=%s, salt_len=%lu B\n", + p11_mechanism_to_name(pss_params.hashAlg), + p11_mgf_to_name(pss_params.mgf), + pss_params.sLen); + } if (opt_input == NULL) fd = 0; @@ -1617,6 +1789,10 @@ if (r < 0) util_fatal("Cannot read from %s: %m", opt_input); + if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) + util_fatal("For %s mechanism, message size (got %d bytes) must be equal to specified digest length (%lu)\n", + p11_mechanism_to_name(opt_mechanism), r, hashlen); + rv = CKR_CANCEL; if (r < (int) sizeof(in_buffer)) { rv = p11->C_SignInit(session, &mech, key); @@ -1659,7 +1835,7 @@ util_fatal("failed to open %s: %m", opt_output); } - if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1) { + if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 || opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 || opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) { if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { unsigned char *seq; size_t seqlen; @@ -1689,6 +1865,7 @@ unsigned char in_buffer[1024], out_buffer[1024]; CK_MECHANISM mech; CK_RV rv; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; CK_ULONG in_len, out_len; int fd, r; @@ -1699,6 +1876,11 @@ fprintf(stderr, "Using decrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); memset(&mech, 0, sizeof(mech)); mech.mechanism = opt_mechanism; + oaep_params.hashAlg = 0; + + if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_OAEP) + util_fatal("The hash-algorithm is applicable only to " + "RSA-PKCS-OAEP mechanism"); if (opt_input == NULL) fd = 0; @@ -1710,6 +1892,62 @@ util_fatal("Cannot read from %s: %m", opt_input); in_len = r; + /* set "default" MGF and hash algorithms. We can overwrite MGF later */ + switch (opt_mechanism) { + case CKM_RSA_PKCS_OAEP: + oaep_params.hashAlg = opt_hash_alg; + switch (opt_hash_alg) { + case CKM_SHA224: + oaep_params.mgf = CKG_MGF1_SHA224; + break; + case CKM_SHA256: + oaep_params.mgf = CKG_MGF1_SHA256; + break; + case CKM_SHA384: + oaep_params.mgf = CKG_MGF1_SHA384; + break; + case CKM_SHA512: + oaep_params.mgf = CKG_MGF1_SHA512; + break; + default: + oaep_params.hashAlg = CKM_SHA_1; + /* fall through */ + case CKM_SHA_1: + oaep_params.mgf = CKG_MGF1_SHA1; + break; + } + break; + case CKM_RSA_PKCS: + mech.pParameter = NULL; + mech.ulParameterLen = 0; + break; + default: + util_fatal("Mechanism %s illegal or not supported\n", p11_mechanism_to_name(opt_mechanism)); + } + + + /* If an RSA-OAEP mechanism, it needs parameters */ + if (oaep_params.hashAlg) { + if (opt_mgf != 0) + oaep_params.mgf = opt_mgf; + + /* These settings are compatible with OpenSSL 1.0.2L and 1.1.0+ */ + oaep_params.source = 0UL; /* empty encoding parameter (label) */ + oaep_params.pSourceData = NULL; /* PKCS#11 standard: this must be NULLPTR */ + oaep_params.ulSourceDataLen = 0; /* PKCS#11 standard: this must be 0 */ + + mech.pParameter = &oaep_params; + mech.ulParameterLen = sizeof(oaep_params); + + fprintf(stderr, "OAEP parameters: hashAlg=%s, mgf=%s, source_type=%lu, source_ptr=%p, source_len=%lu\n", + p11_mechanism_to_name(oaep_params.hashAlg), + p11_mgf_to_name(oaep_params.mgf), + oaep_params.source, + oaep_params.pSourceData, + oaep_params.ulSourceDataLen); + + } + rv = p11->C_DecryptInit(session, &mech, key); if (rv != CKR_OK) p11_fatal("C_DecryptInit", rv); @@ -2028,6 +2266,7 @@ CK_MECHANISM mechanism = {CKM_AES_KEY_GEN, NULL_PTR, 0}; CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_BBOOL _true = TRUE; + CK_BBOOL _false = FALSE; CK_KEY_TYPE key_type = CKK_AES; CK_ULONG key_length; CK_ATTRIBUTE keyTemplate[20] = { @@ -2102,6 +2341,15 @@ util_fatal("Unknown key type %s", type); } + if (opt_is_sensitive != 0) { + FILL_ATTR(keyTemplate[n_attr], CKA_SENSITIVE, &_true, sizeof(_true)); + n_attr++; + } + else { + FILL_ATTR(keyTemplate[n_attr], CKA_SENSITIVE, &_false, sizeof(_false)); + n_attr++; + } + FILL_ATTR(keyTemplate[n_attr], CKA_ENCRYPT, &_true, sizeof(_true)); n_attr++; FILL_ATTR(keyTemplate[n_attr], CKA_DECRYPT, &_true, sizeof(_true)); @@ -2193,7 +2441,6 @@ cert->issuer_len = n; /* check length first */ - n = 0; n = i2d_ASN1_INTEGER(X509_get_serialNumber(x), NULL); if (n < 0) util_fatal("OpenSSL error while encoding serial number"); @@ -2388,7 +2635,7 @@ header_len = point-gost->public.value; memcpy(point, buf, point_len); gost->public.len = header_len+point_len; -#ifndef EC_POINT_NO_ASN1_OCTET_STRING // workaround for non-compliant cards not expecting DER encoding +#ifdef EC_POINT_NO_ASN1_OCTET_STRING // workaround for non-compliant cards not expecting DER encoding gost->public.len -= header_len; gost->public.value += header_len; #endif @@ -2989,7 +3236,7 @@ count = get_mechanisms(slot, &mechs, flags); if (count) { if (list && list_len) { - unsigned ii, jj; + unsigned ii = list_len, jj; for (jj=0; jjC_GetMechanismList(slot, *pList, &ulCount); + if (rv != CKR_OK) + p11_fatal("C_GetMechanismList", rv); + *pList = calloc(ulCount, sizeof(**pList)); if (*pList == NULL) util_fatal("calloc failed: %m"); @@ -4308,14 +4579,14 @@ break; case CKM_RSA_X_509: dataLen = modLenBytes; + pseudo_randomize(data, dataLen); break; default: dataLen = sizeof(data); /* let's hope it's OK */ + pseudo_randomize(data, dataLen); break; } - pseudo_randomize(data, dataLen); - if (firstMechType == CKM_RSA_X_509) { /* make sure our data is smaller than the modulus */ data[0] = 0x00; @@ -4418,7 +4689,8 @@ data[0] = 0x00; data[1] = 0x01; memset(data + 2, 0xFF, dataLen - 3 - dataLens[1]); - data[dataLen - 36] = 0x00; + if (dataLen >= 36) + data[dataLen - 36] = 0x00; memcpy(data + (dataLen - dataLens[1]), datas[1], dataLens[1]); datas[0] = data; dataLens[0] = dataLen; @@ -4834,7 +5106,7 @@ return 0; if (EVP_PKEY_size(pkey) > (int)sizeof(encrypted)) { - fprintf(stderr, "Ciphertext buffer too small\n"); + printf("Ciphertext buffer too small\n"); EVP_PKEY_free(pkey); return 0; } @@ -4845,14 +5117,14 @@ #endif EVP_PKEY_free(pkey); if (((int) encrypted_len) <= 0) { - fprintf(stderr, "Encryption failed, returning\n"); + printf("Encryption failed, returning\n"); return 0; } mech.mechanism = mech_type; rv = p11->C_DecryptInit(session, &mech, privKeyObject); - if (rv == CKR_MECHANISM_INVALID) { - fprintf(stderr, "Mechanism not supported\n"); + if (rv == CKR_MECHANISM_INVALID || rv == CKR_MECHANISM_PARAM_INVALID) { + printf("Mechanism not supported\n"); return 0; } if (rv != CKR_OK) @@ -5137,7 +5409,7 @@ /* This is done in NSS */ getMODULUS(session, priv_key, &mod_len); - if (mod_len < 5 || mod_len > 10000) { /* should be resonable limits */ + if (mod_len < 5 || mod_len > 10000) { /* should be reasonable limits */ fprintf(stderr, "ERR: GetAttribute(privkey, CKA_MODULUS) doesn't seem to work\n"); return session; } @@ -5193,6 +5465,7 @@ p11_fatal("C_SignInit", rv); if (getALWAYS_AUTHENTICATE(session, priv_key)) login(session,CKU_CONTEXT_SPECIFIC); + rv = p11->C_Sign(session, data, data_len, sig, &sig_len); if (rv != CKR_OK) p11_fatal("C_Sign", rv); @@ -5225,7 +5498,7 @@ C_UnloadModule(module); /* Now we assume the user turns of her PC and comes back tomorrow to see - * if here cert is allready made and to install it (as is done next) */ + * if here cert is already made and to install it (as is done next) */ printf("\n*** In real life, the cert req should now be sent to the CA ***\n"); @@ -5259,7 +5532,7 @@ if (!delete_object(session)) util_fatal("Failed to delete certificate"); - printf("\n==> OK, successfull! Should work with Mozilla\n"); + printf("\n==> OK, successful! Should work with Mozilla\n"); return session; } @@ -5608,6 +5881,7 @@ { CKM_MD2_RSA_PKCS, "MD2-RSA-PKCS", NULL }, { CKM_MD5_RSA_PKCS, "MD5-RSA-PKCS", "rsa-md5" }, { CKM_SHA1_RSA_PKCS, "SHA1-RSA-PKCS", "rsa-sha1" }, + { CKM_SHA224_RSA_PKCS, "SHA224-RSA-PKCS", "rsa-sha224" }, { CKM_SHA256_RSA_PKCS, "SHA256-RSA-PKCS", "rsa-sha256" }, { CKM_SHA384_RSA_PKCS, "SHA384-RSA-PKCS", "rsa-sha384" }, { CKM_SHA512_RSA_PKCS, "SHA512-RSA-PKCS", "rsa-sha512" }, @@ -5618,10 +5892,11 @@ { CKM_RSA_X9_31, "RSA-X9-31", NULL }, { CKM_SHA1_RSA_X9_31, "SHA1-RSA-X9-31", NULL }, { CKM_RSA_PKCS_PSS, "RSA-PKCS-PSS", NULL }, - { CKM_SHA1_RSA_PKCS_PSS, "SHA1-RSA-PKCS-PSS", NULL }, - { CKM_SHA256_RSA_PKCS, "SHA256-RSA-PKCS-PSS", NULL }, - { CKM_SHA384_RSA_PKCS, "SHA384-RSA-PKCS-PSS", NULL }, - { CKM_SHA512_RSA_PKCS, "SHA512-RSA-PKCS-PSS", NULL }, + { CKM_SHA1_RSA_PKCS_PSS, "SHA1-RSA-PKCS-PSS", "rsa-pss-sha1" }, + { CKM_SHA224_RSA_PKCS_PSS,"SHA224-RSA-PKCS-PSS", "rsa-pss-sha224" }, + { CKM_SHA256_RSA_PKCS_PSS,"SHA256-RSA-PKCS-PSS", "rsa-pss-sha256" }, + { CKM_SHA384_RSA_PKCS_PSS,"SHA384-RSA-PKCS-PSS", "rsa-pss-sha384" }, + { CKM_SHA512_RSA_PKCS_PSS,"SHA512-RSA-PKCS-PSS", "rsa-pss-sha512" }, { CKM_DSA_KEY_PAIR_GEN, "DSA-KEY-PAIR-GEN", NULL }, { CKM_DSA, "DSA", NULL }, { CKM_DSA_SHA1, "DSA-SHA1", NULL }, @@ -5667,9 +5942,14 @@ { CKM_SHA_1, "SHA-1", NULL }, { CKM_SHA_1_HMAC, "SHA-1-HMAC", NULL }, { CKM_SHA_1_HMAC_GENERAL, "SHA-1-HMAC-GENERAL", NULL }, + { CKM_SHA224, "SHA224", NULL }, + { CKM_SHA224_HMAC, "SHA224-HMAC", NULL }, { CKM_SHA256, "SHA256", NULL }, + { CKM_SHA256_HMAC, "SHA256-HMAC", NULL }, { CKM_SHA384, "SHA384", NULL }, + { CKM_SHA384_HMAC, "SHA384-HMAC", NULL }, { CKM_SHA512, "SHA512", NULL }, + { CKM_SHA512_HMAC, "SHA512-HMAC", NULL }, { CKM_RIPEMD128, "RIPEMD128", NULL }, { CKM_RIPEMD128_HMAC, "RIPEMD128-HMAC", NULL }, { CKM_RIPEMD128_HMAC_GENERAL,"RIPEMD128-HMAC-GENERAL", NULL }, @@ -5767,7 +6047,7 @@ { CKM_ECDSA_SHA1, "ECDSA-SHA1", NULL }, { CKM_ECDSA_SHA224, "ECDSA-SHA224", NULL }, { CKM_ECDSA_SHA256, "ECDSA-SHA256", NULL }, - { CKM_ECDSA_SHA384, "ECDSA-SHA348", NULL }, + { CKM_ECDSA_SHA384, "ECDSA-SHA384", NULL }, { CKM_ECDSA_SHA512, "ECDSA-SHA512", NULL }, { CKM_ECDH1_DERIVE, "ECDH1-DERIVE", NULL }, { CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE", NULL }, @@ -5795,6 +6075,15 @@ { 0, NULL, NULL } }; +static struct mech_info p11_mgf[] = { + { CKG_MGF1_SHA1, "MGF1-SHA1", NULL }, + { CKG_MGF1_SHA224, "MGF1-SHA224", NULL }, + { CKG_MGF1_SHA256, "MGF1-SHA256", NULL }, + { CKG_MGF1_SHA384, "MGF1-SHA384", NULL }, + { CKG_MGF1_SHA512, "MGF1-SHA512", NULL }, + { 0, NULL, NULL } +}; + static const char *p11_mechanism_to_name(CK_MECHANISM_TYPE mech) { static char temp[64]; @@ -5812,6 +6101,9 @@ { struct mech_info *mi; + if (strncasecmp("0x", name, 2) == 0) { + return strtoul(name, NULL, 0); + } for (mi = p11_mechanisms; mi->name; mi++) { if (!strcasecmp(mi->name, name) || (mi->short_name && !strcasecmp(mi->short_name, name))) @@ -5821,6 +6113,30 @@ return 0; /* gcc food */ } +static CK_RSA_PKCS_MGF_TYPE p11_name_to_mgf(const char *name) +{ + struct mech_info *mi; + + for (mi = p11_mgf; mi->name; mi++) { + if (!strcasecmp(mi->name, name)) + return mi->mech; + } + util_fatal("Unknown PKCS11 MGF \"%s\"", name); +} + +static const char *p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE mgf) +{ + static char temp[64]; + struct mech_info *mi; + + for (mi = p11_mgf; mi->name; mi++) { + if (mi->mech == mgf) + return mi->name; + } + snprintf(temp, sizeof(temp), "mgf-0x%lX", (unsigned long) mgf); + return temp; +} + static const char * CKR2Str(CK_ULONG res) { switch (res) { diff -Nru opensc-0.17.0/src/tools/pkcs15-crypt.c opensc-0.19.0/src/tools/pkcs15-crypt.c --- opensc-0.17.0/src/tools/pkcs15-crypt.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/pkcs15-crypt.c 2018-09-13 11:47:21.000000000 +0000 @@ -34,6 +34,7 @@ #endif #include "common/compat_getpass.h" +#include "libopensc/internal.h" #include "libopensc/opensc.h" #include "libopensc/pkcs15.h" #include "libopensc/asn1.h" @@ -129,7 +130,7 @@ static char * get_pin(struct sc_pkcs15_object *obj) { - char buf[80]; + char buf[(sizeof obj->label) + 20]; char *pincode; struct sc_pkcs15_auth_info *pinfo = (struct sc_pkcs15_auth_info *) obj->data; @@ -143,7 +144,8 @@ return strdup(opt_pincode); } - sprintf(buf, "Enter PIN [%.*s]: ", (int) sizeof obj->label, obj->label); + snprintf(buf, sizeof(buf), "Enter PIN [%.*s]: ", + (int) sizeof obj->label, obj->label); while (1) { pincode = getpass(buf); if (strlen(pincode) == 0) @@ -285,7 +287,7 @@ } r = write_output(out, r); - return 0; + return r; } static int get_key(unsigned int usage, sc_pkcs15_object_t **result) @@ -352,7 +354,7 @@ return 0; } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_decipher = 0; @@ -461,7 +463,7 @@ sc_ctx_log_to_file(ctx, "stderr"); } - err = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); + err = util_connect_card_ex(ctx, &card, opt_reader, opt_wait, 0, verbose); if (err) goto end; @@ -508,7 +510,6 @@ if (p15card) sc_pkcs15_unbind(p15card); if (card) { - sc_unlock(card); sc_disconnect_card(card); } if (ctx) diff -Nru opensc-0.17.0/src/tools/pkcs15-init.c opensc-0.19.0/src/tools/pkcs15-init.c --- opensc-0.17.0/src/tools/pkcs15-init.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/pkcs15-init.c 2018-09-13 11:47:21.000000000 +0000 @@ -61,6 +61,7 @@ #endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ #include "common/compat_strlcpy.h" +#include "libopensc/internal.h" #include "libopensc/cardctl.h" #include "libopensc/pkcs15.h" #include "libopensc/log.h" @@ -235,7 +236,7 @@ "Store public key", "Store secret key", "Store an X.509 certificate", - "Update an X.509 certificate (carefull with mail decryption certs!!)", + "Update an X.509 certificate (careful with mail decryption certs!!)", "Store a data object", "Delete object(s) (use \"help\" for more information)", "Change attribute(s) (use \"help\" for more information)", @@ -267,7 +268,7 @@ "Mark certificate as a CA certificate", "Specify X.509 key usage (use \"--key-usage help\" for more information)", "Finish initialization phase of the smart card", - "Update 'lastUpdate' attribut of tokenInfo", + "Update 'lastUpdate' attribute of tokenInfo", "When storing PKCS#12 ignore CA certificates", "Store or update existing certificate", @@ -1473,7 +1474,7 @@ } /* Check if the cert has a 'sibling' and return it's parent cert. - * Should be made more effcicient for long chains by caching the certs. + * Should be made more efficient for long chains by caching the certs. */ static int get_cert_info(sc_pkcs15_card_t *myp15card, sc_pkcs15_object_t *certobj, int *has_sibling, int *stop, sc_pkcs15_object_t **issuercert) @@ -1530,7 +1531,7 @@ /* Delete object(s) by ID. The 'which' param can be any combination of * SC_PKCS15INIT_TYPE_PRKEY, SC_PKCS15INIT_TYPE_PUBKEY, SC_PKCS15INIT_TYPE_CERT * and SC_PKCS15INIT_TYPE_CHAIN. In the last case, every cert in the chain is - * deleted, starting with the cert with ID 'id' and untill a CA cert is + * deleted, starting with the cert with ID 'id' and until a CA cert is * reached that certified other remaining certs on the card. */ static int do_delete_crypto_objects(sc_pkcs15_card_t *myp15card, @@ -2555,7 +2556,7 @@ printf("When \"data\" is specified, an --application-id must also be specified,\n"); printf(" in the other cases an \"--id\" must also be specified\n"); printf("When \"chain\" is specified, the certificate chain starting with the cert\n"); - printf(" with specified ID will be deleted, untill there's a CA cert that certifies\n"); + printf(" with specified ID will be deleted, until there's a CA cert that certifies\n"); printf(" another cert on the card\n"); } else { @@ -2573,7 +2574,7 @@ } } if (del_flags[n].name == NULL) { - fprintf(stderr, "Unknown argument for --delete_objects: %.*s\n", len, list); + fprintf(stderr, "Unknown argument for --delete-objects: %.*s\n", len, list); exit(0); } list += len; @@ -2793,6 +2794,7 @@ break; case OPT_USE_PINPAD_DEPRECATED: fprintf(stderr, "'--no-prompt' is deprecated , use '--use-pinpad' instead.\n"); + /* fall through */ case OPT_USE_PINPAD: opt_use_pinpad = 1; break; @@ -2889,6 +2891,7 @@ switch (o->has_arg) { case optional_argument: *sp++ = ':'; + /* fall through */ case required_argument: *sp++ = ':'; case no_argument: @@ -3088,7 +3091,7 @@ static int verify_pin(struct sc_pkcs15_card *p15card, char *auth_id_str) { struct sc_pkcs15_object *pin_obj = NULL; - char pin_label[64]; + char pin_label[(sizeof pin_obj->label) + 20]; char *pin = NULL; int r; @@ -3142,7 +3145,8 @@ return SC_ERROR_OBJECT_NOT_FOUND; if (pin_obj->label[0]) - snprintf(pin_label, sizeof(pin_label), "User PIN [%s]", pin_obj->label); + snprintf(pin_label, sizeof(pin_label), "User PIN [%.*s]", + (int) sizeof pin_obj->label, pin_obj->label); else snprintf(pin_label, sizeof(pin_label), "User PIN"); memset(&hints, 0, sizeof(hints)); diff -Nru opensc-0.17.0/src/tools/pkcs15-tool.c opensc-0.19.0/src/tools/pkcs15-tool.c --- opensc-0.17.0/src/tools/pkcs15-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/pkcs15-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -570,6 +570,8 @@ else { printf("\tAuth ID: %s\n", sc_pkcs15_print_id(&objs[i]->auth_id)); } + + printf("\n"); } return 0; } @@ -823,7 +825,7 @@ out: if (cert) sc_pkcs15_free_certificate(cert); - else if (pubkey) + else sc_pkcs15_free_pubkey(pubkey); return r; @@ -918,9 +920,9 @@ } if (obj->label[0] != '\0') - fprintf(outf,"ssh-%s %s %.*s\n", alg, uu, (int) sizeof obj->label, obj->label); + fprintf(outf,"%s %s %.*s\n", alg, uu, (int) sizeof obj->label, obj->label); else - fprintf(outf,"ssh-%s %s\n", alg, uu); + fprintf(outf,"%s %s\n", alg, uu); } free(uu); return; @@ -982,6 +984,70 @@ return 1; } + if (pubkey->algorithm == SC_ALGORITHM_EC) { + // support only for NIST + // 'ssh-keygen -t ecdsa' allow only field lengths 256/384/521 + + static struct supported_ec_curves { + char *curve_name; + struct sc_object_id curve_oid; + size_t size; + } ec_curves[] = { + {"secp256r1", {{1, 2, 840, 10045, 3, 1, 7, -1}},256}, + {"secp384r1", {{1, 3, 132, 0, 34, -1}}, 384}, + {"secp521r1", {{1, 3, 132, 0, 35, -1}}, 521}, + {NULL, {{-1}}, 0}, + }; + char alg[20]; + /* Large enough to fit the following: + * 3 x 4B item length headers + * max 20B algorithm name, 9B curve name, max 256B key data */ + unsigned char buf[300]; + unsigned int i, len, tmp, n; + + for (n = 0,i = 0; ec_curves[i].curve_name != NULL; i++) { + if(sc_compare_oid (&ec_curves[i].curve_oid,&pubkey->u.ec.params.id)) + n = ec_curves[i].size; + } + if (!n) { + fprintf(stderr, "Unsupported curve\n"); + goto fail2; + } + if (n != pubkey->u.ec.params.field_length) { + fprintf(stderr, "Wrong field length\n"); + goto fail2; + } + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + len = snprintf((char *) buf+4, 20, "ecdsa-sha2-nistp%d", n); + strncpy(alg, (char *) buf+4, 19); + buf[3] = len; + + len += 4; + buf[len++] = 0; + buf[len++] = 0; + buf[len++] = 0; + tmp = snprintf((char *) buf+len+1, 9, "nistp%d", n); + buf[len++] = tmp; + len += tmp; + + n = pubkey->u.ec.ecpointQ.len; + if(n > 255) { + fprintf(stderr, "Wrong public key length\n"); + goto fail2; + } + buf[len++] = 0; + buf[len++] = 0; + buf[len++] = 0; + buf[len++] = n & 0xff; + memcpy(buf+len,pubkey->u.ec.ecpointQ.value,n); + len += n; + + print_ssh_key(outf, alg, obj, buf, len); + } + if (pubkey->algorithm == SC_ALGORITHM_RSA) { unsigned char buf[2048]; uint32_t len, n; @@ -1034,7 +1100,7 @@ memcpy(buf+len,pubkey->u.rsa.modulus.data, pubkey->u.rsa.modulus.len); len += pubkey->u.rsa.modulus.len; - print_ssh_key(outf, "rsa", obj, buf, len); + print_ssh_key(outf, "ssh-rsa", obj, buf, len); } if (pubkey->algorithm == SC_ALGORITHM_DSA) { @@ -1125,14 +1191,14 @@ memcpy(buf+len,pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len); len += pubkey->u.dsa.pub.len; - print_ssh_key(outf, "dss", obj, buf, len); + print_ssh_key(outf, "ssh-dss", obj, buf, len); } if (outf != stdout) fclose(outf); if (cert) sc_pkcs15_free_certificate(cert); - else if (pubkey) + else sc_pkcs15_free_pubkey(pubkey); return 0; fail: @@ -1142,7 +1208,7 @@ fclose(outf); if (cert) sc_pkcs15_free_certificate(cert); - else if (pubkey) + else sc_pkcs15_free_pubkey(pubkey); return SC_ERROR_OUT_OF_MEMORY; } @@ -1608,7 +1674,7 @@ count++; } } - printf("\n"); + printf((compact) ? "\n" : "\n\n"); } static int dump(void) @@ -2031,7 +2097,7 @@ return 0; } -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int do_read_cert = 0; @@ -2061,8 +2127,6 @@ assert(sizeof(option_help)/sizeof(char *)==sizeof(options)/sizeof(struct option)); - c = OPT_PUK; - while (1) { c = getopt_long(argc, argv, "r:cuko:sva:LR:CwDTU", options, &long_optind); if (c == -1) diff -Nru opensc-0.17.0/src/tools/sceac-example.c opensc-0.19.0/src/tools/sceac-example.c --- opensc-0.17.0/src/tools/sceac-example.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/sceac-example.c 2018-09-13 11:47:21.000000000 +0000 @@ -30,6 +30,7 @@ #include "libopensc/sm.h" #include "sm/sm-iso.h" #include "sm/sm-eac.h" +#include "libopensc/card-npa.h" #include static const char *newpin = NULL; diff -Nru opensc-0.17.0/src/tools/sc-hsm-tool.c opensc-0.19.0/src/tools/sc-hsm-tool.c --- opensc-0.17.0/src/tools/sc-hsm-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/sc-hsm-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -45,6 +45,7 @@ #include "libopensc/opensc.h" #include "libopensc/cardctl.h" #include "libopensc/asn1.h" +#include "libopensc/log.h" #include "libopensc/card-sc-hsm.h" #include "util.h" @@ -62,7 +63,7 @@ // Some reasonable maximums #define MAX_CERT 4096 #define MAX_PRKD 256 -#define MAX_KEY 1024 +#define MAX_KEY 1500 #define MAX_WRAPPED_KEY (MAX_CERT + MAX_PRKD + MAX_KEY) #define SEED_LENGTH 16 @@ -296,7 +297,7 @@ * @param shares Shares used to reconstruct secret (should contain t entries) * @param t Threshold used to reconstruct the secret * @param prime Prime for finite field arithmetic - * @param s Pointer for storage of calculated secred + * @param s Pointer for storage of calculated secret */ static int reconstructSecret(secret_share_t *shares, unsigned char t, const BIGNUM *prime, BIGNUM *s) { @@ -1222,7 +1223,8 @@ unsigned int cla,tag; size_t len; - if (sc_asn1_read_tag(&ptr, buflen, &cla, &tag, &len) != SC_SUCCESS) { + if (sc_asn1_read_tag(&ptr, buflen, &cla, &tag, &len) != SC_SUCCESS + || ptr == NULL) { return 0; } @@ -1387,8 +1389,9 @@ // Encode key in octet string object key_len = 0; - wrap_with_tag(0x04, wrapped_key.wrapped_key, wrapped_key.wrapped_key_length, + r = wrap_with_tag(0x04, wrapped_key.wrapped_key, wrapped_key.wrapped_key_length, &key, &key_len); + LOG_TEST_RET(ctx, r, "Out of memory"); memcpy(ptr, key, key_len); ptr += key_len; @@ -1410,7 +1413,8 @@ } // Encode key, key decription and certificate object in sequence - wrap_with_tag(0x30, keyblob, ptr - keyblob, &key, &key_len); + r = wrap_with_tag(0x30, keyblob, ptr - keyblob, &key, &key_len); + LOG_TEST_RET(ctx, r, "Out of memory"); out = fopen(outf, "wb"); @@ -1449,7 +1453,7 @@ r = sc_select_file(card, &path, NULL); if ((r == SC_SUCCESS) && erase) { - r = sc_delete_file(card, &path); + sc_delete_file(card, &path); r = SC_ERROR_FILE_NOT_FOUND; } @@ -1512,16 +1516,16 @@ fclose(in); ptr = keyblob; - if ((sc_asn1_read_tag(&ptr, keybloblen, &cla, &tag, &len) != SC_SUCCESS) || - ((cla & SC_ASN1_TAG_CONSTRUCTED) != SC_ASN1_TAG_CONSTRUCTED) || - ((tag != SC_ASN1_TAG_SEQUENCE)) ){ + if ((sc_asn1_read_tag(&ptr, keybloblen, &cla, &tag, &len) != SC_SUCCESS) + || ((cla & SC_ASN1_TAG_CONSTRUCTED) != SC_ASN1_TAG_CONSTRUCTED) + || (tag != SC_ASN1_TAG_SEQUENCE) ){ fprintf(stderr, "Invalid wrapped key format (Outer sequence).\n"); return -1; } - if ((sc_asn1_read_tag(&ptr, len, &cla, &tag, &olen) != SC_SUCCESS) || - (cla & SC_ASN1_TAG_CONSTRUCTED) || - ((tag != SC_ASN1_TAG_OCTET_STRING)) ){ + if ((sc_asn1_read_tag(&ptr, len, &cla, &tag, &olen) != SC_SUCCESS) + || ((cla & SC_ASN1_TAG_CONSTRUCTED) == SC_ASN1_TAG_CONSTRUCTED) + || (tag != SC_ASN1_TAG_OCTET_STRING) ){ fprintf(stderr, "Invalid wrapped key format (Key binary).\n"); return -1; } @@ -1651,7 +1655,7 @@ -int main(int argc, char * const argv[]) +int main(int argc, char *argv[]) { int err = 0, r, c, long_optind = 0; int action_count = 0; @@ -1757,7 +1761,7 @@ } } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !(defined LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L) OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, diff -Nru opensc-0.17.0/src/tools/util.c opensc-0.19.0/src/tools/util.c --- opensc-0.17.0/src/tools/util.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/util.c 2018-09-13 11:47:21.000000000 +0000 @@ -30,6 +30,8 @@ #endif #include #include "util.h" +#include "ui/notify.h" +#include "common/compat_strlcat.h" int is_string_valid_atr(const char *atr_str) @@ -54,6 +56,8 @@ struct sc_card *card = NULL; int r; + sc_notify_init(); + if (do_wait) { unsigned int event; @@ -99,7 +103,7 @@ else { /* If the reader identifier looks like an ATR, try to find the reader with that card */ if (is_string_valid_atr(reader_id)) { - unsigned char atr_buf[SC_MAX_ATR_SIZE * 3]; + unsigned char atr_buf[SC_MAX_ATR_SIZE]; size_t atr_buf_len = sizeof(atr_buf); unsigned int i; @@ -232,7 +236,8 @@ } } -void util_print_usage_and_die(const char *app_name, const struct option options[], +NORETURN void +util_print_usage_and_die(const char *app_name, const struct option options[], const char *option_help[], const char *args) { int i; @@ -335,15 +340,16 @@ strcpy(buf, "????"); break; } - strcat(line, buf); - strcat(line, " "); + strlcat(line, buf, sizeof line); + strlcat(line, " ", sizeof line); e = e->next; } + line[(sizeof line)-1] = '\0'; /* make sure it's NUL terminated */ line[strlen(line)-1] = 0; /* get rid of trailing space */ return line; } -void +NORETURN void util_fatal(const char *fmt, ...) { va_list ap; @@ -353,6 +359,9 @@ vfprintf(stderr, fmt, ap); fprintf(stderr, "\nAborting.\n"); va_end(ap); + + sc_notify_close(); + exit(1); } diff -Nru opensc-0.17.0/src/tools/util.h opensc-0.19.0/src/tools/util.h --- opensc-0.17.0/src/tools/util.h 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/util.h 2018-09-13 11:47:21.000000000 +0000 @@ -23,15 +23,28 @@ extern "C" { #endif +#if _MSC_VER >= 1310 +/* MS Visual Studio 2003/.NET Framework 1.1 or newer */ +# define NORETURN _declspec( noreturn) +#elif __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ >= 5)) || (defined __clang__) +# define NORETURN __attribute__ ((noreturn)) +#elif __cplusplus >= 201103L +# define NORETURN [[noreturn]] +#elif __STDC_VERSION__ >= 201112L +# define NORETURN _Noreturn +#else +# define NORETURN +#endif + void util_print_binary(FILE *f, const u8 *buf, int count); void util_hex_dump(FILE *f, const u8 *in, int len, const char *sep); void util_hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr); -void util_print_usage_and_die(const char *app_name, const struct option options[], +NORETURN void util_print_usage_and_die(const char *app_name, const struct option options[], const char *option_help[], const char *args); const char * util_acl_to_str(const struct sc_acl_entry *e); void util_warn(const char *fmt, ...); void util_error(const char *fmt, ...); -void util_fatal(const char *fmt, ...); +NORETURN void util_fatal(const char *fmt, ...); /* All singing all dancing card connect routine */ int util_connect_card_ex(struct sc_context *, struct sc_card **, const char *reader_id, int do_wait, int do_lock, int verbose); int util_connect_card(struct sc_context *, struct sc_card **, const char *reader_id, int do_wait, int verbose); diff -Nru opensc-0.17.0/src/tools/versioninfo-opensc-notify.rc.in opensc-0.19.0/src/tools/versioninfo-opensc-notify.rc.in --- opensc-0.17.0/src/tools/versioninfo-opensc-notify.rc.in 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/tools/versioninfo-opensc-notify.rc.in 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,47 @@ +#include + +#define IDC_STATIC -1 +/* defined twice: in resource file and in source code */ +#define IDI_SMARTCARD 102 + +#ifndef __MINGW32__ +IDI_SMARTCARD ICON "..\\..\\win32\\DDORes.dll_14_2302.ico" +#else +IDI_SMARTCARD ICON "../../win32/DDORes.dll_14_2302.ico" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @OPENSC_VERSION_MAJOR@,@OPENSC_VERSION_MINOR@,@OPENSC_VERSION_FIX@,@OPENSC_VERSION_REVISION@ + PRODUCTVERSION @OPENSC_VERSION_MAJOR@,@OPENSC_VERSION_MINOR@,@OPENSC_VERSION_FIX@,@OPENSC_VERSION_REVISION@ + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "@OPENSC_VS_FF_COMMENTS@" + VALUE "CompanyName", "@OPENSC_VS_FF_COMPANY_NAME@" + VALUE "FileVersion", "@OPENSC_VERSION_MAJOR@.@OPENSC_VERSION_MINOR@.@OPENSC_VERSION_FIX@.@OPENSC_VERSION_REVISION@" + VALUE "InternalName", "@PACKAGE_NAME@" + VALUE "LegalCopyright", "@OPENSC_VS_FF_LEGAL_COPYRIGHT@" + VALUE "LegalTrademarks", "" + VALUE "PrivateBuild", "" + VALUE "ProductName", "@OPENSC_VS_FF_PRODUCT_NAME@" + VALUE "ProductVersion", "@OPENSC_VERSION_MAJOR@,@OPENSC_VERSION_MINOR@,@OPENSC_VERSION_FIX@,@OPENSC_VERSION_REVISION@" + VALUE "SpecialBuild", "" + VALUE "FileDescription", "OpenSC Notify" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff -Nru opensc-0.17.0/src/tools/westcos-tool.c opensc-0.19.0/src/tools/westcos-tool.c --- opensc-0.17.0/src/tools/westcos-tool.c 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/src/tools/westcos-tool.c 2018-09-13 11:47:21.000000000 +0000 @@ -477,7 +477,7 @@ file = sc_file_new(); if(file == NULL) { - printf("Not enougth memory.\n"); + printf("Not enough memory.\n"); goto out; } @@ -596,7 +596,7 @@ if(rsa == NULL || bn == NULL || mem == NULL) { - printf("Not enougth memory.\n"); + printf("Not enough memory.\n"); goto out; } @@ -608,7 +608,7 @@ if(mem == NULL) { - printf("Not enougth memory.\n"); + printf("Not enough memory.\n"); goto out; } @@ -638,7 +638,7 @@ file = sc_file_new(); if(file == NULL) { - printf("Not enougth memory.\n"); + printf("Not enough memory.\n"); goto out; } @@ -814,7 +814,7 @@ b = malloc(file->size); if(b == NULL) { - printf("Not enougth memory.\n"); + printf("Not enough memory.\n"); goto out; } @@ -864,14 +864,18 @@ b = malloc(file->size); if(b == NULL) { - printf("Not enougth memory.\n"); - goto out; + printf("Not enough memory.\n"); + goto out; } memset(b, 0, file->size); fp = fopen(put_filename, "rb"); - fread(b, 1, file->size, fp); + if (fp == NULL || file->size != fread(b, 1, file->size, fp)) + { + printf("could not read %s.\n", put_filename); + goto out; + } fclose(fp); r = sc_update_binary(card, 0, b, file->size, 0); diff -Nru opensc-0.17.0/src/ui/char_str_from_wchar.h opensc-0.19.0/src/ui/char_str_from_wchar.h --- opensc-0.17.0/src/ui/char_str_from_wchar.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/char_str_from_wchar.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * char_str_from_wchar.h: Conversion from wide string to string + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static char *char_str_from_wchar(const WCHAR *in) +{ + char *out; + int out_len; + + if (!in) + return NULL; + + out_len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); + if (0 >= out_len) + return NULL; + + out = LocalAlloc(0, (sizeof *out) * out_len); + if (!out) + return NULL; + + out_len = WideCharToMultiByte(CP_UTF8, 0, in, -1, out, out_len, NULL, NULL); + if (out_len == 0xFFFD || 0 >= out_len) { + LocalFree(out); + return NULL; + } + + return out; +} diff -Nru opensc-0.17.0/src/ui/invisible_window.h opensc-0.19.0/src/ui/invisible_window.h --- opensc-0.17.0/src/ui/invisible_window.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/invisible_window.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * invisible_window.h: Create invisible Window + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +HWND create_invisible_window(LPCTSTR lpszClassName, + LRESULT (CALLBACK* WndProc)(HWND, UINT, WPARAM, LPARAM), + HINSTANCE hInstance) +{ + HWND hWnd = NULL; + WNDCLASSEX wx = {0}; + + //Register Window class + wx.cbSize = sizeof(WNDCLASSEX); + wx.lpfnWndProc = WndProc; + wx.hInstance = hInstance; + wx.lpszClassName = lpszClassName; + if (RegisterClassEx(&wx)) { + /* create window */ + hWnd = CreateWindowEx(0, lpszClassName, lpszClassName, 0, 0, 0, 0, 0, + HWND_MESSAGE, NULL, NULL, NULL ); + } + + return hWnd; +} + +static BOOL delete_invisible_window(HWND hWnd, LPCTSTR lpszClassName, + HINSTANCE hInstance) +{ + BOOL r; + r = DestroyWindow(hWnd); + r &= UnregisterClass(lpszClassName, hInstance); + + return r; +} diff -Nru opensc-0.17.0/src/ui/Makefile.am opensc-0.19.0/src/ui/Makefile.am --- opensc-0.17.0/src/ui/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,16 @@ +include $(top_srcdir)/win32/ltrc.inc + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +EXTRA_DIST = Makefile.mak + +noinst_LTLIBRARIES = libstrings.la libnotify.la +noinst_HEADERS = strings.h notify.h wchar_from_char_str.h char_str_from_wchar.h invisible_window.h + +AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_NOTIFY_CFLAGS) +AM_OBJCFLAGS = $(AM_CFLAGS) + +libstrings_la_SOURCES = strings.c + +libnotify_la_SOURCES = notify.c +libnotify_la_LIBADD = $(OPTIONAL_NOTIFY_LIBS) diff -Nru opensc-0.17.0/src/ui/Makefile.mak opensc-0.19.0/src/ui/Makefile.mak --- opensc-0.17.0/src/ui/Makefile.mak 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/Makefile.mak 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,17 @@ +TOPDIR = ..\.. + +TARGET = strings.lib +OBJECTS = strings.obj + +TARGET2 = notify.lib +OBJECTS2 = notify.obj + +all: $(TARGET) $(TARGET2) + +!INCLUDE $(TOPDIR)\win32\Make.rules.mak + +$(TARGET): $(OBJECTS) + lib $(LIBFLAGS) /out:$(TARGET) $(OBJECTS) + +$(TARGET2): $(OBJECTS2) + lib $(LIBFLAGS) /out:$(TARGET2) $(OBJECTS2) diff -Nru opensc-0.17.0/src/ui/notify.c opensc-0.19.0/src/ui/notify.c --- opensc-0.17.0/src/ui/notify.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/notify.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,542 @@ +/* + * notify.c: Notification implementation + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "notify.h" + +#if defined(ENABLE_NOTIFY) && (defined(__APPLE__)) + +#include "libopensc/internal.h" +#include "libopensc/log.h" +#include +#include +#include +#include +#include + +static pid_t child = -1; + +void sc_notify_init(void) +{ +} + +void sc_notify_close(void) +{ + if (child > 0) { + int i, status; + for (i = 0; child != waitpid(child, &status, WNOHANG); i++) { + switch (i) { + case 0: + kill(child, SIGKILL); + break; + case 1: + kill(child, SIGTERM); + break; + default: + /* SIGTERM was our last resort */ + return; + } + usleep(100); + } + child = -1; + } +} + +#endif + +#if defined(ENABLE_NOTIFY) && defined(_WIN32) + +#include "common/compat_strlcpy.h" +#include "invisible_window.h" +#include "wchar_from_char_str.h" +#include +#include + +// {83C35893-99C6-4600-BFDB-45925C53BDD9} +static const GUID myGUID = { 0x83c35893, 0x99c6, 0x4600, { 0xbf, 0xdb, 0x45, 0x92, 0x5c, 0x53, 0xbd, 0xd9 } }; +HINSTANCE sc_notify_instance = NULL; +HWND sc_notify_hwnd = NULL; +BOOL delete_icon = TRUE; +#define IDI_SMARTCARD 102 +#define WMAPP_NOTIFYCALLBACK (WM_APP + 1) +static BOOL RestoreTooltip(); +void ShowContextMenu(HWND hwnd, POINT pt); + +// we need commctrl v6 for LoadIconMetric() +#include + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_COMMAND: + { + int const wmId = LOWORD(wParam); + // Parse the menu selection: + switch (wmId) + { + case WMAPP_EXIT: + break; + + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + } + break; + + case WMAPP_NOTIFYCALLBACK: + switch (LOWORD(lParam)) { + case NIN_BALLOONTIMEOUT: + case NIN_BALLOONUSERCLICK: + RestoreTooltip(); + break; + + case WM_CONTEXTMENU: + { + POINT const pt = { LOWORD(wParam), HIWORD(wParam) }; + ShowContextMenu(hwnd, pt); + } + break; + } + break; + + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + + return 0; +} + +static const char* lpszClassName = "NOTIFY_CLASS"; + +static BOOL AddNotificationIcon(void) +{ + NOTIFYICONDATA nid = {0}; + TCHAR path[MAX_PATH]={0}; + BOOL r; + + sc_notify_hwnd = create_invisible_window(lpszClassName, WndProc, + sc_notify_instance); + if (!sc_notify_hwnd) { + return FALSE; + } + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.hWnd = sc_notify_hwnd; + // add the icon, setting the icon, tooltip, and callback message. + // the icon will be identified with the GUID + nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP | NIF_GUID; + nid.guidItem = myGUID; + nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK; + LoadIconMetric(sc_notify_instance, MAKEINTRESOURCEW(IDI_SMARTCARD), LIM_SMALL, &nid.hIcon); + if (GetModuleFileName(NULL, path, ARRAYSIZE(path))) { + const char *basename = strrchr(path, '\\'); + if (basename) { + basename++; + if (0 != strcmp(basename, "opensc-notify.exe")) { + /* Allow creation of system tray icon only for + * "opensc-notify.exe" to avoid creation of the same icon by + * multiple processes. */ + delete_icon = FALSE; + return FALSE; + } + } + strlcpy(nid.szTip, path, ARRAYSIZE(nid.szTip)); + } else { + strcpy(nid.szTip, PACKAGE_NAME); + } + + r = Shell_NotifyIcon(NIM_ADD, &nid); + if (TRUE == r) { + nid.uVersion = NOTIFYICON_VERSION_4; + r = Shell_NotifyIcon(NIM_SETVERSION, &nid); + } + + return r; +} + +static BOOL DeleteNotificationIcon(void) +{ + BOOL r; + NOTIFYICONDATA nid = {0}; + + if (!delete_icon) { + return FALSE; + } + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.uFlags = NIF_GUID; + nid.guidItem = myGUID; + + r = Shell_NotifyIcon(NIM_DELETE, &nid); + + r &= delete_invisible_window(sc_notify_hwnd, lpszClassName, + sc_notify_instance); + sc_notify_hwnd = NULL; + + return r; +} + +static BOOL RestoreTooltip() +{ + // After the balloon is dismissed, restore the tooltip. + NOTIFYICONDATA nid = {0}; + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.uFlags = NIF_SHOWTIP | NIF_GUID; + nid.guidItem = myGUID; + + return Shell_NotifyIcon(NIM_MODIFY, &nid); +} + +void ShowContextMenu(HWND hwnd, POINT pt) +{ + HMENU hMenu; + hMenu=CreatePopupMenu(); + + if (hMenu) { + AppendMenu(hMenu, MF_STRING, WMAPP_EXIT, ui_get_str(NULL, NULL, NULL, NOTIFY_EXIT)); + + // our window must be foreground before calling TrackPopupMenu or the menu will not disappear when the user clicks away + SetForegroundWindow(hwnd); + + // respect menu drop alignment + UINT uFlags = TPM_RIGHTBUTTON; + if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0) { + uFlags |= TPM_RIGHTALIGN; + } else { + uFlags |= TPM_LEFTALIGN; + } + + TrackPopupMenuEx(hMenu, uFlags, pt.x, pt.y, hwnd, NULL); + } +} + + +static void notify_shell(struct sc_context *ctx, + const char *title, const char *text, LPCTSTR icon_path, int icon_index) +{ + NOTIFYICONDATA nid = {0}; + HICON icon = NULL; + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.uFlags = NIF_GUID; + nid.guidItem = myGUID; + + if (title) { + strlcpy(nid.szInfoTitle, title, ARRAYSIZE(nid.szInfoTitle)); + } + if (text) { + nid.uFlags |= NIF_INFO; + strlcpy(nid.szInfo, text, ARRAYSIZE(nid.szInfo)); + } + if (icon_path) { + ExtractIconEx(icon_path, icon_index, &icon, NULL, 1); + if (icon) { + nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; + nid.hBalloonIcon = icon; + } + } + + Shell_NotifyIcon(NIM_MODIFY, &nid); + + if (icon) { + DestroyIcon(icon); + } +} + +void sc_notify_init(void) +{ + if (!sc_notify_instance) { + /* returns the HINSTANCE of the exe. If the code executes in a DLL, + * sc_notify_instance_notify should be pre-initialized */ + sc_notify_instance = GetModuleHandle(NULL); + } + AddNotificationIcon(); +} + +void sc_notify_close(void) +{ + DeleteNotificationIcon(); +} + +void sc_notify(const char *title, const char *text) +{ + notify_shell(NULL, title, text, NULL, 0); +} + +void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id) +{ + const char *title, *text; + LPCTSTR icon_path = NULL; + int icon_index = 0; + title = ui_get_str(ctx, atr, p15card, id); + text = ui_get_str(ctx, atr, p15card, id+1); + + switch (id) { + case NOTIFY_CARD_INSERTED: + icon_path = TEXT("%SYSTEMROOT%\\system32\\SCardDlg.dll"); + icon_index = 3; + break; + case NOTIFY_CARD_REMOVED: + icon_path = TEXT("%SYSTEMROOT%\\system32\\SCardDlg.dll"); + icon_index = 2; + break; + case NOTIFY_PIN_GOOD: + icon_path = TEXT("%SYSTEMROOT%\\system32\\certmgr.dll"); + icon_index = 16; + break; + case NOTIFY_PIN_BAD: + icon_path = TEXT("%SYSTEMROOT%\\system32\\certmgr.dll"); + icon_index = 11; + break; + default: + break; + } + + notify_shell(ctx, title, text, icon_path, icon_index); +} + +#elif defined(ENABLE_NOTIFY) && defined(__APPLE__) + +static void notify_proxy(struct sc_context *ctx, + const char *title, const char* subtitle, + const char *text, const char *icon, const char *sound, + const char *group) +{ + /* terminal-notifier does not reliably activate keychain when clicked on + * the notification + * (https://github.com/julienXX/terminal-notifier/issues/196), that's why + * we're including NotificationProxy which has similar features */ + const char notificationproxy[] = "/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications/NotificationProxy.app/Contents/MacOS/NotificationProxy"; + + if (ctx && ctx->app_name + && (0 == strcmp(ctx->app_name, "opensc-pkcs11") + || 0 == strcmp(ctx->app_name, "onepin-opensc-pkcs11"))) { + /* some programs don't like forking when loading our PKCS#11 module, + * see https://github.com/OpenSC/OpenSC/issues/1174. + * TODO implementing an XPC service which sends the notification should + * work, though. See + * https://github.com/OpenSC/OpenSC/issues/1304#issuecomment-376656003 */ + return; + } + + if (child > 0) { + int status; + if (0 == waitpid(child, &status, WNOHANG)) { + kill(child, SIGKILL); + usleep(100); + if (0 == waitpid(child, &status, WNOHANG)) { + sc_log(ctx, "Can't kill %ld, skipping current notification", (long) child); + return; + } + } + } + + child = fork(); + switch (child) { + case 0: + /* child process */ + + /* for some reason the user _tokend can call brew's installation of + * terminal-notifier, but it cannot call `/usr/bin/open` with + * NotificationProxy.app that we're shipping... However, while + * `sudo -u _tokend /usr/local/bin/terminal-notifier -title test` + * works in the terminal, it hangs when executed from the tokend + * process. For now, we try to deliver the notification anyway + * making sure that we are waiting for only one forked process. */ + if (0 > execl(notificationproxy, notificationproxy, + title ? title : "", + subtitle ? subtitle : "", + text ? text : "", + icon ? icon : "", + group ? group : "", + sound ? sound : "", + (char *) NULL)) { + perror("exec failed"); + exit(0); + } + break; + case -1: + sc_log(ctx, "failed to fork for notification"); + break; + default: + if (ctx) { + sc_log(ctx, "Created %ld for notification:", (long) child); + sc_log(ctx, "%s %s %s %s %s %s %s", notificationproxy, + title ? title : "", + subtitle ? subtitle : "", + text ? text : "", + icon ? icon : "", + group ? group : "", + sound ? sound : ""); + } + break; + } +} + +void sc_notify(const char *title, const char *text) +{ + notify_proxy(NULL, title, NULL, text, NULL, NULL, NULL); +} + +void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id) +{ + const char *title, *text, *icon, *group; + title = ui_get_str(ctx, atr, p15card, id); + text = ui_get_str(ctx, atr, p15card, id+1); + + if (p15card && p15card->card && p15card->card->reader) { + group = p15card->card->reader->name; + } else { + group = ctx ? ctx->app_name : NULL; + } + + switch (id) { + case NOTIFY_CARD_INSERTED: + icon = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/VCard.icns"; + break; + case NOTIFY_CARD_REMOVED: + icon = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/EjectMediaIcon.icns"; + break; + case NOTIFY_PIN_GOOD: + icon = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/UnlockedIcon.icns"; + break; + case NOTIFY_PIN_BAD: + icon = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns"; + break; + default: + icon = NULL; + break; + } + + notify_proxy(ctx, title, NULL, text, icon, NULL, group); +} + +#elif defined(ENABLE_NOTIFY) && defined(ENABLE_GIO2) + +#include + +static GApplication *application = NULL; + +void sc_notify_init(void) +{ + sc_notify_close(); + application = g_application_new("org.opensc.notify", G_APPLICATION_NON_UNIQUE); + if (application) { + g_application_register(application, NULL, NULL); + } +} + +void sc_notify_close(void) +{ + if (application) { + g_object_unref(application); + application = NULL; + } +} + +static void notify_gio(struct sc_context *ctx, + const char *title, const char *text, const char *icon, + const char *group) +{ + if (application + && g_application_get_is_registered(application) + && g_application_get_dbus_connection(application)) { + GIcon *gicon = NULL; + GNotification *notification = g_notification_new(title); + if (!notification) { + return; + } + + if (text) { + g_notification_set_body(notification, text); + } + if (icon) { + gicon = g_themed_icon_new(icon); + if (gicon) { + g_notification_set_icon(notification, gicon); + } + } + + g_application_send_notification(application, group, notification); + + if (gicon) { + g_object_unref(gicon); + } + g_object_unref(notification); + } +} + +#else + +void sc_notify_init(void) {} +void sc_notify_close(void) {} +void sc_notify(const char *title, const char *text) {} +void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id) {} + +#endif + +#if defined(ENABLE_NOTIFY) && defined(ENABLE_GIO2) +void sc_notify(const char *title, const char *text) +{ + notify_gio(NULL, title, text, NULL, NULL); +} + +void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id) +{ + const char *title, *text, *icon, *group; + title = ui_get_str(ctx, atr, p15card, id); + text = ui_get_str(ctx, atr, p15card, id+1); + + if (p15card && p15card->card && p15card->card->reader) { + group = p15card->card->reader->name; + } else { + group = ctx ? ctx->app_name : NULL; + } + + switch (id) { + case NOTIFY_CARD_INSERTED: + icon = "contact-new"; + break; + case NOTIFY_CARD_REMOVED: + icon = "media-eject"; + break; + case NOTIFY_PIN_GOOD: + icon = "changes-allow"; + break; + case NOTIFY_PIN_BAD: + icon = "changes-prevent"; + break; + default: + icon = NULL; + break; + } + + notify_gio(ctx, title, text, icon, group); +} + +#endif diff -Nru opensc-0.17.0/src/ui/notify.h opensc-0.19.0/src/ui/notify.h --- opensc-0.17.0/src/ui/notify.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/notify.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * notify.h: OpenSC library header file + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NOTIFY_H +#define _NOTIFY_H + +#include "ui/strings.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void sc_notify_init(void); +void sc_notify_close(void); +void sc_notify(const char *title, const char *text); +void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id); + +#ifdef _WIN32 +#include +/* If the code executes in a DLL, `sc_notify_instance_notify` should be + * initialized before calling `sc_notify_init()`. If not initialized, we're + * using the HINSTANCE of the EXE */ +extern HINSTANCE sc_notify_instance; +/* This is the message created when the user clicks on "exit". */ +#define WMAPP_EXIT (WM_APP + 2) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru opensc-0.17.0/src/ui/strings.c opensc-0.19.0/src/ui/strings.c --- opensc-0.17.0/src/ui/strings.c 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/strings.c 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,318 @@ +/* + * strings.c: Implementation of default UI strings + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "libopensc/internal.h" +#include "ui/strings.h" +#include +#include +#include + +enum ui_langs { + EN, + DE, +}; + +static const char *get_inserted_text(struct sc_pkcs15_card *p15card, struct sc_atr *atr) +{ + static char text[3*SC_MAX_ATR_SIZE] = {0}; + const char prefix[] = "ATR: "; + + if (p15card && p15card->card && p15card->card->name) { + return p15card->card->name; + } + + if (!atr) + return NULL; + + strcpy(text, prefix); + sc_bin_to_hex(atr->value, atr->len, text + (sizeof prefix) - 1, + sizeof(text) - (sizeof prefix) - 1, ':'); + + return text; +} + +static const char *get_removed_text(struct sc_pkcs15_card *p15card) +{ + if (p15card && p15card->card && p15card->card->reader + && p15card->card->reader->name) { + return p15card->card->reader->name; + } + + return NULL; +} + +static const char *ui_get_config_str(struct sc_context *ctx, + struct sc_atr *atr, const char *flag_name, const char *ret_default) +{ + const char *ret = ret_default; + + scconf_block *atrblock = _sc_match_atr_block(ctx, NULL, atr); + + if (atrblock) + ret = scconf_get_str(atrblock, flag_name, ret_default); + + return ret; +} + +static int find_lang_str(const char *str, enum ui_langs *lang) +{ + if (str) { + if (0 == strncmp(str, "de", 2)) { + if (lang) { + *lang = DE; + } + return 1; + } else if (0 == strncmp(str, "en", 2)) { + if (lang) { + *lang = EN; + } + return 1; + } + } + + return 0; +} + +const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id) +{ + enum ui_langs lang = EN; + const char *str, *option; + + /* load option strings */ + switch (id) { + case MD_PINPAD_DLG_TITLE: + option = "md_pinpad_dlg_title"; + break; + case MD_PINPAD_DLG_MAIN: + option = "md_pinpad_dlg_main"; + break; + case MD_PINPAD_DLG_CONTENT_USER: + option = "md_pinpad_dlg_content_user"; + break; + case MD_PINPAD_DLG_CONTENT_USER_SIGN: + option = "md_pinpad_dlg_content_user_sign"; + break; + case MD_PINPAD_DLG_CONTENT_ADMIN: + option = "md_pinpad_dlg_content_admin"; + break; + case MD_PINPAD_DLG_EXPANDED: + option = "md_pinpad_dlg_expanded"; + break; + case MD_PINPAD_DLG_ICON: + option = "md_pinpad_dlg_icon"; + break; + case NOTIFY_CARD_INSERTED: + option = "notify_card_inserted"; + break; + case NOTIFY_CARD_INSERTED_TEXT: + option = "notify_card_inserted_text"; + break; + case NOTIFY_CARD_REMOVED: + option = "notify_card_removed"; + break; + case NOTIFY_CARD_REMOVED_TEXT: + option = "notify_card_removed_text"; + break; + case NOTIFY_PIN_GOOD: + option = "notify_pin_good"; + break; + case NOTIFY_PIN_GOOD_TEXT: + option = "notify_pin_good_text"; + break; + case NOTIFY_PIN_BAD: + option = "notify_pin_bad"; + break; + case NOTIFY_PIN_BAD_TEXT: + option = "notify_pin_bad_text"; + break; + case MD_PINPAD_DLG_VERIFICATION: + option = "md_pinpad_dlg_verification"; + break; + default: + option = NULL; + break; + } + + /* load language */ + /* card's language supersedes system's language */ + if (!p15card || !p15card->tokeninfo + || !find_lang_str(p15card->tokeninfo->preferred_language, &lang)) { +#ifdef _WIN32 + LANGID langid = GetUserDefaultUILanguage(); + if (langid & LANG_GERMAN) { + lang = DE; + } +#else + /* LANGUAGE supersedes locale */ + if (!find_lang_str(getenv("LANGUAGE"), &lang)) { + /* XXX Should we use LC_MESSAGES instead? */ + find_lang_str(setlocale(LC_ALL, ""), &lang); + } +#endif + } + + /* load default strings */ + switch (lang) { + case DE: + switch (id) { + case MD_PINPAD_DLG_TITLE: + str = "Windows-Sicherheit"; + break; + case MD_PINPAD_DLG_MAIN: + str = "OpenSC Smartcard-Anbieter"; + break; + case MD_PINPAD_DLG_CONTENT_USER: + str = "Bitte geben Sie Ihre PIN auf dem PIN-Pad ein."; + break; + case MD_PINPAD_DLG_CONTENT_USER_SIGN: + str = "Bitte geben Sie Ihre PIN für die digitale Signatur auf dem PIN-Pad ein."; + break; + case MD_PINPAD_DLG_CONTENT_ADMIN: + str = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein."; + break; + case MD_PINPAD_DLG_EXPANDED: + str = "Dieses Fenster wird automatisch geschlossen, wenn die PIN am PIN-Pad eingegeben wurde (Timeout typischerweise nach 30 Sekunden)."; + break; + case NOTIFY_CARD_INSERTED: + if (p15card) { + str = "Smartcard kann jetzt verwendet werden"; + } else { + str = "Smartcard erkannt"; + } + break; + case NOTIFY_CARD_INSERTED_TEXT: + str = get_inserted_text(p15card, atr); + break; + case NOTIFY_CARD_REMOVED: + str = "Smartcard entfernt"; + break; + case NOTIFY_CARD_REMOVED_TEXT: + str = get_removed_text(p15card); + break; + case NOTIFY_PIN_GOOD: + str = "PIN verifiziert"; + break; + case NOTIFY_PIN_GOOD_TEXT: + str = "Smartcard ist entsperrt"; + break; + case NOTIFY_PIN_BAD: + str = "PIN nicht verifiziert"; + break; + case NOTIFY_PIN_BAD_TEXT: + str = "Smartcard ist gesperrt"; + break; + case MD_PINPAD_DLG_VERIFICATION: + str = "Sofort PIN am PIN-Pad abfragen"; + break; + + case MD_PINPAD_DLG_CONTROL_COLLAPSED: + case MD_PINPAD_DLG_CONTROL_EXPANDED: + str = "Weitere Informationen"; + break; + case MD_PINPAD_DLG_CANCEL: + str = "Abbrechen"; + break; + case NOTIFY_EXIT: + str = "Beenden"; + break; + default: + str = NULL; + break; + } + break; + case EN: + default: + switch (id) { + case MD_PINPAD_DLG_TITLE: + str = "Windows Security"; + break; + case MD_PINPAD_DLG_MAIN: + str = "OpenSC Smart Card Provider"; + break; + case MD_PINPAD_DLG_CONTENT_USER: + str = "Please enter your PIN on the PIN pad."; + break; + case MD_PINPAD_DLG_CONTENT_USER_SIGN: + str = "Please enter your digital signature PIN on the PIN pad."; + break; + case MD_PINPAD_DLG_CONTENT_ADMIN: + str = "Please enter your PIN to unblock the user PIN on the PIN pad."; + break; + case MD_PINPAD_DLG_EXPANDED: + str = "This window will be closed automatically after the PIN has been submitted on the PIN pad (timeout typically after 30 seconds)."; + break; + case NOTIFY_CARD_INSERTED: + if (p15card) { + str = "Smart card is ready to use"; + } else { + str = "Smart card detected"; + } + break; + case NOTIFY_CARD_INSERTED_TEXT: + str = get_inserted_text(p15card, atr); + break; + case NOTIFY_CARD_REMOVED: + str = "Smart card removed"; + break; + case NOTIFY_CARD_REMOVED_TEXT: + str = get_removed_text(p15card); + break; + case NOTIFY_PIN_GOOD: + str = "PIN verified"; + break; + case NOTIFY_PIN_GOOD_TEXT: + str = "Smart card is unlocked"; + break; + case NOTIFY_PIN_BAD: + str = "PIN not verified"; + break; + case NOTIFY_PIN_BAD_TEXT: + str = "Smart card is locked"; + break; + case MD_PINPAD_DLG_VERIFICATION: + str = "Immediately request PIN on PIN-Pad"; + break; + + case MD_PINPAD_DLG_CONTROL_COLLAPSED: + case MD_PINPAD_DLG_CONTROL_EXPANDED: + str = "Click here for more information"; + break; + case MD_PINPAD_DLG_CANCEL: + str = "Cancel"; + break; + case NOTIFY_EXIT: + str = "Exit"; + break; + default: + str = NULL; + break; + } + break; + } + + /* user's strings supersede default strings */ + if (option != NULL) { + /* overwrite str with the user's choice */ + str = ui_get_config_str(ctx, atr, option, str); + } + + return str; +} diff -Nru opensc-0.17.0/src/ui/strings.h opensc-0.19.0/src/ui/strings.h --- opensc-0.17.0/src/ui/strings.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/strings.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * strings.c: default UI strings + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SC_STRINGS_H +#define _SC_STRINGS_H + +#include "libopensc/pkcs15.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum ui_str { + MD_PINPAD_DLG_TITLE, + MD_PINPAD_DLG_MAIN, + MD_PINPAD_DLG_CONTENT_USER, + MD_PINPAD_DLG_CONTENT_ADMIN, + MD_PINPAD_DLG_EXPANDED, + MD_PINPAD_DLG_CONTROL_COLLAPSED, + MD_PINPAD_DLG_CONTROL_EXPANDED, + MD_PINPAD_DLG_ICON, + MD_PINPAD_DLG_CANCEL, + NOTIFY_CARD_INSERTED, + NOTIFY_CARD_INSERTED_TEXT, + NOTIFY_CARD_REMOVED, + NOTIFY_CARD_REMOVED_TEXT, + NOTIFY_PIN_GOOD, + NOTIFY_PIN_GOOD_TEXT, + NOTIFY_PIN_BAD, + NOTIFY_PIN_BAD_TEXT, + MD_PINPAD_DLG_CONTENT_USER_SIGN, + NOTIFY_EXIT, + MD_PINPAD_DLG_VERIFICATION, +}; + +const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, + struct sc_pkcs15_card *p15card, enum ui_str id); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru opensc-0.17.0/src/ui/wchar_from_char_str.h opensc-0.19.0/src/ui/wchar_from_char_str.h --- opensc-0.17.0/src/ui/wchar_from_char_str.h 1970-01-01 00:00:00.000000000 +0000 +++ opensc-0.19.0/src/ui/wchar_from_char_str.h 2018-09-13 11:47:21.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * wchar_from_char_str.h: Conversion from string to wide string + * + * Copyright (C) 2017 Frank Morgner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static WCHAR *wchar_from_char_str(const char *in) +{ + WCHAR *out; + int out_len; + + if (!in) + return NULL; + + out_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0); + if (0 >= out_len) + return NULL; + + out = LocalAlloc(0, (sizeof *out) * out_len); + if (!out) + return NULL; + + out_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, out, out_len); + if (out_len == 0xFFFD || 0 >= out_len) { + LocalFree(out); + return NULL; + } + + return out; +} diff -Nru opensc-0.17.0/.travis.yml opensc-0.19.0/.travis.yml --- opensc-0.17.0/.travis.yml 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/.travis.yml 2018-09-13 11:47:21.000000000 +0000 @@ -1,7 +1,5 @@ language: c -sudo: false - addons: apt_packages: - binutils-mingw-w64-i686 @@ -14,26 +12,28 @@ - wine - xsltproc - gengetopt - - help2man - coverity_scan: - project: - name: "OpenSC/OpenSC" - description: "Build submitted via Travis CI" - notification_email: viktor.tarasov@gmail.com - build_command: "make -j 4" - branch_pattern: coverity_scan + - libcmocka-dev env: global: - # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created - # via the "travis encrypt" command using the project repo's public key + # The next declaration are encrypted envirnmet variables, created via the + # "travis encrypt" command using the project repo's public key + # COVERITY_SCAN_TOKEN - secure: "UkHn7wy4im8V1nebCWbAetnDSOLRUbOlF6++ovk/7Bnso1/lnhXHelyzgRxfD/oI68wm9nnRV+RQEZ9+72Ug1CyvHxyyxxkwal/tPeHH4B/L+aGdPi0id+5OZSKIm77VP3m5s102sJMJgH7DFd03+nUd0K26p0tk8ad4j1geV4c=" + # GH_TOKEN + - secure: "cUAvpN/XUPMIN5cgWAbIOhghRoLXyw7SCydzGaJ1Ucqb9Ml2v5iuLLuN57YbZHTiWw03vy6rYVzzwMDrHX8r3oUALsv7ViJHG4PzIe7fAFZsZpHECmGsp6SEnue7m7BNy3FT8KYbiXxnxDO0SxmFXlrPAYR0WMZCWx2TENYcafs=" + - COVERITY_SCAN_BRANCH_PATTERN="(master|coverity.*)" + - COVERITY_SCAN_NOTIFICATION_EMAIL="viktor.tarasov@gmail.com" + - COVERITY_SCAN_BUILD_COMMAND="make -j 4" + - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG" + - SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) matrix: fast_finish: true include: - compiler: clang os: osx + env: DO_PUSH_ARTIFACT=yes - compiler: gcc os: osx - compiler: clang @@ -43,24 +43,25 @@ os: linux env: ENABLE_DOC=--enable-doc - os: linux - env: HOST=x86_64-w64-mingw32 + env: + - HOST=x86_64-w64-mingw32 + - DO_PUSH_ARTIFACT=yes + - os: linux + env: + - HOST=i686-w64-mingw32 + - DO_PUSH_ARTIFACT=yes - os: linux - env: HOST=i686-w64-mingw32 + env: DO_COVERITY_SCAN=yes before_install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew uninstall libtool; brew install libtool; - brew install gengetopt help2man; + brew install gengetopt help2man cmocka; fi before_script: - # we run a weekly cron job in travis on the coverity branch - # just synchronize it with master to get a new report - - if [ "${COVERITY_SCAN_BRANCH}" == 1 ]; then - git reset --hard origin/master; - fi - ./bootstrap - if [ -z "$HOST" ]; then CFLAGS="-Werror" ./configure $ENABLE_DOC --enable-dnie-ui; @@ -73,22 +74,24 @@ fi; unset CC; unset CXX; - ./configure --host=$HOST --disable-openssl --disable-readline --disable-zlib --prefix=${TRAVIS_BUILD_DIR}/win32/opensc || cat config.log; + ./configure --host=$HOST --disable-openssl --disable-readline --disable-zlib --disable-notify --prefix=${TRAVIS_BUILD_DIR}/win32/opensc || cat config.log; fi + # Optionally try to upload to Coverity Scan + # On error (propably quota is exhausted), just continue + - if [ "${DO_COVERITY_SCAN}" = "yes" ]; then curl -s 'https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh' | bash || true; fi script: - - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then + - if [ "${DO_COVERITY_SCAN}" != "yes" ]; then if [ $TRAVIS_OS_NAME == osx ]; then ./MacOSX/build; else make; fi; fi - - if [ -z "$HOST" -a "${COVERITY_SCAN_BRANCH}" != 1 ]; then - make check; - make dist; + - if [ -z "$HOST" -a "${DO_COVERITY_SCAN}" != "yes" ]; then + make check && make dist; fi - - if [ ! -z "$HOST" -a "${COVERITY_SCAN_BRANCH}" != 1 ]; then + - if [ ! -z "$HOST" -a "${DO_COVERITY_SCAN}" != "yes" ]; then make install; wine "C:/Program Files (x86)/Inno Setup 5/ISCC.exe" win32/OpenSC.iss; fi @@ -100,4 +103,11 @@ killall services.exe; fi + # keep in sync with appveyor.yml + - if [ "${DO_PUSH_ARTIFACT}" = "yes" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then + git config --global user.email "builds@travis-ci.org"; + git config --global user.name "Travis CI"; + .github/push_artifacts.sh "Travis CI build ${TRAVIS_JOB_NUMBER}"; + fi + cache: ccache diff -Nru opensc-0.17.0/version.m4 opensc-0.19.0/version.m4 --- opensc-0.17.0/version.m4 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/version.m4 2018-09-13 11:47:21.000000000 +0000 @@ -1,11 +1,5 @@ -dnl define the OpenSC version -define([PRODUCT_NAME], [OpenSC]) -define([PRODUCT_TARNAME], [opensc]) -define([PRODUCT_BUGREPORT], [opensc-devel@lists.sourceforge.net]) +dnl version.m4 - source for version.m4.ci generated by bootstrap.ci +dnl * bootstrap.ci generates version.m4.ci based on this file +dnl * if version.m4.ci exists, it is included in configure.ac define([PACKAGE_SUFFIX], []) -define([VS_FF_LEGAL_COPYRIGHT], [OpenSC Project]) -define([VS_FF_LEGAL_COMPANY_NAME], [OpenSC Project]) -define([VS_FF_COMMENTS], [Provided under the terms of the GNU Lesser General Public License (LGPLv2.1+).]) -define([VS_FF_PRODUCT_NAME], [OpenSC smartcard framework]) - diff -Nru opensc-0.17.0/win32/customactions.cpp opensc-0.19.0/win32/customactions.cpp --- opensc-0.17.0/win32/customactions.cpp 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/customactions.cpp 2018-09-13 11:47:21.000000000 +0000 @@ -64,17 +64,15 @@ For example, do not uninstall the minidriver for a card if a middleware is already installed */ MD_REGISTRATION minidriver_registration[] = { - /* from minidriver-feitian.reg */ {TEXT("ePass2003"), {0x3b,0x9f,0x95,0x81,0x31,0xfe,0x9f,0x00,0x66,0x46,0x53,0x05,0x01,0x00,0x11,0x71,0xdf,0x00,0x00,0x03,0x6a,0x82,0xf8}, 23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, {TEXT("FTCOS/PK-01C"), {0x3b,0x9f,0x95,0x81,0x31,0xfe,0x9f,0x00,0x65,0x46,0x53,0x05,0x00,0x06,0x71,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}}, - /* from minidriver-sc-hsm.reg */ {TEXT("SmartCard-HSM"), {0x3b,0xfe,0x18,0x00,0x00,0x81,0x31,0xfe,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4d,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xfa}, 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}, + {TEXT("Contactless Smart Card"), {0x3B,0x80,0x80,0x01,0x01}, 5, {0xff,0xff,0xff,0xff,0xff}}, {TEXT("GoID"), {0x3B,0x84,0x80,0x01,0x47,0x6f,0x49,0x44,0x00}, 9, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00}}, @@ -100,13 +98,16 @@ 19, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, {TEXT("GoID (11)"), {0x3B,0x8f,0x80,0x01,0x47,0x6f,0x49,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 20, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - /* 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}}, /* from card-openpgp.c */ - {TEXT("OpenPGP card v1.0/1.1"), {0x3b,0xfa,0x13,0x00,0xff,0x81,0x31,0x80,0x45,0x00,0x31,0xc1,0x73,0xc0,0x01,0x00,0x00,0x90,0x00,0xb1}, + {TEXT("OpenPGP card v1.x"), {0x3b,0xfa,0x13,0x00,0xff,0x81,0x31,0x80,0x45,0x00,0x31,0xc1,0x73,0xc0,0x01,0x00,0x00,0x90,0x00,0xb1}, 20, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, - {TEXT("CryptoStick v1.2 (OpenPGP v2.0)"), {0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xc5,0x73,0xc0,0x01,0x40,0x00,0x90,0x00,0x0c}, + {TEXT("OpenPGP card v2.x"), {0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xc5,0x73,0xc0,0x01,0x40,0x00,0x90,0x00,0x0c}, + 21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("Gnuk v1.0.x (OpenPGP v2.0)"), {0x3b,0xda,0x11,0xff,0x81,0xb1,0xfe,0x55,0x1f,0x03,0x00,0x31,0x84,0x73,0x80,0x01,0x80,0x00,0x90,0x00,0xe4}, + 21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0x00}}, + {TEXT("OpenPGP card v3.x"), {0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xf5,0x73,0xc0,0x01,0x60,0x00,0x90,0x00,0x1c}, 21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, /* from card-masktech.c */ /* note: the card name MUST be unique */ @@ -120,12 +121,14 @@ /* from card-cardos.c */ {TEXT("CardOS 4.0"), {0x3b,0xe2,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0xc8,0x02,0x9c}, 12, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, - {TEXT("Italian eID card, postecert"), {0x3b,0xe9,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x00,0xc8,0x02,0x31,0x80,0x00,0x47}, + {TEXT("Italian CNS (a)"), {0x3b,0xe9,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x00,0xc8,0x02,0x31,0x80,0x00,0x47}, 19, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, - {TEXT("Italian eID card, infocamere"), {0x3b,0xfb,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x20,0x47,0x03,0x31,0x80,0x00,0x90,0x00,0xf3}, + {TEXT("Italian CNS (b)"), {0x3b,0xfb,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x20,0x47,0x03,0x31,0x80,0x00,0x90,0x00,0xf3}, 22, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, - {TEXT("Italian InfocamereCard"), {0x3b,0xfc,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0xc8,0x03,0x49,0x6e,0x66,0x6f,0x63,0x61,0x6d,0x65,0x72,0x65,0x28}, + {TEXT("Italian CNS (c)"), {0x3b,0xfc,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0xc8,0x03,0x49,0x6e,0x66,0x6f,0x63,0x61,0x6d,0x65,0x72,0x65,0x28}, 23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("Italian CNS (d)"), {0x3b,0xff,0x18,0x00,0xff,0x81,0x31,0xfe,0x55,0x00,0x6b,0x02,0x09,0x03,0x03,0x01,0x01,0x01,0x43,0x4e,0x53,0x10,0x31,0x80,0x9d}, + 25, {0xff,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("CardOS 4.0 a"), {0x3b,0xf4,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x4d,0x34,0x63,0x76,0xb4}, 15, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, {TEXT("Cardos M4"), {0x3b,0xf2,0x18,0x00,0x02,0xc1,0x0a,0x31,0xfe,0x58,0xc8,0x08,0x74}, @@ -135,7 +138,29 @@ {TEXT("CardOS v5.0"), {0x3b,0xd2,0x18,0x00,0x81,0x31,0xfe,0x58,0xc9,0x01,0x14}, 11, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, {TEXT("JPKI"), {0x3b,0xe0,0x00,0xff,0x81,0x31,0xfe,0x45,0x14}, - 9, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + 9, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + + /* from card-starcos.c */ + {TEXT("STARCOS (a)"), {0x3B,0xB7,0x94,0x00,0xc0,0x24,0x31,0xfe,0x65,0x53,0x50,0x4b,0x32,0x33,0x90,0x00,0xb4}, + 17, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS (b)"), {0x3B,0xB7,0x94,0x00,0x81,0x31,0xfe,0x65,0x53,0x50,0x4b,0x32,0x33,0x90,0x00,0xd1}, + 16, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS (c)"), {0x3b,0xb7,0x18,0x00,0xc0,0x3e,0x31,0xfe,0x65,0x53,0x50,0x4b,0x32,0x34,0x90,0x00,0x25}, + 17, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS 3.4"), {0x3b,0xd8,0x18,0xff,0x81,0xb1,0xfe,0x45,0x1f,0x03,0x80,0x64,0x04,0x1a,0xb4,0x03,0x81,0x05,0x61}, + 19, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS 3.5 (a)"), {0x3B,0x9B,0x96,0xC0,0x0A,0x31,0xFE,0x45,0x80,0x67,0x04,0x1E,0xB5,0x01,0x00,0x89,0x4C,0x81,0x05,0x45}, + 20, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS 3.5 (b)"), {0x3B,0xDB,0x96,0xFF,0x81,0x31,0xFE,0x45,0x80,0x67,0x05,0x34,0xB5,0x02,0x01,0xC0,0xA1,0x81,0x05,0x3C}, + 20, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS 3.5 (c)"), {0x3B,0xD9,0x96,0xFF,0x81,0x31,0xFE,0x45,0x80,0x31,0xB8,0x73,0x86,0x01,0xC0,0x81,0x05,0x02}, + 18, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("STARCOS 3.5 (d)"), {0x3B,0xDF,0x96,0xFF,0x81,0x31,0xFE,0x45,0x80,0x5B,0x44,0x45,0x2E,0x42,0x4E,0x4F,0x54,0x4B,0x31,0x31,0x31,0x81,0x05,0xA0}, + 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("STARCOS 3.5 (e)"), {0x3B,0xDF,0x96,0xFF,0x81,0x31,0xFE,0x45,0x80,0x5B,0x44,0x45,0x2E,0x42,0x4E,0x4F,0x54,0x4B,0x31,0x30,0x30,0x81,0x05,0xA0}, + 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("STARCOS 3.5 (f)"), {0x3B,0xD9,0x96,0xFF,0x81,0x31,0xFE,0x45,0x80,0x31,0xB8,0x73,0x86,0x01,0xE0,0x81,0x05,0x22}, + 18, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, }; @@ -254,8 +279,18 @@ VOID RegisterSmartCard(PMD_REGISTRATION registration) { - RegisterCardWithKey(SC_DATABASE, registration->szName, TEXT("opensc-minidriver.dll"),registration->pbAtr, registration->dwAtrSize, registration->pbAtrMask ); + DWORD expanded_len = PATH_MAX; + TCHAR expanded_val[PATH_MAX]; + PTSTR szPath = TEXT("C:\\Program Files\\OpenSC Project\\OpenSC\\minidriver\\opensc-minidriver.dll"); + + /* cope with x86 installation on x64 */ + expanded_len = ExpandEnvironmentStrings( + TEXT("%ProgramFiles%\\OpenSC Project\\OpenSC\\minidriver\\opensc-minidriver.dll"), + expanded_val, expanded_len); + if (0 < expanded_len && expanded_len < sizeof expanded_val) + szPath = expanded_val; + RegisterCardWithKey(SC_DATABASE, registration->szName, szPath, registration->pbAtr, registration->dwAtrSize, registration->pbAtrMask ); } UINT WINAPI AddSmartCardConfiguration(MSIHANDLE hInstall) Binary files /tmp/tmp8cIdBX/DwE453RpuS/opensc-0.17.0/win32/DDORes.dll_14_2302.ico and /tmp/tmp8cIdBX/coIhbhAT2o/opensc-0.19.0/win32/DDORes.dll_14_2302.ico differ diff -Nru opensc-0.17.0/win32/Makefile.am opensc-0.19.0/win32/Makefile.am --- opensc-0.17.0/win32/Makefile.am 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/Makefile.am 2018-09-13 11:47:21.000000000 +0000 @@ -1,11 +1,11 @@ include $(top_srcdir)/win32/ltrc.inc MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo.rc $(srcdir)/winconfig.h \ - $(srcdir)/OpenSC.iss $(srcdir)/OpenSC.wxs $(srcdir)/OpenSC.ico \ - $(srcdir)/dlgbmp.bmp $(srcdir)/bannrbmp.bmp $(srcdir)/versioninfo-customactions.rc -EXTRA_DIST = ltrc.inc Makefile.mak Make.rules.mak \ - versioninfo.rc.in winconfig.h.in OpenSC.iss.in OpenSC.wxs.in versioninfo-customactions.rc.in -dist_noinst_HEADERS = versioninfo.rc winconfig.h OpenSC.iss OpenSC.wxs OpenSC.ico dlgbmp.bmp bannrbmp.bmp + $(srcdir)/OpenSC.iss $(srcdir)/OpenSC.wxs $(srcdir)/versioninfo-customactions.rc +EXTRA_DIST = ltrc.inc Makefile.mak Make.rules.mak versioninfo.rc.in winconfig.h.in \ + OpenSC.iss.in OpenSC.wxs.in versioninfo-customactions.rc.in \ + OpenSC.ico dlgbmp.bmp bannrbmp.bmp DDORes.dll_14_2302.ico +dist_noinst_HEADERS = versioninfo.rc winconfig.h OpenSC.iss OpenSC.wxs if ENABLE_MINIDRIVER_SETUP_CUSTOMACTION lib_LTLIBRARIES = customactions@LIBRARY_BITNESS@.la diff -Nru opensc-0.17.0/win32/Make.rules.mak opensc-0.19.0/win32/Make.rules.mak --- opensc-0.17.0/win32/Make.rules.mak 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/Make.rules.mak 2018-09-13 11:47:21.000000000 +0000 @@ -20,6 +20,9 @@ WIX_INCL_DIR = "/I$(WIX)\SDK\$(WIXVSVER)\inc" WIX_LIBS = "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\dutil.lib" "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\wcautil.lib" +# We do not build tests on windows +#TESTS_DEF = /DENABLE_TESTS + #Include support for Secure Messaging SM_DEF = /DENABLE_SM @@ -44,9 +47,29 @@ OPENSSL_STATIC_DIR = static !IF "$(DEBUG_DEF)" == "/DDEBUG" -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib +!IF "$(PLATFORM)" == "x86" +# OpenSSL 1.0.2 +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +# OpenSSL 1.1.0 +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +!ELSE +# OpenSSL 1.0.2 +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +# OpenSSL 1.1.0 +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +!ENDIF !ELSE -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib +!IF "$(PLATFORM)" == "x86" +# OpenSSL 1.0.2 +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +# OpenSSL 1.1.0 +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +!ELSE +# OpenSSL 1.0.2 +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +# OpenSSL 1.1.0 +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +!ENDIF !ENDIF PROGRAMS_OPENSSL = cryptoflex-tool.exe pkcs15-init.exe netkey-tool.exe piv-tool.exe \ @@ -86,7 +109,7 @@ # If you want support for EAC: # - Download OpenPACE and # - uncomment the line starting with OPENPACE_DEF -# - set the OPENPACE_INCL_DIR below to the OpenPACE include directory preceeded by "/I" +# - set the OPENPACE_INCL_DIR below to the OpenPACE include directory preceded by "/I" # - set the OPENPACE_LIB below to your OpenPACE lib file #OPENPACE_DEF= /DENABLE_OPENPACE !IF "$(OPENPACE_DEF)" == "/DENABLE_OPENPACE" @@ -117,14 +140,14 @@ !IF "$(DEBUG_DEF)" == "/DDEBUG" LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMT /DEBUG CODE_OPTIMIZATION = -COPTS = /GS /W3 /D_CRT_SECURE_NO_DEPRECATE /MTd /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /D_WIN32_WINNT=0x0502 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /DDEBUG /Zi /Od +COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MTd /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) $(TESTS_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /DDEBUG /Zi /Od !ELSE -LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMTD -COPTS = /GS /W3 /D_CRT_SECURE_NO_DEPRECATE /MT /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /D_WIN32_WINNT=0x0502 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" +LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMTD /DEBUG /OPT:REF /OPT:ICF +COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MT /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) $(TESTS_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /Zi !ENDIF -LINKFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:$(PLATFORM) /MANIFEST:NO /NODEFAULTLIB:MSVCRTD /NODEFAULTLIB:MSVCRT /NXCOMPAT /DYNAMICBASE $(LINKDEBUGFLAGS) +LINKFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:$(PLATFORM) /NODEFAULTLIB:MSVCRTD /NODEFAULTLIB:MSVCRT /NXCOMPAT /DYNAMICBASE $(LINKDEBUGFLAGS) LIBFLAGS = /nologo /machine:$(PLATFORM) !IF "$(PLATFORM)" == "x86" CANDLEFLAGS = -dPlatform=x86 $(CANDLEFLAGS) @@ -142,4 +165,4 @@ rc /l 0x0409 $< clean:: - del /Q *.obj *.dll *.exe *.pdb *.lib *.def *.manifest *.res + del /Q *.obj *.dll *.exe *.pdb *.lib *.def *.res diff -Nru opensc-0.17.0/win32/OpenSC.wxs.in opensc-0.19.0/win32/OpenSC.wxs.in --- opensc-0.17.0/win32/OpenSC.wxs.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/OpenSC.wxs.in 2018-09-13 11:47:21.000000000 +0000 @@ -7,7 +7,6 @@ - @@ -17,7 +16,6 @@ - @@ -58,54 +56,22 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - + @@ -113,6 +79,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -123,18 +130,27 @@ + + + + + + + + + @@ -288,6 +304,15 @@ + + + + + + + + + @@ -303,6 +328,7 @@ + @@ -325,13 +351,17 @@ + + + + diff -Nru opensc-0.17.0/win32/versioninfo.rc.in opensc-0.19.0/win32/versioninfo.rc.in --- opensc-0.17.0/win32/versioninfo.rc.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/versioninfo.rc.in 2018-09-13 11:47:21.000000000 +0000 @@ -27,7 +27,7 @@ VALUE "ProductName", "@OPENSC_VS_FF_PRODUCT_NAME@" VALUE "ProductVersion", "@OPENSC_VERSION_MAJOR@,@OPENSC_VERSION_MINOR@,@OPENSC_VERSION_FIX@,@OPENSC_VERSION_REVISION@" VALUE "SpecialBuild", "" - VALUE "FileDescription", "OpenSC common usage application extention" + VALUE "FileDescription", "OpenSC common usage application extension" END END BLOCK "VarFileInfo" diff -Nru opensc-0.17.0/win32/winconfig.h.in opensc-0.19.0/win32/winconfig.h.in --- opensc-0.17.0/win32/winconfig.h.in 2017-07-18 14:29:50.000000000 +0000 +++ opensc-0.19.0/win32/winconfig.h.in 2018-09-13 11:47:21.000000000 +0000 @@ -7,6 +7,13 @@ #include #include +#ifdef _MSC_VER +// TODO fix data truncation instead of disabling them +// VC++ 2015 changes truncation warnings from 4244 to 4267. +#pragma warning (disable : 4267) +#pragma warning (disable : 4244) +#endif + #ifndef strcasecmp #define strcasecmp stricmp #endif @@ -15,48 +22,12 @@ #define strncasecmp strnicmp #endif -#ifndef snprintf -#define snprintf _snprintf -#endif - #ifndef vsnprintf #define vsnprintf _vsnprintf #endif -#ifndef isatty -#define isatty _isatty -#endif - -#ifndef strnicmp -#define strnicmp _strnicmp -#endif - -#ifndef stricmp -#define stricmp _stricmp -#endif - -#ifndef strdup -#define strdup _strdup -#endif - -#ifndef fileno -#define fileno _fileno -#endif - -#ifndef mkdir -#define mkdir _mkdir -#endif - -#ifndef access -#define access _access -#endif - -#ifndef unlink -#define unlink _unlink -#endif - -#ifndef putenv -#define putenv _putenv +#ifndef snprintf +#define snprintf _snprintf #endif #ifndef R_OK @@ -82,6 +53,8 @@ #define DEFAULT_PCSC_PROVIDER "@DEFAULT_PCSC_PROVIDER@" #endif +#define ENABLE_NOTIFY + #define SC_PKCS15_PROFILE_DIRECTORY "C:\\Program Files\\OpenSC Project\\OpenSC\\profiles" #define PATH_MAX FILENAME_MAX @@ -103,11 +76,11 @@ #endif #ifndef OPENSC_VERSION_MAJOR -#define OPENSC_VERSION_MAJOR "@OPENSC_VERSION_MAJOR@" +#define OPENSC_VERSION_MAJOR @OPENSC_VERSION_MAJOR@ #endif #ifndef OPENSC_VERSION_MINOR -#define OPENSC_VERSION_MINOR "@OPENSC_VERSION_MINOR@" +#define OPENSC_VERSION_MINOR @OPENSC_VERSION_MINOR@ #endif #ifndef OPENSC_VS_FF_COMPANY_NAME @@ -126,6 +99,13 @@ #define DEFAULT_PKCS11_PROVIDER "@DEFAULT_PKCS11_PROVIDER@" #endif +#ifndef DEFAULT_SM_MODULE +#define DEFAULT_SM_MODULE "@DEFAULT_SM_MODULE@" +#endif +#ifndef DEFAULT_SM_MODULE_PATH +#define DEFAULT_SM_MODULE_PATH "@DEFAULT_SM_MODULE_PATH@" +#endif + #ifndef OPENSC_SCM_REVISION #define OPENSC_SCM_REVISION "@OPENSC_SCM_REVISION@" #endif