diff --git a/.gitignore b/.gitignore index 74d89dd3..f69bedbf 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ doc/tools/pkcs15-init doc/tools/pkcs15-tool doc/tools/sc-hsm-tool doc/tools/westcos-tool +doc/tools/dnie-tool etc/opensc.conf.win etc/opensc.conf diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..54a754d0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,69 @@ +language: C + +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "UkHn7wy4im8V1nebCWbAetnDSOLRUbOlF6++ovk/7Bnso1/lnhXHelyzgRxfD/oI68wm9nnRV+RQEZ9+72Ug1CyvHxyyxxkwal/tPeHH4B/L+aGdPi0id+5OZSKIm77VP3m5s102sJMJgH7DFd03+nUd0K26p0tk8ad4j1geV4c=" + +matrix: + include: + - compiler: clang + os: osx + - compiler: gcc + os: osx + - compiler: clang + os: linux + env: ENABLE_DOC=--enable-doc + - compiler: gcc + os: linux + env: ENABLE_DOC=--enable-doc + - compiler: gcc + os: linux + env: HOST=i686-w64-mingw32 + +before_install: + - if [ $TRAVIS_OS_NAME == linux ]; then + sudo apt-get update || true; + fi + +install: + - if [ $TRAVIS_OS_NAME == linux ]; then + if [ -z "$HOST" ]; then + sudo apt-get install libpcsclite-dev xsltproc docbook-xsl; + else + sudo apt-get install mingw-w64 binutils-mingw-w64-i686 gcc-mingw-w64-i686; + fi + fi + +before_script: + - ./bootstrap + - if [ -z "$HOST" ]; then + ./configure $ENABLE_DOC --enable-dnie-ui; + else + unset CC; + unset CXX; + ./configure --host=$HOST --disable-openssl; + fi + +addons: + 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 + +script: + - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then + if [ $TRAVIS_OS_NAME == osx ]; then + ./MacOSX/build; + else + make; + fi; + fi + - if [ -z "$HOST" -a "${COVERITY_SCAN_BRANCH}" != 1 -a "$TRAVIS_OS_NAME" != "osx" ]; then + make check; + make dist; + fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..d587910a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# 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 --git a/MacOSX/build-package.in b/MacOSX/build-package.in index 4f671c45..86a2a729 100755 --- a/MacOSX/build-package.in +++ b/MacOSX/build-package.in @@ -70,12 +70,9 @@ fi test -L OpenSC.tokend/build/opensc-src || ln -sf ${BUILDPATH}/src OpenSC.tokend/build/opensc-src # Build and copy OpenSC.tokend -xcodebuild -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj +xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj install DSTROOT=${PWD}/target # Prepare target root -# Copy Tokend -mkdir -p target/System/Library/Security/tokend -mv OpenSC.tokend/build/OpenSC.tokend target/System/Library/Security/tokend # The "UnInstaller" mkdir -p target/usr/local/bin cp MacOSX/opensc-uninstall target/usr/local/bin diff --git a/MacOSX/opensc-uninstall b/MacOSX/opensc-uninstall index bd87839f..9dbc0059 100755 --- a/MacOSX/opensc-uninstall +++ b/MacOSX/opensc-uninstall @@ -16,6 +16,7 @@ test -L /usr/lib/opensc-pkcs11.so && rm -f /usr/lib/opensc-pkcs11.so # Remove installed files rm -rf /Library/OpenSC +rm -rf /Library/Security/tokend/OpenSC.tokend rm -rf /System/Library/Security/tokend/OpenSC.tokend # delete receipts on 10.6+ diff --git a/NEWS b/NEWS index b1b63b89..1de0b8d4 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,68 @@ NEWS for OpenSC -- History of user visible changes +New in 0.15.0; 2015-05-11 +* new card drivers + AzeDIT 3.5 + IsoApplet + MaskTech +* libopensc + allow extended length APDUs + accept no output for 'SELECT' MF and 'SELECT' DF_NAME APDUs + fixed sc_driver_version check + adjusted send/receive size accoriding to card capabilities + in iso7816 make SELECT agnosting to sc_path_t's aid +* asn1 + support multi-bytes tags +* pkcs15 + reviewed support and tool functions for public key + public certs and pubkeys with an auth_id are treated as private +* pkcs11 + introduced default PKCS#11 provider + fetched real value of CKA_LOCAL for pubkey + removed inconsistent attributes + C_Digest issues + no check if buffer too small before update +* added support for Travis CI +* updated support of EC in libopensc, pkcs15 and pkcs11 +* fixed number of warnings, resource leaks, overity-scan issues +* macosx + target minimum OSX version to 10.7 + update the minimal building instructions. + locate and target the latest SDK to build against. + locate the best newest SDK present on the computer. +* build + disable Secure Messaging if OpenSSL is not used +* tools + util_get_pin helper function +* PIV + Add AES support for PIV General Authenticate + fixed invalid bit when writing PIV certificate object with gzipped certificate + fixed bad caching behavior of PIV PKCS15 emulator +* ePass2003 + fixed failure due to re-authenticate of secure messaging when card is accessed + by multiple PKCS11 sessions +* MyEID + EC support for MyEID-v4 card +* openpgp + extended options for openpgp-tool +* asepcos + fixed puk handling +* sc-hsm + support for Koblitz curves secp192k1 and secp256k1 (Bitcoin) + improved error detection and reporting in sc-hsm-tool + fixed Lc byte in VERIFY PIN block for PC/SC PIN PAD reader + fix certificate delete bug +* IAS/ECC + fixed PKCS#11 compliance issues + support for Morpho IAS Agent Card +* cardos + overwrite content of deleted private key +* win32 + setup improuvement + look & feel + custom actions with card registration + minidriver impouvement + fixed errors and warnings returned by Microsoft quality tool + pin-pad support New in 0.14.0; 2014-05-31 * new card driver DNIe diff --git a/README.md b/README.md new file mode 100644 index 00000000..714ad043 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +OpenSC documentation wiki is available online at + https://github.com/OpenSC/OpenSC/wiki + +Please take a look at the documentation before trying to use OpenSC. + +Coverity Scan: +[![Coverity Scan Build Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) + +Jenkins CI: +[![Build Status](https://opensc.fr/jenkins/buildStatus/icon?job=OpenSC-master)](https://opensc.fr/jenkins/view/OpenSC-master/job/OpenSC-master/) + +Travis CI: +[![Build Status](https://api.travis-ci.org/OpenSC/OpenSC.png)](https://travis-ci.org/OpenSC/OpenSC) + diff --git a/configure.ac b/configure.ac index b2853ae3..e65c9197 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ define([PRODUCT_NAME], [OpenSC]) define([PRODUCT_TARNAME], [opensc]) define([PRODUCT_BUGREPORT], [opensc-devel@lists.sourceforge.net]) define([PACKAGE_VERSION_MAJOR], [0]) -define([PACKAGE_VERSION_MINOR], [14]) +define([PACKAGE_VERSION_MINOR], [15]) define([PACKAGE_VERSION_FIX], [0]) define([PACKAGE_SUFFIX], []) define([PACKAGE_VERSION_REVISION], [0]) @@ -39,8 +39,8 @@ OPENSC_VS_FF_PRODUCT_NAME="VS_FF_PRODUCT_NAME" # (Code changed: REVISION++) # (Oldest interface removed: OLDEST++) # (Interfaces added: CURRENT++, REVISION=0) -OPENSC_LT_CURRENT="3" -OPENSC_LT_OLDEST="3" +OPENSC_LT_CURRENT="4" +OPENSC_LT_OLDEST="4" OPENSC_LT_REVISION="0" OPENSC_LT_AGE="0" OPENSC_LT_AGE="$((${OPENSC_LT_CURRENT}-${OPENSC_LT_OLDEST}))" @@ -52,6 +52,8 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CANONICAL_HOST AC_PROG_CC +# AC_PROG_CXX is needed to built the win32 custom action. Indeed dutil.h use [extern "C"] definition which fails on pure c compiler +AC_PROG_CXX PKG_PROG_PKG_CONFIG AC_C_BIGENDIAN @@ -218,6 +220,13 @@ AC_ARG_WITH( , [with_pcsc_provider="detect"] ) + +AC_ARG_WITH( + [pkcs11-provider], + [AS_HELP_STRING([--with-pkcs11-provider=PATH],[Path to the default PKCS11 provider @<:@default=OpenSC@:>@])], + , + [with_pkcs11_provider="detect"] +) dnl ./configure check reader_count="" for rdriver in "${enable_pcsc}" "${enable_openct}" "${enable_ctapi}"; do @@ -531,10 +540,13 @@ if test "${enable_pcsc}" = "yes"; then case "${host}" in *-*-darwin*) # Locate the latest SDK. - SDKS_PATH="$(xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs" - SDK_PATH="${SDK_PATH:-$SDKS_PATH/$(ls -1 ${SDKS_PATH} | sort -n -t. -k2 -r | head -1)}" - # and set the PC/SC include path - PCSC_CFLAGS="-I$SDK_PATH/System/Library/Frameworks/PCSC.framework/Versions/Current/Headers" + SDKS_PATH="$(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs" + if test -d $SDKS_PATH; then + SDK_PATH="${SDK_PATH:-$SDKS_PATH/$(ls -1 ${SDKS_PATH} | sort -n -t. -k2 -r | head -1)}" + PCSC_CFLAGS="-I$SDK_PATH/System/Library/Frameworks/PCSC.framework/Versions/Current/Headers" + else + PCSC_CFLAGS="-I/System/Library/Frameworks/PCSC.framework/Headers" + fi ;; *) PCSC_CFLAGS="-I/usr/include/PCSC" @@ -568,6 +580,24 @@ if test "${enable_pcsc}" = "yes"; then AC_DEFINE([ENABLE_PCSC], [1], [Define if PC/SC is to be enabled]) fi + +if test "${with_pkcs11_provider}" = "detect"; then + case "${host}" in + *-*-darwin*) + DEFAULT_PKCS11_PROVIDER="opensc-pkcs11.dylib" + ;; + *-mingw*|*-winnt*|*-cygwin*) + DEFAULT_PKCS11_PROVIDER="opensc-pkcs11.dll" + ;; + *) + DEFAULT_PKCS11_PROVIDER="opensc-pkcs11.so" + ;; + esac +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 enable_man="no" @@ -643,6 +673,7 @@ AC_SUBST([OPENSC_LT_AGE]) AC_SUBST([OPENSC_LT_OLDEST]) AC_SUBST([WIN_LIBPREFIX]) AC_SUBST([DEFAULT_PCSC_PROVIDER]) +AC_SUBST([DEFAULT_PKCS11_PROVIDER]) AC_SUBST([OPTIONAL_ZLIB_CFLAGS]) AC_SUBST([OPTIONAL_ZLIB_LIBS]) AC_SUBST([OPTIONAL_READLINE_CFLAGS]) @@ -708,6 +739,7 @@ AC_CONFIG_FILES([ src/minidriver/opensc-minidriver.inf win32/Makefile win32/versioninfo.rc + win32/versioninfo-customactions.rc win32/winconfig.h win32/OpenSC.iss win32/OpenSC.wxs @@ -752,6 +784,7 @@ DNIe UI support: ${enable_dnie_ui} Debug file: ${DEBUG_FILE} PC/SC default provider: ${DEFAULT_PCSC_PROVIDER} +PKCS11 default provider: ${DEFAULT_PKCS11_PROVIDER} Host: ${host} Compiler: ${CC} diff --git a/doc/tools/Makefile.am b/doc/tools/Makefile.am index aa0862ee..82c1ceb1 100644 --- a/doc/tools/Makefile.am +++ b/doc/tools/Makefile.am @@ -1,5 +1,7 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +EXTRA_DIST = completion-template + dist_noinst_DATA = $(wildcard $(srcdir)/*.xml) if ENABLE_DOC html_DATA = tools.html @@ -25,8 +27,8 @@ tools.html: $(srcdir)/tools.xml $(wildcard $(srcdir)/*.1.xml) $(wildcard $(srcdi | $(XSLTPROC) --nonet --path "$(srcdir)/..:$(xslstylesheetsdir)/manpages" --xinclude -o $@ man.xsl $< %: $(srcdir)/%.1.xml - echo $< $@ - cat completion-template \ + @echo $< $@ + @cat completion-template \ | sed "s,ALLOPTS,\ $(shell sed -n 's,\s\s\s*.*,\1,pg' $< \ | sort -u | grep -- '^\-' | tr '\n' ' ')," \ diff --git a/doc/tools/dnie-tool.1.xml b/doc/tools/dnie-tool.1.xml index f2d670f4..d58b25b2 100644 --- a/doc/tools/dnie-tool.1.xml +++ b/doc/tools/dnie-tool.1.xml @@ -3,20 +3,22 @@ dnie-tool 1 - opensc + OpenSC + OpenSC Tools + opensc dnie-tool displays information about DNIe based security tokens - - - Synopsis - - dnie-tool [OPTIONS] - - + + + + dnie-tool + OPTIONS + + Description @@ -30,33 +32,49 @@ - - Show the DNIe IDESP value. - + + , + + + Show the DNIe IDESP value. - + + , + + Show DNIe personal information. Reads and print DNIe number and User Name and SurName - + + , + + Displays every available information. - This command is equivalent to -d -i -s - + This command is equivalent to -d -i -s - + + , + + Displays DNIe Serial Number - + + , + + Show DNIe sw version. Displays sofware version for in-card DNIe OS - pin, pin + + pin, + pin + Specify the user pin pin to use. If set to env:VARIABLE, the value of the environment variable @@ -64,22 +82,34 @@ The default is do not enter pin - number, number + + number, + number + Specify the reader number to use. The default is reader 0. - driver, driver + + driver, + driver + Specify the card driver driver to use. Default is use driver from configuration file, or auto-detect if absent - + + , + + Causes dnie-tool to wait for the token to be inserted into reader. - + + , + + Causes dnie-tool to be more verbose. Specify this flag several times to enable debug output in the opensc library. diff --git a/doc/tools/opensc-explorer.1.xml b/doc/tools/opensc-explorer.1.xml index 40646fb7..85ab0857 100644 --- a/doc/tools/opensc-explorer.1.xml +++ b/doc/tools/opensc-explorer.1.xml @@ -292,6 +292,14 @@ 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 diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml index 23d5512e..3efcccc2 100644 --- a/doc/tools/pkcs11-tool.1.xml +++ b/doc/tools/pkcs11-tool.1.xml @@ -236,6 +236,13 @@ Sign some data. + + + , + + Decrypt some data. + + id diff --git a/doc/tools/pkcs15-crypt.1.xml b/doc/tools/pkcs15-crypt.1.xml index 2053ba12..40dd262b 100644 --- a/doc/tools/pkcs15-crypt.1.xml +++ b/doc/tools/pkcs15-crypt.1.xml @@ -159,6 +159,18 @@ (see also ). + + + , + + + When signing with ECDSA key this option indicates + to pkcs15-crypt the signature output format. + Possible values are 'rs'(default) -- two concatanated + integers (PKCS#11), 'sequence' or 'openssl' -- DER encoded sequence + of two integeres (OpenSSL). + + , @@ -168,7 +180,6 @@ verbose. Specify this flag several times to enable debug output in the OpenSC library. - diff --git a/doc/tools/pkcs15-tool.1.xml b/doc/tools/pkcs15-tool.1.xml index 9c588726..82ad7b91 100644 --- a/doc/tools/pkcs15-tool.1.xml +++ b/doc/tools/pkcs15-tool.1.xml @@ -185,7 +185,21 @@ Reads the public key with id id, writing the output in format suitable for - $HOME/.ssh/authorized_keys. + $HOME/.ssh/authorized_keys. + + The key label, if any will be shown in the 'Comment' field. + + + + + + + When used in conjunction with option the + output format of the public key follows rfc4716. + + + The default output format is a single line (openssh). + diff --git a/etc/Makefile.am b/etc/Makefile.am index 59f2d29f..3816fbc3 100644 --- a/etc/Makefile.am +++ b/etc/Makefile.am @@ -15,7 +15,7 @@ force: opensc.conf: opensc.conf.in force .in: - sed \ + @sed \ -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \ -e 's|@libdir[@]|$(libdir)|g' \ -e 's|@DEFAULT_PCSC_PROVIDER[@]|$(DEFAULT_PCSC_PROVIDER)|g' \ diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in index b4a28993..c14107a8 100644 --- a/etc/opensc.conf.in +++ b/etc/opensc.conf.in @@ -202,6 +202,10 @@ app default { # # flags = "rng", "0x80000000"; + # Enable pkcs11 initialization. + # Default: no + # pkcs11_enable_InitToken = yes; + # # Context: PKCS#15 emulation layer # @@ -301,6 +305,14 @@ app default { # 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"; diff --git a/etc/opensc.conf.win.in b/etc/opensc.conf.win.in index fb648c75..b1efb221 100644 --- a/etc/opensc.conf.win.in +++ b/etc/opensc.conf.win.in @@ -202,6 +202,10 @@ app default { # # flags = "rng", "0x80000000"; + # Enable pkcs11 initialization. + # Default: no + # pkcs11_enable_InitToken = yes; + # # Context: PKCS#15 emulation layer # diff --git a/src/common/compat_getopt.c b/src/common/compat_getopt.c index 688e6cc8..e44ebca6 100644 --- a/src/common/compat_getopt.c +++ b/src/common/compat_getopt.c @@ -23,7 +23,9 @@ * DEALINGS IN THE SOFTWARE. */ +#if HAVE_CONFIG_H #include "config.h" +#endif #if ! ( defined(HAVE_GETOPT_H) && defined(HAVE_GETOPT_LONG) && defined(HAVE_GETOPT_LONG_ONLY) ) diff --git a/src/common/compat_getopt_main.c b/src/common/compat_getopt_main.c index b5215118..827ba019 100644 --- a/src/common/compat_getopt_main.c +++ b/src/common/compat_getopt_main.c @@ -234,7 +234,7 @@ main(int argc, char * argv[]) case 'o': /* -output=FILE */ outfilename = optarg; /* we allow "-" as a synonym for stdout here */ - if (! strcmp(optarg, "-")) + if (optarg && !strcmp(optarg, "-")) { outfilename = 0; } diff --git a/src/common/compat_getpass.c b/src/common/compat_getpass.c index f0b09e92..22a1abd1 100644 --- a/src/common/compat_getpass.c +++ b/src/common/compat_getpass.c @@ -1,4 +1,6 @@ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifndef HAVE_GETPASS /* empty file if getpass is available */ #include diff --git a/src/common/compat_strlcat.c b/src/common/compat_strlcat.c index 7fe0cd6b..af373f11 100644 --- a/src/common/compat_strlcat.c +++ b/src/common/compat_strlcat.c @@ -27,7 +27,9 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifndef HAVE_STRLCAT #include diff --git a/src/common/compat_strlcpy.c b/src/common/compat_strlcpy.c index 3e09da73..88f3a5fb 100644 --- a/src/common/compat_strlcpy.c +++ b/src/common/compat_strlcpy.c @@ -16,7 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifndef HAVE_STRLCPY /* empty file if strlcpy is available */ #include diff --git a/src/common/libpkcs11.c b/src/common/libpkcs11.c index b22d16de..58fb814c 100644 --- a/src/common/libpkcs11.c +++ b/src/common/libpkcs11.c @@ -5,7 +5,9 @@ * Copyright (C) 2002 Olaf Kirch */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/common/libscdl.c b/src/common/libscdl.c index b66dbd5e..a78f9e2f 100644 --- a/src/common/libscdl.c +++ b/src/common/libscdl.c @@ -28,12 +28,12 @@ #include void *sc_dlopen(const char *filename) { - return (void *)LoadLibrary(filename); + return (void *)LoadLibraryA(filename); } void *sc_dlsym(void *handle, const char *symbol) { - return GetProcAddress((HANDLE)handle, symbol); + return GetProcAddress((HMODULE)handle, symbol); } const char *sc_dlerror() @@ -43,7 +43,7 @@ const char *sc_dlerror() int sc_dlclose(void *handle) { - return FreeLibrary((HANDLE)handle); + return FreeLibrary((HMODULE)handle); } #else #include diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 33bc3e6e..1d42b0d5 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -41,6 +41,7 @@ libopensc_la_SOURCES = \ card-itacns.c card-authentic.c \ card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \ card-dnie.c cwa14890.c cwa-dnie.c user-interface.c \ + card-isoApplet.c card-masktech.c \ \ pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \ pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \ diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 6a004e3b..a287f70f 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -23,7 +23,8 @@ OBJECTS = \ card-rtecp.obj card-westcos.obj card-myeid.obj card-ias.obj \ card-itacns.obj card-authentic.obj \ card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj cwa-dnie.obj cwa14890.obj \ - card-sc-hsm.obj card-dnie.obj user-interface.obj \ + card-sc-hsm.obj card-dnie.obj user-interface.obj card-isoApplet.obj \ + card-masktech.obj \ \ pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \ pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \ diff --git a/src/libopensc/apdu.c b/src/libopensc/apdu.c index 55f13d08..39c0294b 100644 --- a/src/libopensc/apdu.c +++ b/src/libopensc/apdu.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -203,8 +205,10 @@ int sc_apdu_get_octets(sc_context_t *ctx, const sc_apdu_t *apdu, u8 **buf, if (nbuf == NULL) return SC_ERROR_OUT_OF_MEMORY; /* encode the APDU in the buffer */ - if (sc_apdu2bytes(ctx, apdu, proto, nbuf, nlen) != SC_SUCCESS) + if (sc_apdu2bytes(ctx, apdu, proto, nbuf, nlen) != SC_SUCCESS) { + free(nbuf); return SC_ERROR_INTERNAL; + } *buf = nbuf; *len = nlen; @@ -577,7 +581,7 @@ int sc_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu) * bytes using command chaining */ size_t len = apdu->datalen; const u8 *buf = apdu->data; - size_t max_send_size = card->max_send_size > 0 ? card->max_send_size : 255; + size_t max_send_size = card->max_send_size; while (len != 0) { size_t plen; diff --git a/src/libopensc/asn1.c b/src/libopensc/asn1.c index cad459b0..bc8e9005 100644 --- a/src/libopensc/asn1.c +++ b/src/libopensc/asn1.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -65,9 +67,12 @@ int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out, if (left < 2) return SC_ERROR_INVALID_ASN1_OBJECT; *buf = NULL; - if (*p == 0xff || *p == 0) + if (*p == 0xff || *p == 0) { /* end of data reached */ + *taglen = 0; + *tag_out = SC_ASN1_TAG_EOC; return SC_SUCCESS; + } /* parse tag byte(s) */ cla = (*p & SC_ASN1_TAG_CLASS) | (*p & SC_ASN1_TAG_CONSTRUCTED); tag = *p & SC_ASN1_TAG_PRIMITIVE; @@ -740,23 +745,70 @@ static int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen, return 0; } -int sc_asn1_put_tag(int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr) +int sc_asn1_put_tag(unsigned int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr) { + size_t c = 0; + size_t tag_len; + size_t ii; u8 *p = out; + u8 tag_char[4] = {0, 0, 0, 0}; - if (outlen < 2) - return SC_ERROR_INVALID_ARGUMENTS; - if (datalen > 127) - return SC_ERROR_INVALID_ARGUMENTS; - *p++ = tag & 0xFF; /* FIXME: Support longer tags */ - outlen--; - *p++ = datalen; - outlen--; - if (outlen < datalen) - return SC_ERROR_INVALID_ARGUMENTS; + /* Check tag */ + if (tag == 0 || tag > 0xFFFFFFFF) { + /* A tag of 0x00 is not valid and at most 4-byte tag names are supported. */ + return SC_ERROR_INVALID_DATA; + } + for (tag_len = 0; tag; tag >>= 8) { + /* Note: tag char will be reversed order. */ + tag_char[tag_len++] = tag & 0xFF; + } - memcpy(p, data, datalen); - p += datalen; + if (tag_len > 1) { + if ((tag_char[tag_len - 1] & SC_ASN1_TAG_PRIMITIVE) != SC_ASN1_TAG_ESCAPE_MARKER) { + /* First byte is not escape marker. */ + return SC_ERROR_INVALID_DATA; + } + for (ii = 1; ii < tag_len - 1; ii++) { + if ((tag_char[ii] & 0x80) != 0x80) { + /* MS bit is not 'one'. */ + return SC_ERROR_INVALID_DATA; + } + } + if ((tag_char[0] & 0x80) != 0x00) { + /* MS bit of the last byte is not 'zero'. */ + return SC_ERROR_INVALID_DATA; + } + } + + /* Calculate the number of additional bytes necessary to encode the length. */ + /* c+1 is the size of the length field. */ + if (datalen > 127) { + c = 1; + while (datalen >> (c << 3)) + c++; + } + if (outlen == 0 || out == NULL) { + /* Caller only asks for the length that would be written. */ + return tag_len + (c+1) + datalen; + } + /* We will write the tag, so check the length. */ + if (outlen < tag_len + (c+1) + datalen) + return SC_ERROR_BUFFER_TOO_SMALL; + for (ii=0;ii 0) { + *p++ = 0x80 | c; + while (c--) + *p++ = (datalen >> (c << 3)) & 0xFF; + } + else { + *p++ = datalen & 0x7F; + } + if(data && datalen > 0) { + memcpy(p, data, datalen); + p += datalen; + } if (ptr != NULL) *ptr = p; return 0; @@ -955,7 +1007,7 @@ static const struct sc_asn1_entry c_asn1_se_info[4] = { }; static int asn1_decode_se_info(sc_context_t *ctx, const u8 *obj, size_t objlen, - sc_pkcs15_sec_env_info_t ***se, size_t *num, int depth) + sc_pkcs15_sec_env_info_t ***se, size_t *num, int depth) { struct sc_pkcs15_sec_env_info **ses; const unsigned char *ptr = obj; @@ -1393,6 +1445,8 @@ static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, left, depth, choice ? ", choice" : ""); + if (!p) + return SC_ERROR_ASN1_OBJECT_NOT_FOUND; if (left < 2) { while (asn1->name && (asn1->flags & SC_ASN1_OPTIONAL)) asn1++; @@ -1741,6 +1795,8 @@ _sc_asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, int sc_der_copy(sc_pkcs15_der_t *dst, const sc_pkcs15_der_t *src) { + if (!dst) + return SC_ERROR_INVALID_ARGUMENTS; memset(dst, 0, sizeof(*dst)); if (src->len) { dst->value = malloc(src->len); @@ -1757,7 +1813,7 @@ sc_encode_oid (struct sc_context *ctx, struct sc_object_id *id, unsigned char **out, size_t *size) { static const struct sc_asn1_entry c_asn1_object_id[2] = { - { "oid", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_ALLOC, NULL, NULL }, + { "oid", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_ALLOC, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; struct sc_asn1_entry asn1_object_id[2]; @@ -1772,3 +1828,86 @@ sc_encode_oid (struct sc_context *ctx, struct sc_object_id *id, return SC_SUCCESS; } + +#define C_ASN1_SIG_VALUE_SIZE 2 +static struct sc_asn1_entry c_asn1_sig_value[C_ASN1_SIG_VALUE_SIZE] = { + { "ECDSA-Sig-Value", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +#define C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE 3 +static struct sc_asn1_entry c_asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE] = { + { "r", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, + { "s", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + + +int +sc_asn1_sig_value_rs_to_sequence(struct sc_context *ctx, unsigned char *in, size_t inlen, + unsigned char **buf, size_t *buflen) +{ + struct sc_asn1_entry asn1_sig_value[C_ASN1_SIG_VALUE_SIZE]; + struct sc_asn1_entry asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE]; + unsigned char *r = in, *s = in + inlen/2; + size_t r_len = inlen/2, s_len = inlen/2; + int rv; + + LOG_FUNC_CALLED(ctx); + sc_copy_asn1_entry(c_asn1_sig_value, asn1_sig_value); + sc_format_asn1_entry(asn1_sig_value + 0, asn1_sig_value_coefficients, NULL, 1); + + sc_copy_asn1_entry(c_asn1_sig_value_coefficients, asn1_sig_value_coefficients); + sc_format_asn1_entry(asn1_sig_value_coefficients + 0, r, &r_len, 1); + sc_format_asn1_entry(asn1_sig_value_coefficients + 1, s, &s_len, 1); + + rv = sc_asn1_encode(ctx, asn1_sig_value, buf, buflen); + LOG_TEST_RET(ctx, rv, "ASN.1 encoding ECDSA-SIg-Value failed"); + + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + + +int +sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, unsigned char *in, size_t inlen, + unsigned char *buf, size_t buflen) +{ + struct sc_asn1_entry asn1_sig_value[C_ASN1_SIG_VALUE_SIZE]; + struct sc_asn1_entry asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE]; + unsigned char *r, *s; + size_t r_len, s_len, halflen = buflen/2; + int rv; + + LOG_FUNC_CALLED(ctx); + if (!buf || !buflen) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + sc_copy_asn1_entry(c_asn1_sig_value, asn1_sig_value); + sc_format_asn1_entry(asn1_sig_value + 0, asn1_sig_value_coefficients, NULL, 0); + + sc_copy_asn1_entry(c_asn1_sig_value_coefficients, asn1_sig_value_coefficients); + sc_format_asn1_entry(asn1_sig_value_coefficients + 0, &r, &r_len, 0); + sc_format_asn1_entry(asn1_sig_value_coefficients + 1, &s, &s_len, 0); + + rv = sc_asn1_decode(ctx, asn1_sig_value, in, inlen, NULL, NULL); + LOG_TEST_RET(ctx, rv, "ASN.1 decoding ECDSA-Sig-Value failed"); + + if (halflen < r_len || halflen < s_len) { + rv = SC_ERROR_BUFFER_TOO_SMALL; + goto done; + } + + memset(buf, 0, buflen); + memcpy(buf + (halflen - r_len), r, r_len); + memcpy(buf + (buflen - s_len), s, s_len); + + sc_log(ctx, "r(%i): %s", halflen, sc_dump_hex(buf, halflen)); + sc_log(ctx, "s(%i): %s", halflen, sc_dump_hex(buf + halflen, halflen)); + + rv = SC_SUCCESS; +done: + free(r); + free(s); + + LOG_FUNC_RETURN(ctx, rv); +} diff --git a/src/libopensc/asn1.h b/src/libopensc/asn1.h index 1189275f..0fa23e18 100644 --- a/src/libopensc/asn1.h +++ b/src/libopensc/asn1.h @@ -58,7 +58,7 @@ void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg, int set_present); void sc_copy_asn1_entry(const struct sc_asn1_entry *src, struct sc_asn1_entry *dest); - + /* DER tag and length parsing */ int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *left); @@ -84,8 +84,10 @@ const u8 *sc_asn1_skip_tag(struct sc_context *ctx, const u8 ** buf, /* DER encoding */ /* Argument 'ptr' is set to the location of the next possible ASN.1 object. - * If NULL, no action on 'ptr' is performed. */ -int sc_asn1_put_tag(int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 ** ptr); + * If NULL, no action on 'ptr' is performed. + * If out is NULL or outlen is zero, the length that would be written is returned. + * If data is NULL, the data field will not be written. This is helpful for constructed structures. */ +int sc_asn1_put_tag(unsigned int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 ** ptr); /* ASN.1 printing functions */ void sc_asn1_print_tags(const u8 * buf, size_t buflen); @@ -101,7 +103,7 @@ int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen, int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out); int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen, struct sc_object_id *id); -int sc_asn1_encode_object_id(u8 **buf, size_t *buflen, +int sc_asn1_encode_object_id(u8 **buf, size_t *buflen, const struct sc_object_id *id); /* algorithm encoding/decoding */ @@ -118,6 +120,13 @@ void sc_asn1_clear_algorithm_id(struct sc_algorithm_id *); int sc_asn1_write_element(sc_context_t *ctx, unsigned int tag, const u8 * data, size_t datalen, u8 ** out, size_t * outlen); +int sc_asn1_sig_value_rs_to_sequence(struct sc_context *ctx, + unsigned char *in, size_t inlen, + unsigned char **buf, size_t *buflen); +int sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, + unsigned char *in, size_t inlen, + unsigned char *buf, size_t buflen); + #define SC_ASN1_CLASS_MASK 0x30000000 #define SC_ASN1_UNI 0x00000000 /* Universal */ #define SC_ASN1_APP 0x10000000 /* Application */ diff --git a/src/libopensc/base64.c b/src/libopensc/base64.c index 9152080c..961bd436 100644 --- a/src/libopensc/base64.c +++ b/src/libopensc/base64.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-acos5.c b/src/libopensc/card-acos5.c index 4bc08237..3e392585 100644 --- a/src/libopensc/card-acos5.c +++ b/src/libopensc/card-acos5.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include @@ -26,6 +28,8 @@ #include "cardctl.h" static 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, SC_CARD_TYPE_ACOS5_GENERIC, 0, NULL}, {NULL, NULL, NULL, 0, 0, NULL} diff --git a/src/libopensc/card-akis.c b/src/libopensc/card-akis.c index 684b8b0a..c84e5513 100644 --- a/src/libopensc/card-akis.c +++ b/src/libopensc/card-akis.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-asepcos.c b/src/libopensc/card-asepcos.c index 855c53a1..ad0f514d 100644 --- a/src/libopensc/card-asepcos.c +++ b/src/libopensc/card-asepcos.c @@ -16,7 +16,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -662,7 +664,7 @@ static int asepcos_list_files(sc_card_t *card, u8 *buf, size_t blen) /* 1. get currently selected DF */ r = asepcos_get_current_df_path(card, &bpath); - if (rv != SC_SUCCESS) + if (r != SC_SUCCESS) return r; /* 2. re-select DF to get the FID of the child EFs/DFs */ r = sc_select_file(card, &bpath, &tfile); diff --git a/src/libopensc/card-atrust-acos.c b/src/libopensc/card-atrust-acos.c index f0ac176b..9d3c41fd 100644 --- a/src/libopensc/card-atrust-acos.c +++ b/src/libopensc/card-atrust-acos.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-authentic.c b/src/libopensc/card-authentic.c index 744c534b..1454767b 100644 --- a/src/libopensc/card-authentic.c +++ b/src/libopensc/card-authentic.c @@ -650,7 +650,7 @@ authentic_reduce_path(struct sc_card *card, struct sc_path *path) LOG_FUNC_CALLED(ctx); - if (path->len <= 2 || path->type == SC_PATH_TYPE_DF_NAME || !path) + if (!path || path->len <= 2 || path->type == SC_PATH_TYPE_DF_NAME) LOG_FUNC_RETURN(ctx, SC_SUCCESS); if (!card->cache.valid || !card->cache.current_df) @@ -660,7 +660,7 @@ authentic_reduce_path(struct sc_card *card, struct sc_path *path) cur_path = card->cache.current_df->path; if (!memcmp(cur_path.value, "\x3F\x00", 2) && memcmp(in_path.value, "\x3F\x00", 2)) { - memcpy(in_path.value + 2, in_path.value, in_path.len); + memmove(in_path.value + 2, in_path.value, in_path.len); memcpy(in_path.value, "\x3F\x00", 2); in_path.len += 2; } @@ -672,7 +672,7 @@ authentic_reduce_path(struct sc_card *card, struct sc_path *path) break; } - memcpy(in_path.value, in_path.value + offs, sizeof(in_path.value) - offs); + memmove(in_path.value, in_path.value + offs, sizeof(in_path.value) - offs); in_path.len -= offs; *path = in_path; @@ -749,7 +749,7 @@ authentic_select_file(struct sc_card *card, const struct sc_path *path, rv = authentic_select_mf(card, file_out); LOG_TEST_RET(ctx, rv, "cannot select MF"); - memcpy(&lpath.value[0], &lpath.value[2], lpath.len - 2); + memmove(&lpath.value[0], &lpath.value[2], lpath.len - 2); lpath.len -= 2; if (!lpath.len) @@ -1654,9 +1654,7 @@ authentic_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tri } if (save_current) { - struct sc_file *dummy_file = NULL; - - rv = authentic_select_file(card, &save_current->path, &dummy_file); + rv = authentic_select_file(card, &save_current->path, NULL); LOG_TEST_RET(ctx, rv, "Cannot return to saved PATH"); } LOG_FUNC_RETURN(ctx, rv); @@ -2112,14 +2110,16 @@ static int authentic_sm_acl_init (struct sc_card *card, struct sm_info *sm_info, int cmd, unsigned char *resp, size_t *resp_len) { - struct sc_context *ctx = card->ctx; - struct sm_type_params_gp *params_gp = &sm_info->session.gp.params; + struct sc_context *ctx; + struct sm_type_params_gp *params_gp; struct sc_remote_data rdata; int rv; - sc_log(ctx, "called; command 0x%X\n", cmd); if (!card || !sm_info || !resp || !resp_len) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + return SC_ERROR_INVALID_ARGUMENTS; + + ctx = card->ctx; + params_gp = &sm_info->session.gp.params; if (!card->sm_ctx.module.ops.initialize || !card->sm_ctx.module.ops.get_apdus) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); @@ -2264,22 +2264,22 @@ authentic_sm_get_wrapped_apdu(struct sc_card *card, struct sc_apdu *plain, struc LOG_FUNC_CALLED(ctx); - if (!plain || !sm_apdu) + if (!plain || !sm_apdu) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "called; CLA:%X, INS:%X, P1:%X, P2:%X, data(%i) %p", plain->cla, plain->ins, plain->p1, plain->p2, plain->datalen, plain->data); - *sm_apdu = NULL; + *sm_apdu = NULL; if ((plain->cla & 0x04) - || (plain->cla==0x00 && plain->ins==0x22) - || (plain->cla==0x00 && plain->ins==0x2A) - || (plain->cla==0x00 && plain->ins==0x84) - || (plain->cla==0x00 && plain->ins==0x88) - || (plain->cla==0x00 && plain->ins==0xA4) - || (plain->cla==0x00 && plain->ins==0xC0) - || (plain->cla==0x00 && plain->ins==0xCA) - || (plain->cla==0x80 && plain->ins==0x50) - ) { + || (plain->cla==0x00 && plain->ins==0x22) + || (plain->cla==0x00 && plain->ins==0x2A) + || (plain->cla==0x00 && plain->ins==0x84) + || (plain->cla==0x00 && plain->ins==0x88) + || (plain->cla==0x00 && plain->ins==0xA4) + || (plain->cla==0x00 && plain->ins==0xC0) + || (plain->cla==0x00 && plain->ins==0xCA) + || (plain->cla==0x80 && plain->ins==0x50) + ) { sc_log(ctx, "SM wrap is not applied for this APDU"); LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_APPLIED); } @@ -2290,25 +2290,31 @@ authentic_sm_get_wrapped_apdu(struct sc_card *card, struct sc_apdu *plain, struc if (!card->sm_ctx.module.ops.get_apdus) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - apdu = calloc(1, sizeof(struct sc_apdu)); - if (!apdu) + apdu = calloc(1, sizeof(struct sc_apdu)); + if (!apdu) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy((void *)apdu, (void *)plain, sizeof(struct sc_apdu)); - apdu->data = calloc (1, plain->datalen + 24); - if (!apdu->data) + apdu->data = calloc (1, plain->datalen + 24); + if (!apdu->data) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); if (plain->data && plain->datalen) memcpy((unsigned char *) apdu->data, plain->data, plain->datalen); - apdu->resp = calloc (1, plain->resplen + 32); - if (!apdu->resp) + apdu->resp = calloc (1, plain->resplen + 32); + if (!apdu->resp) { + free(apdu); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + } card->sm_ctx.info.cmd = SM_CMD_APDU_TRANSMIT; card->sm_ctx.info.cmd_data = (void *)apdu; rv = card->sm_ctx.module.ops.get_apdus(ctx, &card->sm_ctx.info, NULL, 0, NULL); + if (rv < 0) { + free(apdu->resp); + free(apdu); + } LOG_TEST_RET(ctx, rv, "SM: GET_APDUS failed"); *sm_apdu = apdu; diff --git a/src/libopensc/card-belpic.c b/src/libopensc/card-belpic.c index 73969d06..bbfb0582 100644 --- a/src/libopensc/card-belpic.c +++ b/src/libopensc/card-belpic.c @@ -80,7 +80,9 @@ * language-selection functionality. */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -127,6 +129,40 @@ static long t1, t2, tot_read = 0, tot_dur = 0, dur; #define BELPIC_PAD_CHAR 0xFF #define BELPIC_KEY_REF_NONREP 0x83 +/* Data in the return value for the GET CARD DATA command: + * All fields are one byte, except when noted otherwise. + * + * See §6.9 in + * https://github.com/Fedict/eid-mw/blob/master/doc/sdk/documentation/Public_Belpic_Applet_v1%207_Ref_Manual%20-%20A01.pdf + * for the full documentation on the GET CARD DATA command. + */ +// Card serial number (16 bytes) +#define BELPIC_CARDDATA_OFF_SERIALNUM 0 +// "Component code" +#define BELPIC_CARDDATA_OFF_COMPCODE 16 +// "OS number" +#define BELPIC_CARDDATA_OFF_OSNUM 17 +// "OS version" +#define BELPIC_CARDDATA_OFF_OSVER 18 +// "Softmask number" +#define BELPIC_CARDDATA_OFF_SMNUM 19 +// "Softmask version" +#define BELPIC_CARDDATA_OFF_SMVER 20 +// Applet version +#define BELPIC_CARDDATA_OFF_APPLETVERS 21 +// Global OS version (2 bytes) +#define BELPIC_CARDDATA_OFF_GL_OSVE 22 +// Applet interface version +#define BELPIC_CARDDATA_OFF_APPINTVERS 24 +// PKCS#1 support version +#define BELPIC_CARDDATA_OFF_PKCS1 25 +// Key exchange version +#define BELPIC_CARDDATA_OFF_KEYX 26 +// Applet life cycle (Should always be 0F for released cards, is 07 when not issued yet) +#define BELPIC_CARDDATA_OFF_APPLCYCLE 27 +// Full length of reply +#define BELPIC_CARDDATA_RESP_LEN 28 + /* Used for a trick in select file and read binary */ static size_t next_idx = (size_t)-1; @@ -577,6 +613,42 @@ static int str2lang(sc_context_t *ctx, char *lang) return -1; } +static int get_carddata(sc_card_t *card, u8* carddata_loc, unsigned int carddataloc_len) +{ + sc_apdu_t apdu; + u8 carddata_cmd[] = { 0x80, 0xE4, 0x00, 0x00, 0x1C }; + int r; + + assert(carddataloc_len == BELPIC_CARDDATA_RESP_LEN); + + r = sc_bytes2apdu(card->ctx, carddata_cmd, sizeof(carddata_cmd), &apdu); + if(r) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "bytes to APDU conversion failed: %d\n", r); + return r; + } + + apdu.resp = carddata_loc; + apdu.resplen = carddataloc_len; + + r = sc_transmit_apdu(card, &apdu); + if(r) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "GetCardData command failed: %d\n", r); + return r; + } + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if(r) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "GetCardData: card returned %d\n", r); + return r; + } + if(apdu.resplen < carddataloc_len) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "GetCardData: card returned %d bytes rather than expected %d\n", apdu.resplen, carddataloc_len); + return SC_ERROR_WRONG_LENGTH; + } + + return 0; +} + #ifdef GET_LANG_FROM_CARD /* str is in lower case, the case of buf can be both, and buf is large enough */ @@ -843,9 +915,10 @@ static int belpic_init(sc_card_t *card) { struct belpic_priv_data *priv = NULL; scconf_block *conf_block; -#ifdef BELPIC_PIN_PAD + u8 applet_version; + u8 carddata[BELPIC_CARDDATA_RESP_LEN]; + int key_size = 1024; int r; -#endif sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Belpic V%s", BELPIC_VERSION); #ifdef HAVE_GUI @@ -865,7 +938,14 @@ static int belpic_init(sc_card_t *card) card->drv_data = priv; card->cla = 0x00; if (card->type == SC_CARD_TYPE_BELPIC_EID) { - _sc_card_add_rsa_alg(card, 1024, + if((r = get_carddata(card, carddata, sizeof(carddata))) < 0) { + return r; + } + applet_version = carddata[BELPIC_CARDDATA_OFF_APPLETVERS]; + if(applet_version >= 0x17) { + key_size = 2048; + } + _sc_card_add_rsa_alg(card, key_size, SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE, 0); } diff --git a/src/libopensc/card-cardos.c b/src/libopensc/card-cardos.c index cbc48e83..7b5b51fd 100644 --- a/src/libopensc/card-cardos.c +++ b/src/libopensc/card-cardos.c @@ -21,7 +21,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -47,8 +49,6 @@ static struct sc_atr_table cardos_atrs[] = { { "3b:e9:00:ff:c1:10:31:fe:55:00:64:05:00:c8:02:31:80:00:47", NULL, NULL, SC_CARD_TYPE_CARDOS_CIE_V1, 0, NULL }, /* Italian eID card, infocamere */ { "3b:fb:98:00:ff:c1:10:31:fe:55:00:64:05:20:47:03:31:80:00:90:00:f3", NULL, NULL, SC_CARD_TYPE_CARDOS_GENERIC, 0, NULL }, - /* Italian CNS - Prov. BZ */ - { "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", NULL, NULL, SC_CARD_TYPE_CARDOS_M4_2, 0, NULL }, /* Another Italian InfocamereCard */ { "3b:fc:98:00:ff:c1:10:31:fe:55:c8:03:49:6e:66:6f:63:61:6d:65:72:65:28", NULL, NULL, SC_CARD_TYPE_CARDOS_GENERIC, 0, NULL }, { "3b:f4:98:00:ff:c1:10:31:fe:55:4d:34:63:76:b4", NULL, NULL, SC_CARD_TYPE_CARDOS_GENERIC, 0, NULL}, @@ -165,6 +165,9 @@ static int cardos_have_2048bit_package(sc_card_t *card) static int cardos_init(sc_card_t *card) { unsigned long flags, rsa_2048 = 0; + size_t data_field_length; + sc_apdu_t apdu; + u8 rbuf[2]; card->name = "CardOS M4"; card->cla = 0x00; @@ -195,6 +198,29 @@ static int cardos_init(sc_card_t *card) card->caps |= SC_CARD_CAP_APDU_EXT; } + /* probe DATA FIELD LENGTH with GET DATA */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x8D); + 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"); + if (apdu.resplen != 2) + return SC_ERROR_WRONG_LENGTH; + data_field_length = ((rbuf[0] << 8) | rbuf[1]); + + /* strip the length of possible Lc and Le bytes */ + if (card->caps & SC_CARD_CAP_APDU_EXT) + card->max_send_size = data_field_length - 6; + else + card->max_send_size = data_field_length - 3; + /* strip the length of SW bytes */ + card->max_recv_size = data_field_length - 2; + if (rsa_2048 == 1) { _sc_card_add_rsa_alg(card, 1280, flags, 0); _sc_card_add_rsa_alg(card, 1536, flags, 0); @@ -1217,35 +1243,6 @@ cardos_logout(sc_card_t *card) return SC_ERROR_NOT_SUPPORTED; } -static int cardos_get_data(struct sc_card *card, unsigned int tag, u8 *buf, size_t len) -{ - int r; - struct sc_apdu apdu; - - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, - (tag >> 8) & 0xff, tag & 0xff); - apdu.lc = 0; - apdu.datalen = 0; - apdu.le = len; - apdu.resp = buf; - apdu.resplen = len; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "GET_DATA returned error"); - - if (apdu.resplen > len) - r = SC_ERROR_WRONG_LENGTH; - else - r = apdu.resplen; - - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); -} - - /* eToken R2 supports WRITE_BINARY, PRO Tokens support UPDATE_BINARY */ static struct sc_card_driver * sc_get_driver(void) @@ -1266,7 +1263,6 @@ static struct sc_card_driver * sc_get_driver(void) cardos_ops.card_ctl = cardos_card_ctl; cardos_ops.pin_cmd = cardos_pin_cmd; cardos_ops.logout = cardos_logout; - cardos_ops.get_data = cardos_get_data; return &cardos_drv; } diff --git a/src/libopensc/card-default.c b/src/libopensc/card-default.c index b5501560..a17c2acb 100644 --- a/src/libopensc/card-default.c +++ b/src/libopensc/card-default.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c index 7bd0df7f..90cb4241 100644 --- a/src/libopensc/card-dnie.c +++ b/src/libopensc/card-dnie.c @@ -293,7 +293,7 @@ data_found: static int dnie_get_info(sc_card_t * card, char *data[]) { sc_file_t *file = NULL; - sc_path_t *path = NULL; + sc_path_t path; u8 *buffer = NULL; size_t bufferlen = 0; char *msg = NULL; @@ -309,14 +309,8 @@ static int dnie_get_info(sc_card_t * card, char *data[]) /* phase 1: get DNIe number, Name and GivenName */ /* read EF(CDF) at 3F0050156004 */ - path = (sc_path_t *) calloc(1, sizeof(sc_path_t)); - if (!path) { - msg = "Cannot allocate path data for EF(CDF) read"; - res = SC_ERROR_OUT_OF_MEMORY; - goto get_info_end; - } - sc_format_path("3F0050156004", path); - res = dnie_read_file(card, path, &file, &buffer, &bufferlen); + sc_format_path("3F0050156004", &path); + res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); if (res != SC_SUCCESS) { msg = "Cannot read EF(CDF)"; goto get_info_end; @@ -334,7 +328,7 @@ static int dnie_get_info(sc_card_t * card, char *data[]) } /* phase 2: get IDESP */ - sc_format_path("3F000006", path); + sc_format_path("3F000006", &path); if (file) { sc_file_free(file); file = NULL; @@ -344,9 +338,8 @@ static int dnie_get_info(sc_card_t * card, char *data[]) buffer=NULL; bufferlen=0; } - res = dnie_read_file(card, path, &file, &buffer, &bufferlen); + res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); if (res != SC_SUCCESS) { - msg = "Cannot read IDESP EF"; data[3]=NULL; goto get_info_ph3; } @@ -360,7 +353,7 @@ static int dnie_get_info(sc_card_t * card, char *data[]) get_info_ph3: /* phase 3: get DNIe software version */ - sc_format_path("3F002F03", path); + sc_format_path("3F002F03", &path); if (file) { sc_file_free(file); file = NULL; @@ -374,7 +367,7 @@ get_info_ph3: * Some old DNIe cards seems not to include SW version file, * so let this code fail without notice */ - res = dnie_read_file(card, path, &file, &buffer, &bufferlen); + res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); if (res != SC_SUCCESS) { msg = "Cannot read DNIe Version EF"; data[4]=NULL; @@ -396,10 +389,12 @@ get_info_ph3: get_info_end: if (file) { sc_file_free(file); - free(buffer); file = NULL; - buffer = NULL; - bufferlen = 0; + } + if (buffer) { + free(buffer); + buffer=NULL; + bufferlen=0; } if (msg) sc_log(card->ctx,msg); @@ -498,8 +493,8 @@ static inline void init_flags(struct sc_card *card) card->max_send_size = (255 - 12); /* manual says 255, but we need 12 extra bytes when encoding */ card->max_recv_size = 255; - algoflags = SC_ALGORITHM_RSA_RAW; /* RSA support */ - algoflags |= SC_ALGORITHM_RSA_HASH_NONE; + /* 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, 2048, algoflags, 0); } @@ -876,7 +871,7 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; - apdu.le = card->max_recv_size > 0 ? card->max_recv_size : 256; + apdu.le = card->max_recv_size; if (p1 == 3) apdu.cse= SC_APDU_CASE_1; @@ -906,6 +901,8 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa if (file == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); res = card->ops->process_fci(card, file, apdu.resp + 2, apdu.resp[1]); + if (*file_out != NULL) + sc_file_free(*file_out); *file_out = file; LOG_FUNC_RETURN(ctx, res); } @@ -1195,7 +1192,7 @@ static int dnie_set_security_env(struct sc_card *card, sc_log(card->ctx, "checking key references"); if (env->key_ref_len != 1) { sc_log(card->ctx, "Null or invalid key ID reference"); - result = SC_ERROR_INVALID_ARGUMENTS; + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } sc_log(card->ctx, "Using key reference '%s'", sc_dump_hex(env->key_ref, env->key_ref_len)); @@ -1357,8 +1354,6 @@ static int dnie_compute_signature(struct sc_card *card, { int result = SC_SUCCESS; struct sc_apdu apdu; - u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; /* to compose digest+hash data */ - size_t sbuflen = 0; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; /* to receive sign response */ /* some preliminar checks */ @@ -1392,20 +1387,6 @@ static int dnie_compute_signature(struct sc_card *card, sc_log(card->ctx, "Compute signature len: '%d' bytes:\n%s\n============================================================", datalen, sc_dump_hex(data, datalen)); - if (datalen != 256) { - sc_log(card->ctx, "Expected pkcs#1 v1.5 DigestInfo data"); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH); - } - - /* try to strip pkcs1 padding */ - sbuflen = sizeof(sbuf); - memset(sbuf, 0, sbuflen); - result = sc_pkcs1_strip_01_padding(card->ctx, data, datalen, sbuf, &sbuflen); - if (result != SC_SUCCESS) { - sc_log(card->ctx, "Provided data is not pkcs#1 padded"); - /* TODO: study what to do on plain data */ - LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_PADDING); - } /*INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x9E Resp: Digital Signature @@ -1414,9 +1395,9 @@ static int dnie_compute_signature(struct sc_card *card, apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; /* signature response size */ - apdu.data = sbuf; - apdu.lc = sbuflen; /* 15 SHA1 DigestInfo + 20 SHA1 computed Hash */ - apdu.datalen = sizeof(sbuf); + apdu.data = data; + apdu.lc = datalen; /* Caller determines the type of hash and its size */ + apdu.datalen = datalen; /* tell card to compute signature */ result = dnie_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, result, "compute_signature() failed"); @@ -1747,7 +1728,7 @@ static int dnie_process_fci(struct sc_card *card, case 0x15: /* EF for keys: linear variable simple TLV */ file->type = SC_FILE_TYPE_WORKING_EF; /* pin file 3F000000 has also this EF type */ - if ( ( file->prop_attr[3] == 0x00 ) && (file->prop_attr[3] == 0x00 ) ) { + if ( ( file->prop_attr[2] == 0x00 ) && (file->prop_attr[3] == 0x00 ) ) { sc_log(ctx,"Processing pin EF"); break; } diff --git a/src/libopensc/card-entersafe.c b/src/libopensc/card-entersafe.c index ca16a2d6..798d28fb 100644 --- a/src/libopensc/card-entersafe.c +++ b/src/libopensc/card-entersafe.c @@ -16,7 +16,9 @@ /* Initially written by Weitao Sun (weitao@ftsafe.com) 2008 */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_OPENSSL /* empty file without openssl */ #include @@ -339,7 +341,7 @@ static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu, blocks=(apdu->lc+2)/8+1; cipher_data_size=blocks*8; cipher_data=malloc(cipher_data_size); - if(!cipher) + if(!cipher_data) { r = SC_ERROR_OUT_OF_MEMORY; goto out; diff --git a/src/libopensc/card-epass2003.c b/src/libopensc/card-epass2003.c index f3d79477..8c75a15e 100644 --- a/src/libopensc/card-epass2003.c +++ b/src/libopensc/card-epass2003.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_SM /* empty file without SM enabled */ #ifdef ENABLE_OPENSSL /* empty file without openssl */ @@ -209,7 +211,7 @@ des3_encrypt_ecb(const unsigned char *key, int keysize, static int -des3_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], +des3_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], const unsigned char *input, size_t length, unsigned char *output) { unsigned char bKey[24] = { 0 }; @@ -227,7 +229,7 @@ des3_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], static int -des3_decrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], +des3_decrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], const unsigned char *input, size_t length, unsigned char *output) { unsigned char bKey[24] = { 0 }; @@ -244,7 +246,7 @@ des3_decrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], static int -des_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], +des_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], const unsigned char *input, size_t length, unsigned char *output) { return openssl_enc(EVP_des_cbc(), key, iv, input, length, output); @@ -252,7 +254,7 @@ des_encrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], static int -des_decrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[8], +des_decrypt_cbc(const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], const unsigned char *input, size_t length, unsigned char *output) { return openssl_dec(EVP_des_cbc(), key, iv, input, length, output); @@ -450,7 +452,9 @@ epass2003_refresh(struct sc_card *card) int r = SC_SUCCESS; if (g_sm) { + card->sm_ctx.sm_mode = 0; r = mutual_auth(card, g_init_key_enc, g_init_key_mac); + card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; LOG_TEST_RET(card->ctx, r, "mutual_auth failed"); } @@ -947,9 +951,6 @@ epass2003_init(struct sc_card *card) card->name = "epass2003"; card->cla = 0x00; card->drv_data = NULL; -/* VT - card->ctx->use_sm = 1; -*/ g_sm = SM_SCP01; /* g_sm = SM_PLAIN; */ @@ -1141,7 +1142,7 @@ epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_l LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); /* update cache */ - if (file->type == SC_FILE_TYPE_DF) { + if (file && file->type == SC_FILE_TYPE_DF) { card->cache.current_path.type = SC_PATH_TYPE_PATH; card->cache.current_path.value[0] = 0x3f; card->cache.current_path.value[1] = 0x00; diff --git a/src/libopensc/card-flex.c b/src/libopensc/card-flex.c index ff4c5085..3c031285 100644 --- a/src/libopensc/card-flex.c +++ b/src/libopensc/card-flex.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-gemsafeV1.c b/src/libopensc/card-gemsafeV1.c index 7b6b87b8..be3ea5b5 100644 --- a/src/libopensc/card-gemsafeV1.c +++ b/src/libopensc/card-gemsafeV1.c @@ -17,7 +17,9 @@ /* Initially written by David Mattes (david.mattes@boeing.com) */ /* Portuguese eID card support by Joao Poupino (joao.poupino@ist.utl.pt) */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -369,7 +371,7 @@ static u8 gemsafe_flags2algref(struct sc_card *card, const struct sc_security_en } else if (env->operation == SC_SEC_OPERATION_DECIPHER) { if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ret = (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || - card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID) ? 0x02 : 0x12; + card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) ? 0x02 : 0x12; } return ret; diff --git a/src/libopensc/card-gpk.c b/src/libopensc/card-gpk.c index 2b44884b..b7a2670a 100644 --- a/src/libopensc/card-gpk.c +++ b/src/libopensc/card-gpk.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_OPENSSL /* empty file without openssl */ #include diff --git a/src/libopensc/card-ias.c b/src/libopensc/card-ias.c index 9c48a5f5..584d5d9d 100644 --- a/src/libopensc/card-ias.c +++ b/src/libopensc/card-ias.c @@ -22,7 +22,9 @@ * Thanks to Andre Cruz, Jorge Ferreira and Paulo F. Andrade */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -473,8 +475,6 @@ static int ias_select_file(sc_card_t *card, const sc_path_t *in_path, r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (file_out == NULL) { - if (apdu.sw1 == 0x61) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); } } diff --git a/src/libopensc/card-iasecc.c b/src/libopensc/card-iasecc.c index 905c0b23..09d730d6 100644 --- a/src/libopensc/card-iasecc.c +++ b/src/libopensc/card-iasecc.c @@ -71,7 +71,7 @@ static struct sc_card_driver iasecc_drv = { static 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:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF", + "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 }, { "3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:08:00:07:90:00:FE", NULL, "IAS/ECC v1.0.1 Oberthur", SC_CARD_TYPE_IASECC_OBERTHUR, 0, NULL }, @@ -79,6 +79,8 @@ static struct sc_atr_table iasecc_known_atrs[] = { "IAS/ECC v1.0.1 Sagem MDW-IAS-CARD2", SC_CARD_TYPE_IASECC_SAGEM, 0, NULL }, { "3B:7F:18:00:00:00:31:B8:64:50:23:EC:C1:73:94:01:80:82:90:00", NULL, "IAS/ECC v1.0.1 Sagem ypsID S3", SC_CARD_TYPE_IASECC_SAGEM, 0, NULL }, + { "3B:DF:96:00:80:31:FE:45:00:31:B8:64:04:1F:EC:C1:73:94:01:80:82:90:00:EC", NULL, + "IAS/ECC Morpho MinInt - Agent Card", SC_CARD_TYPE_IASECC_MI, 0, NULL }, { "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", NULL, "IAS/ECC v1.0.1 Amos", SC_CARD_TYPE_IASECC_AMOS, 0, NULL }, { "3B:DC:18:FF:81:91:FE:1F:C3:80:73:C8:21:13:66:02:04:03:55:00:02:34", NULL, @@ -98,6 +100,10 @@ static struct sc_aid OberthurIASECC_AID = { {0xA0,0x00,0x00,0x00,0x77,0x01,0x08,0x00,0x07,0x00,0x00,0xFE,0x00,0x00,0x01,0x00}, 16 }; +static struct sc_aid MIIASECC_AID = { + { 0x4D, 0x49, 0x4F, 0x4D, 0x43, 0x54}, 6 +}; + struct iasecc_pin_status { unsigned char sha1[SHA_DIGEST_LENGTH]; unsigned char reference; @@ -414,7 +420,8 @@ iasecc_init_gemalto(struct sc_card *card) card->caps |= SC_CARD_CAP_USE_FCI_AC; sc_format_path("3F00", &path); - sc_select_file(card, &path, NULL); + rv = sc_select_file(card, &path, NULL); + /* Result ignored*/ rv = iasecc_parse_ef_atr(card); sc_log(ctx, "rv %i", rv); @@ -565,6 +572,54 @@ iasecc_init_amos(struct sc_card *card) 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) { @@ -588,6 +643,8 @@ iasecc_init(struct sc_card *card) rv = iasecc_init_sagem(card); else if (card->type == SC_CARD_TYPE_IASECC_AMOS) rv = iasecc_init_amos(card); + else if (card->type == SC_CARD_TYPE_IASECC_MI) + rv = iasecc_init_mi(card); else LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT); @@ -812,7 +869,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, LOG_TEST_RET(ctx, rv, "MF selection error"); if (lpath.len >= 2 && lpath.value[0] == 0x3F && lpath.value[1] == 0x00) { - memcpy(&lpath.value[0], &lpath.value[2], lpath.len - 2); + memmove(&lpath.value[0], &lpath.value[2], lpath.len - 2); lpath.len -= 2; } } @@ -878,7 +935,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, if (card->type != SC_CARD_TYPE_IASECC_GEMALTO && 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_AMOS + && card->type != SC_CARD_TYPE_IASECC_MI) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported card"); if (lpath.type == SC_PATH_TYPE_FILE_ID) { @@ -889,6 +947,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, } if (card->type == SC_CARD_TYPE_IASECC_AMOS) apdu.p2 = 0x04; + if (card->type == SC_CARD_TYPE_IASECC_MI) + apdu.p2 = 0x04; } else if (lpath.type == SC_PATH_TYPE_FROM_CURRENT) { apdu.p1 = 0x09; @@ -896,6 +956,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, apdu.p2 = 0x04; if (card->type == SC_CARD_TYPE_IASECC_AMOS) apdu.p2 = 0x04; + if (card->type == SC_CARD_TYPE_IASECC_MI) + apdu.p2 = 0x04; } else if (lpath.type == SC_PATH_TYPE_PARENT) { apdu.p1 = 0x03; @@ -1439,12 +1501,18 @@ iasecc_se_cache_info(struct sc_card *card, struct iasecc_se_info *se) if (card->cache.valid && card->cache.current_df) { sc_file_dup(&se_info->df, card->cache.current_df); - if (se_info->df == NULL) + if (se_info->df == NULL) { + free(se_info); LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate current DF file"); + } } rv = iasecc_docp_copy(ctx, &se->docp, &se_info->docp); - LOG_TEST_RET(ctx, rv, "Cannot make copy of DOCP"); + if (rv < 0) { + free(se_info->df); + free(se_info); + LOG_TEST_RET(ctx, rv, "Cannot make copy of DOCP"); + } if (!prv->se_info) { prv->se_info = se_info; @@ -1740,13 +1808,14 @@ iasecc_chv_verify_pinpad(struct sc_card *card, struct sc_pin_cmd_data *pin_cmd, LOG_FUNC_RETURN(ctx, SC_ERROR_READER); } - if (pin_cmd->pin1.min_length != pin_cmd->pin1.max_length) { - sc_log(ctx, "Different values for PIN min and max lengths is not actually compatible with PinPAD."); - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, - "Different values for PIN min and max lengths is not actually compatible with PinPAD."); - } - - pin_cmd->pin1.len = pin_cmd->pin1.min_length; + /* When PIN stored length available + * P10 verify data contains full template of 'VERIFY PIN' APDU. + * Without PIN stored length + * pin-pad has to set the Lc and fill PIN data itself. + * Not all pin-pads support this case + */ + pin_cmd->pin1.len = pin_cmd->pin1.stored_length; + pin_cmd->pin1.length_offset = 5; memset(buffer, 0xFF, sizeof(buffer)); pin_cmd->pin1.data = buffer; @@ -1976,25 +2045,29 @@ iasecc_chv_change_pinpad(struct sc_card *card, unsigned reference, int *tries_le rv = iasecc_pin_get_policy(card, &pin_cmd); LOG_TEST_RET(ctx, rv, "Get 'PIN policy' error"); - if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Different values for PIN min and max lengths is not allowed with PinPAD."); + /* Some pin-pads do not support mode with Lc=0. + * Give them a chance to work with some cards. + */ + if ((pin_cmd.pin1.min_length == pin_cmd.pin1.stored_length) && (pin_cmd.pin1.max_length == pin_cmd.pin1.min_length)) + pin_cmd.pin1.len = pin_cmd.pin1.stored_length; + else + pin_cmd.pin1.len = 0; - if (pin_cmd.pin1.min_length < 4) - pin_cmd.pin1.min_length = 4; - pin_cmd.pin1.len = pin_cmd.pin1.min_length; + pin_cmd.pin1.length_offset = 5; pin_cmd.pin1.data = pin1_data; memcpy(&pin_cmd.pin2, &pin_cmd.pin1, sizeof(pin_cmd.pin1)); pin_cmd.pin2.data = pin2_data; - sc_log(ctx, "PIN1 max/min: %i/%i", pin_cmd.pin1.max_length, pin_cmd.pin1.min_length); - sc_log(ctx, "PIN2 max/min: %i/%i", pin_cmd.pin2.max_length, pin_cmd.pin2.min_length); + sc_log(ctx, "PIN1 max/min/stored: %i/%i/%i", pin_cmd.pin1.max_length, pin_cmd.pin1.min_length, pin_cmd.pin1.stored_length); + sc_log(ctx, "PIN2 max/min/stored: %i/%i/%i", pin_cmd.pin2.max_length, pin_cmd.pin2.min_length, pin_cmd.pin2.stored_length); rv = iso_ops->pin_cmd(card, &pin_cmd, tries_left); LOG_FUNC_RETURN(ctx, rv); } +#if 0 static int iasecc_chv_set_pinpad(struct sc_card *card, unsigned char reference) { @@ -2022,16 +2095,17 @@ iasecc_chv_set_pinpad(struct sc_card *card, unsigned char reference) rv = iasecc_pin_get_policy(card, &pin_cmd); LOG_TEST_RET(ctx, rv, "Get 'PIN policy' error"); - if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Different values for PIN min and max lengths is not allowed with PinPAD."); + if ((pin_cmd.pin1.min_length == pin_cmd.pin1.stored_length) && (pin_cmd.pin1.max_length == pin_cmd.pin1.min_length)) + pin_cmd.pin1.len = pin_cmd.pin1.stored_length; + else + pin_cmd.pin1.len = 0; - if (pin_cmd.pin1.min_length < 4) - pin_cmd.pin1.min_length = 4; - pin_cmd.pin1.len = pin_cmd.pin1.min_length; + pin_cmd.pin1.length_offset = 5; pin_cmd.pin1.data = pin_data; memcpy(&pin_cmd.pin2, &pin_cmd.pin1, sizeof(pin_cmd.pin1)); memset(&pin_cmd.pin1, 0, sizeof(pin_cmd.pin1)); + pin_cmd.flags |= SC_PIN_CMD_IMPLICIT_CHANGE; sc_log(ctx, "PIN1(max:%i,min:%i)", pin_cmd.pin1.max_length, pin_cmd.pin1.min_length); sc_log(ctx, "PIN2(max:%i,min:%i)", pin_cmd.pin2.max_length, pin_cmd.pin2.min_length); @@ -2039,6 +2113,7 @@ iasecc_chv_set_pinpad(struct sc_card *card, unsigned char reference) rv = iso_ops->pin_cmd(card, &pin_cmd, NULL); LOG_FUNC_RETURN(ctx, rv); } +#endif static int @@ -2091,6 +2166,7 @@ iasecc_pin_get_policy (struct sc_card *card, struct sc_pin_cmd_data *data) if (sdo.docp.acls_contact.size == 0) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Extremely strange ... there is no ACLs"); + sc_log(ctx, "iasecc_pin_get_policy() sdo.docp.size.size %i %02X:%02X", sdo.docp.size.size, *(sdo.docp.size.value + 0), *(sdo.docp.size.value + 1)); for (ii=0; iipin1.max_tries = *sdo.docp.tries_maximum.value; if (sdo.docp.tries_remaining.value) data->pin1.tries_left = *sdo.docp.tries_remaining.value; + if (sdo.docp.size.value) { + for (ii=0; iipin1.stored_length = ((data->pin1.stored_length) << 8) + *(sdo.docp.size.value + ii); + } data->pin1.encoding = SC_PIN_ENCODING_ASCII; data->pin1.offset = 5; @@ -2219,12 +2299,14 @@ iasecc_keyset_change(struct sc_card *card, struct sc_pin_cmd_data *data, int *tr update.fields[0].parent_tag = IASECC_SDO_KEYSET_TAG; update.fields[0].tag = IASECC_SDO_KEYSET_TAG_MAC; - update.fields[0].value = data->pin2.data; + /* FIXME is it safe to modify the const value here? */ + update.fields[0].value = (unsigned char *) data->pin2.data; update.fields[0].size = 16; update.fields[1].parent_tag = IASECC_SDO_KEYSET_TAG; update.fields[1].tag = IASECC_SDO_KEYSET_TAG_ENC; - update.fields[1].value = data->pin2.data + 16; + /* FIXME is it safe to modify the const value here? */ + update.fields[1].value = (unsigned char *) data->pin2.data + 16; update.fields[1].size = 16; rv = iasecc_sm_sdo_update(card, (scb & IASECC_SCB_METHOD_MASK_REF), &update); @@ -2331,6 +2413,7 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ unsigned char se_num = scb & IASECC_SCB_METHOD_MASK_REF; if (scb & IASECC_SCB_METHOD_USER_AUTH) { + sc_log(ctx, "Verify PIN in SE %X", se_num); rv = iasecc_pin_verify(card, SC_AC_SEN, se_num, data->pin1.data, data->pin1.len, tries_left); LOG_TEST_RET(ctx, rv, "iasecc_pin_reset() verify PUK error"); @@ -2341,9 +2424,6 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ if (scb & IASECC_SCB_METHOD_SM) { rv = iasecc_sm_pin_reset(card, se_num, data); LOG_FUNC_RETURN(ctx, rv); - - if (!need_all) - break; } if (scb & IASECC_SCB_METHOD_EXT_AUTH) { @@ -2355,6 +2435,7 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ iasecc_sdo_free_fields(card, &sdo); if (data->pin2.len) { + sc_log(ctx, "Reset PIN %X and set new value", reference); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2C, 0x02, reference); apdu.data = data->pin2.data; apdu.datalen = data->pin2.len; @@ -2366,6 +2447,7 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ LOG_TEST_RET(ctx, rv, "PIN cmd failed"); } else if (data->pin2.data) { + sc_log(ctx, "Reset PIN %X and set new value", reference); sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2C, 3, reference); rv = sc_transmit_apdu(card, &apdu); @@ -2374,8 +2456,13 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ LOG_TEST_RET(ctx, rv, "PIN cmd failed"); } else { + sc_log(ctx, "Reset PIN %X and set new value with PIN-PAD", reference); +#if 0 rv = iasecc_chv_set_pinpad(card, reference); - sc_log(ctx, "Set CHV with PIN pad returned %i", rv); + LOG_TEST_RET(ctx, rv, "Reset PIN failed"); +#else + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Reset retry counter with PIN PAD not supported "); +#endif } if (save_current) { @@ -2393,7 +2480,6 @@ static int iasecc_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left) { struct sc_context *ctx = card->ctx; - struct sc_apdu apdu; int rv; LOG_FUNC_CALLED(ctx); @@ -2404,29 +2490,24 @@ iasecc_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_le switch (data->cmd) { case SC_PIN_CMD_VERIFY: rv = iasecc_pin_verify(card, data->pin_type, data->pin_reference, data->pin1.data, data->pin1.len, tries_left); - LOG_FUNC_RETURN(ctx, rv); + break; case SC_PIN_CMD_CHANGE: if (data->pin_type == SC_AC_AUT) rv = iasecc_keyset_change(card, data, tries_left); else rv = iasecc_pin_change(card, data, tries_left); - LOG_FUNC_RETURN(ctx, rv); + break; case SC_PIN_CMD_UNBLOCK: rv = iasecc_pin_reset(card, data, tries_left); - LOG_FUNC_RETURN(ctx, rv); + break; case SC_PIN_CMD_GET_INFO: rv = iasecc_pin_get_policy(card, data); - LOG_FUNC_RETURN(ctx, rv); + break; default: sc_log(ctx, "Other pin commands not supported yet: 0x%X", data->cmd); - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Non-supported PIN command"); + rv = SC_ERROR_NOT_SUPPORTED; } - 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, "PIN cmd failed"); - LOG_FUNC_RETURN(ctx, rv); } @@ -2563,7 +2644,8 @@ iasecc_sdo_create(struct sc_card *card, struct iasecc_sdo *sdo) rv = iasecc_sdo_put_data(card, &update); LOG_TEST_RET(ctx, rv, "failed to update 'Compulsory usage' data"); - field->on_card = 1; + if (field) + field->on_card = 1; } free(data); @@ -3250,14 +3332,19 @@ static int iasecc_compute_signature(struct sc_card *card, const unsigned char *in, size_t in_len, unsigned char *out, size_t out_len) { - struct sc_context *ctx = card->ctx; - struct iasecc_private_data *prv = (struct iasecc_private_data *) card->drv_data; - struct sc_security_env *env = &prv->security_env; + struct sc_context *ctx; + struct iasecc_private_data *prv; + struct sc_security_env *env; + + if (!card || !in || !out) + return SC_ERROR_INVALID_ARGUMENTS; + + ctx = card->ctx; + prv = (struct iasecc_private_data *) card->drv_data; + env = &prv->security_env; LOG_FUNC_CALLED(ctx); sc_log(ctx, "inlen %i, outlen %i", in_len, out_len); - if (!card || !in || !out) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid compute signature arguments"); if (env->operation == SC_SEC_OPERATION_SIGN) return iasecc_compute_signature_dst(card, in, in_len, out, out_len); @@ -3315,7 +3402,8 @@ iasecc_read_public_key(struct sc_card *card, unsigned type, rv = sc_pkcs15_encode_pubkey_rsa(ctx, &rsa_key, out, out_len); LOG_TEST_RET(ctx, rv, "failed to read public key: cannot encode RSA public key"); - sc_log(ctx, "encoded public key: %s", sc_dump_hex(*out, *out_len)); + if (out && out_len) + sc_log(ctx, "encoded public key: %s", sc_dump_hex(*out, *out_len)); if (bn[0].data) free(bn[0].data); @@ -3324,7 +3412,7 @@ iasecc_read_public_key(struct sc_card *card, unsigned type, iasecc_sdo_free_fields(card, &sdo); - SC_FUNC_RETURN(ctx, SC_SUCCESS, rv); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } diff --git a/src/libopensc/card-incrypto34.c b/src/libopensc/card-incrypto34.c index 317afe30..676a755d 100644 --- a/src/libopensc/card-incrypto34.c +++ b/src/libopensc/card-incrypto34.c @@ -21,7 +21,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -722,7 +724,7 @@ incrypto34_generate_key(sc_card_t *card, apdu.ins = 0x46; apdu.p1 = 0x00; apdu.p2 = args->key_id;/* doc is not clear, it just says "ID" */ - apdu.p2 = 0x00; + apdu.le = 0x00; apdu.data= data; apdu.datalen = apdu.lc = sizeof(data); diff --git a/src/libopensc/card-isoApplet.c b/src/libopensc/card-isoApplet.c new file mode 100644 index 00000000..06ccd098 --- /dev/null +++ b/src/libopensc/card-isoApplet.c @@ -0,0 +1,1291 @@ +/* + * Support for the IsoApplet JavaCard Applet. + * + * Copyright (C) 2014 Philip Wendland + * + * 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 +#include + +#include "asn1.h" +#include "cardctl.h" +#include "internal.h" +#include "log.h" +#include "opensc.h" +#include "pkcs15.h" +#include "types.h" + +#define ISOAPPLET_ALG_REF_ECDSA 0x21 +#define ISOAPPLET_ALG_REF_RSA_PAD_PKCS1 0x11 + +#define ISOAPPLET_API_VERSION_MAJOR 0x00 +#define ISOAPPLET_API_VERSION_MINOR 0x06 + +#define ISOAPPLET_API_FEATURE_EXT_APDU 0x01 +#define ISOAPPLET_API_FEATURE_SECURE_RANDOM 0x02 +#define ISOAPPLET_API_FEATURE_ECC 0x04 + +#define ISOAPPLET_AID_LEN 12 +static const u8 isoApplet_aid[] = {0xf2,0x76,0xa2,0x88,0xbc,0xfb,0xa6,0x9d,0x34,0xf3,0x10,0x01}; + +struct isoApplet_drv_data +{ + /* 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. + * If ECC is being used, the signatures generated by the card + * have to be modified. */ + unsigned int sec_env_alg_ref; + unsigned int sec_env_ec_field_length; + unsigned int isoapplet_version; +}; +#define DRVDATA(card) ((struct isoApplet_drv_data *) ((card)->drv_data)) + +/* Operations supported by the applet. */ +static struct sc_card_operations isoApplet_ops; + +/* A reference to the iso7816_* functions. + * Initialized in sc_get_driver. */ +static const struct sc_card_operations *iso_ops = NULL; + +/* The description of the driver. */ +static struct sc_card_driver isoApplet_drv = +{ + "Javacard with IsoApplet", + "isoApplet", + &isoApplet_ops, + NULL, 0, NULL +}; + +static struct isoapplet_supported_ec_curves { + struct sc_object_id oid; + size_t size; + unsigned int min_applet_version; +} ec_curves[] = { + {{{1, 2, 840, 10045, 3, 1, 1, -1}}, 192, 0x0000}, /* secp192r1, nistp192, prime192v1, ansiX9p192r1 */ + {{{1, 3, 132, 0, 33, -1}}, 224, 0x0000}, /* secp224r1, nistp224 */ + {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, 0x0000}, /* secp256r1, nistp256, prime256v1, ansiX9p256r1 */ + {{{1, 3, 132, 0, 34, -1}}, 384, 0x0000}, /* secp384r1, nistp384, prime384v1, ansiX9p384r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 3, -1}}, 192, 0x0000}, /* brainpoolP192r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 5, -1}}, 224, 0x0000}, /* brainpoolP224r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256, 0x0000}, /* brainpoolP256r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 9, -1}}, 320, 0x0000}, /* brainpoolP320r1 */ + {{{1, 3, 132, 0, 31, -1}}, 192, 0x0006}, /* secp192k1 */ + {{{1, 3, 132, 0, 10, -1}}, 256, 0x0006}, /* secp256k1 */ + {{{-1}}, 0, 0} /* This entry must not be touched. */ +}; + +/* + * SELECT an applet on the smartcard. (Not in the emulated filesystem.) + * The response will be written to resp. + * + * @param[in] card + * @param[in] aid The applet ID. + * @param[in] aid_len The legth 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. + * + * @return SC_SUCCESS: The applet is present and could be selected. + * any other: Transmit failure or the card returned an error. + * The card will return an error when the applet is + * not present. + */ +static int +isoApplet_select_applet(sc_card_t *card, const u8 *aid, const size_t aid_len, u8 *resp, size_t *resp_len) +{ + int rv; + sc_context_t *ctx = card->ctx; + sc_apdu_t apdu; + + LOG_FUNC_CALLED(card->ctx); + + if(aid_len > SC_MAX_APDU_BUFFER_SIZE) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xa4, 0x04, 0x00); + apdu.lc = aid_len; + apdu.data = aid; + apdu.datalen = aid_len; + apdu.resp = resp; + apdu.resplen = *resp_len; + apdu.le = 0; + + rv = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(ctx, rv, "APDU transmit faiure."); + + rv = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, rv, "Card returned error"); + + *resp_len = apdu.resplen; + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static int +isoApplet_finish(sc_card_t *card) +{ + struct isoApplet_drv_data *drvdata=DRVDATA(card); + + LOG_FUNC_CALLED(card->ctx); + if (drvdata) + { + free(drvdata); + card->drv_data=NULL; + } + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static int +isoApplet_match_card(sc_card_t *card) +{ + size_t rlen = SC_MAX_APDU_BUFFER_SIZE; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + int rv; + + rv = isoApplet_select_applet(card, isoApplet_aid, ISOAPPLET_AID_LEN, rbuf, &rlen); + + if(rv != SC_SUCCESS) + { + return 0; + } + + /* The IsoApplet should return an API version (major and minor) and a feature bitmap. + * We expect 3 bytes: MAJOR API version - MINOR API version - API feature bitmap. + * If applet does not return API version, versions 0x00 will match */ + if(rlen < 3) + { + assert(sizeof(rbuf) >= 3); + memset(rbuf, 0x00, 3); + } + + if(rbuf[0] != ISOAPPLET_API_VERSION_MAJOR) + { + sc_log(card->ctx, "IsoApplet: Mismatching major API version. Not proceeding. " + "API versions: Driver (%02X-%02X), applet (%02X-%02X). Please update accordingly.", + ISOAPPLET_API_VERSION_MAJOR, ISOAPPLET_API_VERSION_MINOR, rbuf[0], rbuf[1]); + return 0; + } + + if(rbuf[1] != ISOAPPLET_API_VERSION_MINOR) + { + sc_log(card->ctx, "IsoApplet: Mismatching minor API version. Proceeding anyway. " + "API versions: Driver (%02X-%02X), applet (%02X-%02X). " + "Please update accordingly whenever possible.", + ISOAPPLET_API_VERSION_MAJOR, ISOAPPLET_API_VERSION_MINOR, rbuf[0], rbuf[1]); + } + + return 1; +} + +static int +isoApplet_init(sc_card_t *card) +{ + int r; + int i; + unsigned long flags = 0; + unsigned long ext_flags = 0; + size_t rlen = SC_MAX_APDU_BUFFER_SIZE; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + struct isoApplet_drv_data *drvdata; + + LOG_FUNC_CALLED(card->ctx); + + drvdata=calloc(1, sizeof(*drvdata)); + if (!drvdata) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + + card->drv_data = drvdata; + 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(rlen < 3) + { + assert(sizeof(rbuf) >= 3); + memset(rbuf, 0x00, 3); + } + drvdata->isoapplet_version = ((unsigned int)rbuf[0] << 8) | rbuf[1]; + if(rbuf[2] & ISOAPPLET_API_FEATURE_EXT_APDU) + card->caps |= SC_CARD_CAP_APDU_EXT; + if(rbuf[2] & ISOAPPLET_API_FEATURE_SECURE_RANDOM) + card->caps |= SC_CARD_CAP_RNG; + if(drvdata->isoapplet_version <= 0x0005 || rbuf[2] & ISOAPPLET_API_FEATURE_ECC) + { + /* There are Java Cards that do not support ECDSA at all. The IsoApplet + * started to report this with version 00.06. + * + * Curves supported by the pkcs15-init driver are indicated per curve. This + * should be kept in sync with the explicit parameters in the pkcs15-init + * driver. */ + flags = 0; + flags |= SC_ALGORITHM_ECDSA_RAW; + flags |= SC_ALGORITHM_ECDSA_HASH_SHA1; + flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; + ext_flags = SC_ALGORITHM_EXT_EC_UNCOMPRESES; + ext_flags |= SC_ALGORITHM_EXT_EC_NAMEDCURVE; + ext_flags |= SC_ALGORITHM_EXT_EC_F_P; + for (i=0; ec_curves[i].oid.value[0] >= 0; i++) + { + if(drvdata->isoapplet_version >= ec_curves[i].min_applet_version) + _sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].oid); + } + } + + /* RSA */ + flags = 0; + /* Padding schemes: */ + flags |= SC_ALGORITHM_RSA_PAD_PKCS1; + /* Hashes are to be done by the host for RSA */ + flags |= SC_ALGORITHM_RSA_HASH_NONE; + /* Key-generation: */ + flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; + /* Modulus lengths: */ + _sc_card_add_rsa_alg(card, 2048, flags, 0); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +/* + * @brief convert an OpenSC ACL entry to the security condition + * byte used by the IsoApplet. + * + * Used by IsoApplet_create_file to parse OpenSC ACL entries + * into ISO 7816-4 Table 20 security condition bytes. + * + * @param entry The OpenSC ACL entry. + * + * @return The security condition byte. No restriction (0x00) + * if unknown operation. + */ +static u8 +isoApplet_acl_to_security_condition_byte(const sc_acl_entry_t *entry) +{ + if(!entry) + return 0x00; + switch(entry->method) + { + case SC_AC_CHV: + return 0x90; + case SC_AC_NEVER: + return 0xFF; + case SC_AC_NONE: + default: + return 0x00; + } +} + +/* + * The reason for this function is that OpenSC doesn't set any + * Security Attribute Tag in the FCI upon file creation if there + * is no file->sec_attr. I set the file->sec_attr to a format + * understood by the applet (ISO 7816-4 tables 16, 17 and 20). + * The iso7816_create_file will then set this as Tag 86 - Sec. + * Attr. Prop. Format. + * The applet will then be able to set and enforce access rights + * for any file created by OpenSC. Without this function, the + * applet would not know where to enforce security rules and + * when. + * + * Note: IsoApplet currently only supports a "onepin" option. + * + * Format of the sec_attr: 8 Bytes: + * 7 - ISO 7816-4 table 16 or 17 + * 6 to 0 - ISO 7816-4 table 20 + */ +static int +isoApplet_create_file(sc_card_t *card, sc_file_t *file) +{ + int r = 0; + + LOG_FUNC_CALLED(card->ctx); + + if(file->sec_attr_len == 0) + { + u8 access_buf[8]; + int idx[8], i; + + if(file->type == SC_FILE_TYPE_DF) + { + const int df_idx[8] = /* These are the SC operations. */ + { + 0, /* Reserved. */ + SC_AC_OP_DELETE_SELF, /* b6 */ + SC_AC_OP_LOCK, /* b5 */ + SC_AC_OP_ACTIVATE, /* b4 */ + SC_AC_OP_DEACTIVATE, /* b3 */ + SC_AC_OP_CREATE_DF, /* b2 */ + SC_AC_OP_CREATE_EF, /* b1 */ + SC_AC_OP_DELETE /* b0 */ + }; + for(i=0; i<8; i++) + { + idx[i] = df_idx[i]; + } + } + else /* EF */ + { + const int ef_idx[8] = + { + 0, /* Reserved. */ + SC_AC_OP_DELETE_SELF, /* b6 */ + SC_AC_OP_LOCK, /* b5 */ + SC_AC_OP_ACTIVATE, /* b4 */ + SC_AC_OP_DEACTIVATE, /* b3 */ + SC_AC_OP_WRITE, /* b2 */ + SC_AC_OP_UPDATE, /* b1 */ + SC_AC_OP_READ /* b0 */ + }; + for(i=0; i<8; i++) + { + idx[i] = ef_idx[i]; + } + } + /* Now idx contains the operation identifiers. + * We now search for the OPs. */ + access_buf[0] = 0xFF; /* A security condition byte is present for every OP. (Table 19) */ + for(i=1; i<8; i++) + { + const sc_acl_entry_t *entry; + entry = sc_file_get_acl_entry(file, idx[i]); + access_buf[i] = isoApplet_acl_to_security_condition_byte(entry); + } + + r = sc_file_set_sec_attr(file, access_buf, 8); + LOG_TEST_RET(card->ctx, r, "Error adding security attribute."); + } + + r = iso_ops->create_file(card, file); + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * Add an ACL entry to the OpenSC file struct, according to the operation + * and the saByte (Encoded according to IsoApplet FCI proprietary security + * information, see also ISO 7816-4 table 20). + * + * @param[in,out] file + * @param[in] operation The OpenSC operation. + * @param[in] saByte The security condition byte returned by the applet. + */ +static int +isoApplet_add_sa_to_acl(sc_file_t *file, unsigned int operation, u8 saByte) +{ + int r; + + switch(saByte) + { + case 0x90: + r = sc_file_add_acl_entry(file, operation, SC_AC_CHV, 1); + if(r < 0) + return r; + break; + case 0xFF: + r = sc_file_add_acl_entry(file, operation, SC_AC_NEVER, SC_AC_KEY_REF_NONE); + if(r < 0) + return r; + break; + case 0x00: + r = sc_file_add_acl_entry(file, operation, SC_AC_NONE, SC_AC_KEY_REF_NONE); + if(r < 0) + return r; + break; + default: + r = sc_file_add_acl_entry(file, operation, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE); + if(r < 0) + return r; + } + return SC_SUCCESS; +} + + +/* + * This function first calls the iso7816.c process_fci() for any other FCI + * information and then updates the ACL of the OpenSC file struct according + * to the FCI from the applet. + */ +static int +isoApplet_process_fci(sc_card_t *card, sc_file_t *file, + const u8 *buf, size_t buflen) +{ + int r; + u8 *sa = NULL; + + LOG_FUNC_CALLED(card->ctx); + + r = iso_ops->process_fci(card, file, buf, buflen); + LOG_TEST_RET(card->ctx, r, "Error while processing the FCI."); + /* Construct the ACL from the sec_attr. */ + if(file->sec_attr && file->sec_attr_len == 8) + { + sa = file->sec_attr; + if(sa[0] != 0xFF) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, + "File security attribute does not contain a ACL byte for every operation."); + } + if(file->type == SC_FILE_TYPE_DF) + { + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE_SELF, sa[1]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_LOCK, sa[2]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_ACTIVATE, sa[3]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DEACTIVATE, sa[4]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_CREATE_DF, sa[5]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_CREATE_EF, sa[6]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE, sa[7]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + } + else if(file->type == SC_FILE_TYPE_INTERNAL_EF + || file->type == SC_FILE_TYPE_WORKING_EF) + { + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE_SELF, sa[1]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_LOCK, sa[2]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_ACTIVATE, sa[3]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DEACTIVATE, sa[4]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_WRITE, sa[5]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_UPDATE, sa[6]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + r = isoApplet_add_sa_to_acl(file, SC_AC_OP_READ, sa[7]); + LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); + } + + } + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +/* + * @brief Encode the EC parameters as a concatenation of TLV enrties. + * + * The format is: + * 81 - prime + * 82 - coefficient A + * 83 - coefficient B + * 84 - base point G + * 85 - order + * 87 - cofactor + * + * @param[in] card + * @param[in] params The ECparameters containing the information of the curve. + * @param[out] out The array the encoded parameters are written to. + * @param[in] out_len The size of out + * @param[out] ptr A pointer pointing to the end of the parameters in out + * (the first untouched byte behind the parameters). + */ +static int +isoApplet_put_ec_params(sc_card_t *card, sc_cardctl_isoApplet_ec_parameters_t *params, u8 *out, size_t out_len, u8 **ptr) +{ + u8 *p = out; + int r; + + LOG_FUNC_CALLED(card->ctx); + + if(!params + || !params->prime.value + || !params->coefficientA.value + || !params->coefficientB.value + || !params->basePointG.value + || !params->order.value + || !params->coFactor.value) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Error: EC params not present."); + } + + if(out == NULL || out_len == 0) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Error: Parameter out is NULL or outlen is zero."); + } + + r = sc_asn1_put_tag(0x81, params->prime.value, params->prime.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + r = sc_asn1_put_tag(0x82, params->coefficientA.value, params->coefficientA.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + r = sc_asn1_put_tag(0x83, params->coefficientB.value, params->coefficientB.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + r = sc_asn1_put_tag(0x84, params->basePointG.value, params->basePointG.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + r = sc_asn1_put_tag(0x85, params->order.value, params->order.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + r = sc_asn1_put_tag(0x87, params->coFactor.value, params->coFactor.len, p, out_len - (p - out), &p); + LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); + + if (ptr != NULL) + *ptr = p; + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * @brief Generate a private key on the card. + */ +static int +isoApplet_ctl_generate_key(sc_card_t *card, sc_cardctl_isoApplet_genkey_t *args) +{ + int r; + sc_apdu_t apdu; + u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + u8 *p; + const u8 *inner_tag_value; + const u8 *outer_tag_value; + unsigned int tag; + size_t outer_tag_len; + size_t inner_tag_len; + unsigned int cla; + + LOG_FUNC_CALLED(card->ctx); + + /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); + + p = sbuf; + *p++ = 0x80; /* algorithm reference */ + *p++ = 0x01; + *p++ = args->algorithm_ref; + + *p++ = 0x84; /* Private key reference */ + *p++ = 0x01; + *p++ = args->priv_key_ref; + + r = p - sbuf; + p = NULL; + + apdu.lc = r; + apdu.datalen = r; + apdu.data = sbuf; + + 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"); + + + /* GENERATE ASYMMETRIC KEY PAIR + * We use a larger buffer here, even if the card does not support extended apdus. + * 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 + * 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) + { + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x46, 0x00, 0x00); + apdu.data = sbuf; + p = sbuf; + r = isoApplet_put_ec_params(card, &args->pubkey.ec.params, p, sizeof(sbuf), &p); + LOG_TEST_RET(card->ctx, r, "Error composing EC params."); + apdu.datalen = p - sbuf; + apdu.lc = p - sbuf; + /* Use APDU chaining if the card does not support extended apdus + * and the data does not fit in one short apdu. */ + if ((apdu.datalen > 255) && !(card->caps & SC_CARD_CAP_APDU_EXT)) + { + apdu.flags |= SC_APDU_FLAGS_CHAINING; + } + } + else + { + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x46, 0x42, 0x00); + } + + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 256; + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) + { + sc_log(card->ctx, "Key generation not supported by the card with that particular key type. " + "Your card may not support the specified algorithm used by the applet / specified by you. " + "In most cases, this happens when trying to generate EC keys not supported by your java card. " + "In this case, look for supported field lengths and whether FP and/or F2M are supported."); + } + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + /* Parse the public key / response. */ + outer_tag_value = apdu.resp; + r = sc_asn1_read_tag(&outer_tag_value, apdu.resplen, &cla, &tag, &outer_tag_len); + LOG_TEST_RET(card->ctx, r, "Error in ASN1 handling."); + /* Interindustry template for nesting one set of public key data objects */ + if((tag != 0x1F49) || (cla != 0x60)) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, + "The data returned by the card is unexpected."); + } + + switch(args->algorithm_ref) + { + + case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: + /* Search for the modulus tag (81). */ + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != 256) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid modulus."); + } + if(inner_tag_len > args->pubkey.rsa.modulus.len) + { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); + } + memcpy(args->pubkey.rsa.modulus.value, inner_tag_value, inner_tag_len); + args->pubkey.rsa.modulus.len = inner_tag_len; + + /* Exponent tag (82) */ + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != 3) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid exponent."); + } + if(inner_tag_len > args->pubkey.rsa.exponent.len) + { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); + } + if(memcmp(inner_tag_value, "\x01\x00\x01", 3) != 0) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, + "Key generation error: Unexpected public key exponent."); + } + memcpy(args->pubkey.rsa.exponent.value, inner_tag_value, inner_tag_len); + args->pubkey.rsa.exponent.len = inner_tag_len; + p = NULL; + break; + + case SC_ISOAPPLET_ALG_REF_EC_GEN: + /* Compare the parameters received from the card to the ones sent to the card. */ + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.prime.len + || memcmp(inner_tag_value, args->pubkey.ec.params.prime.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid prime."); + + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientA.len + || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientA.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient A."); + + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x83, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientB.len + || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientB.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient B."); + + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x84, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.basePointG.len + || memcmp(inner_tag_value, args->pubkey.ec.params.basePointG.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid base point G."); + + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x85, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.order.len + || memcmp(inner_tag_value, args->pubkey.ec.params.order.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid order."); + + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x87, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coFactor.len + || memcmp(inner_tag_value, args->pubkey.ec.params.coFactor.value, inner_tag_len) != 0) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid cofactor."); + + /* Extract public key */ + inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x86, &inner_tag_len); + if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.ecPointQ.len) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid EC point Q."); + memcpy(args->pubkey.ec.ecPointQ.value, inner_tag_value, inner_tag_len); + + break; + default: + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unable to parse public key: Unsupported algorithm."); + }/* switch */ + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +/* + * @brief Use PUT DATA to import a private RSA key. + * + * For simplicity, command chaining has to be used. One chunk (apdu) must contain + * one RSA field (P, Q, etc.). The first apdu must contain the outer tag (7F48). + * + * @param card + * @param rsa The RSA private key to import. + * + * @return SC_ERROR_INVALID_ARGUMENTS: The RSA key does not contain CRT fields. + * other errors: Transmit errors / errors returned by card. + */ +static int +isoApplet_put_data_prkey_rsa(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) +{ + sc_apdu_t apdu; + u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + u8 *p = NULL; + int r; + size_t tags_len; + + LOG_FUNC_CALLED(card->ctx); + + if(!args->privkey.rsa.p.value + || !args->privkey.rsa.q.value + || !args->privkey.rsa.iqmp.value + || !args->privkey.rsa.dmp1.value + || !args->privkey.rsa.dmq1.value) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "RSA key is missing information."); + } + + /* Note: The format is according to ISO 2-byte tag 7F48 + * "T-L pair to indicate a private key data object" */ + + /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ + tags_len = 0; + r = sc_asn1_put_tag(0x92, NULL, args->privkey.rsa.p.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x93, NULL, args->privkey.rsa.q.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x94, NULL, args->privkey.rsa.iqmp.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x95, NULL, args->privkey.rsa.dmp1.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x96, NULL, args->privkey.rsa.dmq1.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + + /* Write the outer tag and length information. */ + p = sbuf; + r = sc_asn1_put_tag(0x7F48, NULL, tags_len, p, sizeof(sbuf), &p); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + + /* Write inner tags. */ + /* p */ + r = sc_asn1_put_tag(0x92, args->privkey.rsa.p.value, args->privkey.rsa.p.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + /* q */ + r = sc_asn1_put_tag(0x93, args->privkey.rsa.q.value, args->privkey.rsa.q.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + /* 1/q mod p */ + r = sc_asn1_put_tag(0x94, args->privkey.rsa.iqmp.value, args->privkey.rsa.iqmp.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + /* d mod (p-1) */ + r = sc_asn1_put_tag(0x95, args->privkey.rsa.dmp1.value, args->privkey.rsa.dmp1.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + /* d mod (q-1) */ + r = sc_asn1_put_tag(0x96, args->privkey.rsa.dmq1.value, args->privkey.rsa.dmq1.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + + /* Send to card, using chaining or extended APDUs. */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); + apdu.data = sbuf; + apdu.datalen = p - sbuf; + apdu.lc = p - sbuf; + if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0) + { + /* The lower layers will automatically do chaining */ + apdu.flags |= SC_APDU_FLAGS_CHAINING; + } + r = sc_transmit_apdu(card, &apdu); + if(r < 0) + goto out; + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) + { + sc_log(card->ctx, "Key import not supported by the card with that particular key type. " + "Your card may not support the specified algorithm used by the applet / specified by you. " + "In most cases, this happens when trying to import EC keys not supported by your java card. " + "In this case, look for supported field lengths and whether FP and/or F2M are supported. " + "If you tried to import a private RSA key, check the key length."); + } + if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) + { + sc_log(card->ctx, "Key import not allowed by the applet's security policy. " + "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," + " rebuild and reinstall the applet."); + } + if(r < 0) + goto out; + + r = SC_SUCCESS; +out: + sc_mem_clear(sbuf, sizeof(sbuf)); + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * @brief Use PUT DATA to import a private EC key. + * + * Format of transmitted data: + * 0xE0 - Private class, constructed encoding, number one. + * 0x81 - prime + * 0x82 - coefficient A + * 0x83 - coefficient B + * 0x84 - base point G + * 0x85 - order + * 0x87 - cofactor + * 0x88 - private D (private key) + * + * @param card + * @param ec The EC private key to import. + * + * @return SC_ERROR_INVALID_ARGUMENTS: Curve parameters or private component is missing. + * other errors: Transmit errors / errors returned by card. + * ASN1 errors. + */ +static int +isoApplet_put_data_prkey_ec(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) +{ + sc_apdu_t apdu; + u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + int r; + u8 *p; + size_t tags_len; + + LOG_FUNC_CALLED(card->ctx); + + if(!args->privkey.ec.privateD.value + || !args->privkey.ec.params.prime.value + || !args->privkey.ec.params.coefficientA.value + || !args->privkey.ec.params.coefficientB.value + || !args->privkey.ec.params.basePointG.value + || !args->privkey.ec.params.order.value + || !args->privkey.ec.params.coFactor.value + ) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing information about EC private key."); + } + + /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ + tags_len = 0; + r = sc_asn1_put_tag(0x81, NULL, args->privkey.ec.params.prime.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x82, NULL, args->privkey.ec.params.coefficientA.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x83, NULL, args->privkey.ec.params.coefficientB.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x84, NULL, args->privkey.ec.params.basePointG.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x85, NULL, args->privkey.ec.params.order.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x87, NULL, args->privkey.ec.params.coFactor.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + r = sc_asn1_put_tag(0x88, NULL, args->privkey.ec.privateD.len, NULL, 0, NULL); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + tags_len += r; + + /* Write the outer tag and length information. */ + p = sbuf; + r = sc_asn1_put_tag(0xE0, NULL, tags_len, p, sizeof(sbuf), &p); + LOG_TEST_RET(card->ctx, r, "Error handling TLV."); + + /* Write inner tags. */ + r = isoApplet_put_ec_params(card, &args->privkey.ec.params, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + { + sc_log(card->ctx, "Error composing EC params."); + goto out; + } + r = sc_asn1_put_tag(0x88, args->privkey.ec.privateD.value, args->privkey.ec.privateD.len, p, sizeof(sbuf) - (p - sbuf), &p); + if(r < 0) + goto out; + + /* Send to card. */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); + apdu.lc = p - sbuf; + apdu.datalen = p - sbuf; + apdu.data = sbuf; + r = sc_transmit_apdu(card, &apdu); + if(r < 0) + { + sc_log(card->ctx, "APDU transmit failed"); + goto out; + } + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if(apdu.sw1 == 0x6D && apdu.sw2 == 0x00) + { + sc_log(card->ctx, "The applet returned that the PUT DATA instruction byte is not supported. " + "If you are using an older applet version and are trying to import keys, please update your applet first."); + } + else if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) + { + sc_log(card->ctx, "Key import not supported by the card with that particular key type. " + "Your card may not support the specified algorithm used by the applet / specified by you. " + "In most cases, this happens when trying to import EC keys not supported by your java card. " + "In this case, look for supported field lengths and whether FP and/or F2M are supported. " + "If you tried to import a private RSA key, check the key length."); + } + else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) + { + sc_log(card->ctx, "Key import not allowed by the applet's security policy. " + "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," + " rebuild and reinstall the applet."); + } + if(r < 0) + { + sc_log(card->ctx, "Card returned error"); + goto out; + } + + r = SC_SUCCESS; +out: + sc_mem_clear(sbuf, sizeof(sbuf)); + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * @brief Import a private key. + */ +static int +isoApplet_ctl_import_key(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) +{ + int r; + sc_apdu_t apdu; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 *p; + + LOG_FUNC_CALLED(card->ctx); + + /* + * Private keys are not stored in the filesystem. + * ISO 7816-8 - section C.2 describes: + * "Usage of the PUT DATA command for private key import" + * The applet uses this PUT DATA to import private keys, if private key import is allowed. + * + * The first step is to perform a MANAGE SECURITY ENVIRONMENT as it would be done + * with on-card key generation. The second step is PUT DATA (instead of + * GENERATE ASYMMETRIC KEYPAIR). + */ + + /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); + + p = sbuf; + *p++ = 0x80; /* algorithm reference */ + *p++ = 0x01; + *p++ = args->algorithm_ref; + + *p++ = 0x84; /* Private key reference */ + *p++ = 0x01; + *p++ = args->priv_key_ref; + + r = p - sbuf; + p = NULL; + + apdu.lc = r; + apdu.datalen = r; + apdu.data = sbuf; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "%s: APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + + /* PUT DATA */ + switch(args->algorithm_ref) + { + + case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: + r = isoApplet_put_data_prkey_rsa(card, args); + LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); + break; + + case SC_ISOAPPLET_ALG_REF_EC_GEN: + r = isoApplet_put_data_prkey_ec(card, args); + LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); + break; + + default: + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Uknown algorithm refernce."); + } + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static int +isoApplet_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) +{ + int r = 0; + + LOG_FUNC_CALLED(card->ctx); + switch (cmd) + { + case SC_CARDCTL_ISOAPPLET_GENERATE_KEY: + r = isoApplet_ctl_generate_key(card, + (sc_cardctl_isoApplet_genkey_t *) ptr); + break; + case SC_CARDCTL_ISOAPPLET_IMPORT_KEY: + r = isoApplet_ctl_import_key(card, + (sc_cardctl_isoApplet_import_key_t *) ptr); + break; + default: + r = SC_ERROR_NOT_SUPPORTED; + } + LOG_FUNC_RETURN(card->ctx, r); +} + +static int +isoApplet_set_security_env(sc_card_t *card, + const sc_security_env_t *env, int se_num) +{ + sc_apdu_t apdu; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 *p; + int r, locked = 0; + struct isoApplet_drv_data *drvdata = DRVDATA(card); + + LOG_FUNC_CALLED(card->ctx); + + if(se_num != 0) + { + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, + "IsoApplet does not support storing of security environments."); + } + assert(card != NULL && env != 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 = 0xB6; + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; + } + p = sbuf; + + if (env->flags & SC_SEC_ENV_ALG_PRESENT) + { + + switch(env->algorithm) + { + + case SC_ALGORITHM_RSA: + if( env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1 ) + { + drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_RSA_PAD_PKCS1; + } + else + { + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports RSA with PKCS1 padding."); + } + break; + + case SC_ALGORITHM_EC: + if( env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW ) + { + drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_ECDSA; + drvdata->sec_env_ec_field_length = env->algorithm_ref; + } + else + { + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports raw ECDSA."); + } + break; + + default: + LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported algorithm."); + } + + *p++ = 0x80; /* algorithm reference */ + *p++ = 0x01; + *p++ = drvdata->sec_env_alg_ref; + } + + if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) + { + *p++ = 0x81; + *p++ = 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) + *p++ = 0x83; + else + *p++ = 0x84; + *p++ = env->key_ref_len; + assert(sizeof(sbuf) - (p - sbuf) >= env->key_ref_len); + memcpy(p, env->key_ref, env->key_ref_len); + p += env->key_ref_len; + } + r = p - sbuf; + apdu.lc = r; + apdu.datalen = r; + apdu.data = sbuf; + + if (se_num > 0) + { + r = sc_lock(card); + LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); + locked = 1; + } + + if (apdu.datalen != 0) + { + r = sc_transmit_apdu(card, &apdu); + if (r) + { + 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_log(card->ctx, "%s: Card returned error", sc_strerror(r)); + goto err; + } + } + + if (se_num <= 0) + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num); + r = sc_transmit_apdu(card, &apdu); + sc_unlock(card); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_FUNC_RETURN(card->ctx, r); +err: + if (locked) + sc_unlock(card); + LOG_FUNC_RETURN(card->ctx, r); +} + +static int +isoApplet_compute_signature(struct sc_card *card, + const u8 *data, size_t datalen, + u8 *out, size_t outlen) +{ + struct sc_context *ctx = card->ctx; + struct isoApplet_drv_data *drvdata = DRVDATA(card); + int r; + + LOG_FUNC_CALLED(ctx); + + r = iso_ops->compute_signature(card, data, datalen, out, outlen); + if(r < 0) + { + LOG_FUNC_RETURN(ctx, r); + } + + /* If ECDSA was used, the ASN.1 sequence of integers R,S returned by the + * card needs to be converted to the raw concatenation of R,S for PKCS#11. */ + if(drvdata->sec_env_alg_ref == ISOAPPLET_ALG_REF_ECDSA) + { + u8* p = NULL; + size_t len = (drvdata->sec_env_ec_field_length + 7) / 8 * 2; + + if (len > outlen) + LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL); + + p = calloc(1,len); + if (!p) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + + r = sc_asn1_sig_value_sequence_to_rs(ctx, out, r, p, len); + if (!r) { + memcpy(out, p, len); + r = len; + } + + free(p); + } + LOG_FUNC_RETURN(ctx, r); +} + +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); + + 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); +} + +static struct sc_card_driver *sc_get_driver(void) +{ + sc_card_driver_t *iso_drv = sc_get_iso7816_driver(); + + if(iso_ops == NULL) + { + iso_ops = iso_drv->ops; + } + + isoApplet_ops = *iso_drv->ops; + + isoApplet_ops.match_card = isoApplet_match_card; + isoApplet_ops.init = isoApplet_init; + isoApplet_ops.finish = isoApplet_finish; + + isoApplet_ops.card_ctl = isoApplet_card_ctl; + + isoApplet_ops.create_file = isoApplet_create_file; + isoApplet_ops.process_fci = isoApplet_process_fci; + isoApplet_ops.set_security_env = isoApplet_set_security_env; + isoApplet_ops.compute_signature = isoApplet_compute_signature; + isoApplet_ops.get_challenge = isoApplet_get_challenge; + + /* unsupported functions */ + isoApplet_ops.write_binary = NULL; + isoApplet_ops.read_record = NULL; + isoApplet_ops.write_record = NULL; + isoApplet_ops.append_record = NULL; + isoApplet_ops.update_record = NULL; + isoApplet_ops.restore_security_env = NULL; + + return &isoApplet_drv; +} + +struct sc_card_driver * sc_get_isoApplet_driver(void) +{ + return sc_get_driver(); +} diff --git a/src/libopensc/card-itacns.c b/src/libopensc/card-itacns.c index 08c60415..d73057e6 100644 --- a/src/libopensc/card-itacns.c +++ b/src/libopensc/card-itacns.c @@ -479,6 +479,65 @@ static int itacns_select_file(sc_card_t *card, SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } +static int itacns_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) +{ + sc_path_t path; + sc_file_t *file; + size_t len; + int r; + u8 rbuf[256]; + + 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_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Reading EF_IDCarta.\n"); + + sc_format_path("3F0010001003", &path); + + r = sc_select_file(card, &path, &file); + if (r != SC_SUCCESS) { + return SC_ERROR_WRONG_CARD; + } + len = file->size; + + //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. + if (len != 16) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Unexpected file length of EF_IDCarta (%lu)\n", + (unsigned long) len); + } + + r = sc_read_binary(card, 0, rbuf, 256, 0); + if ( r != 16 ) { + return SC_ERROR_WRONG_CARD; + } + + /* cache serial number */ + memcpy(card->serialnr.value, rbuf, 16); + card->serialnr.len = 16; + /* copy and return serial number */ + memcpy(serial, &card->serialnr, sizeof(*serial)); + + return SC_SUCCESS; +} + +static int +itacns_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) +{ + switch (cmd) { + case SC_CARDCTL_GET_SERIALNR: + return itacns_get_serialnr(card, ptr); + } + return SC_ERROR_NOT_SUPPORTED; +} static struct sc_card_driver * sc_get_driver(void) { @@ -494,6 +553,7 @@ static struct sc_card_driver * sc_get_driver(void) itacns_ops.read_binary = itacns_read_binary; itacns_ops.list_files = itacns_list_files; itacns_ops.select_file = itacns_select_file; + itacns_ops.card_ctl = itacns_card_ctl; return &itacns_drv; } diff --git a/src/libopensc/card-jcop.c b/src/libopensc/card-jcop.c index d01324c0..08a10972 100644 --- a/src/libopensc/card-jcop.c +++ b/src/libopensc/card-jcop.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-masktech.c b/src/libopensc/card-masktech.c new file mode 100644 index 00000000..9cd501e9 --- /dev/null +++ b/src/libopensc/card-masktech.c @@ -0,0 +1,377 @@ +/* + * card-masktech.c: Support for Masktech smart cards using the MTCOS operating system. + * + * Copyright (C) 2011-2015 MaskTech GmbH Fischerstrasse 19, 87435 Kempten, Germany + * Copyright (C) 2011 Andrey Uvarov (X-Infotech) + * Copyright (C) 2015 Vincent Le Toux (My Smart Logon) + * + * 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 +#include + +#include "internal.h" +#include "cardctl.h" +#include "iso7816.h" + +static struct sc_atr_table masktech_atrs[] = { + {"3B:89:80:01:4D:54:43:4F:53:70:02:02:05:3B", NULL, NULL, + SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, + {"3B:88:80:01:00:00:00:00:77:81:81:00:7E", NULL, NULL, + SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, + {"3B:9D:13:81:31:60:37:80:31:C0:69:4D:54:43:4F:53:73:02:02:05:41", NULL, NULL, + SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, + {"3B:9D:13:81:31:60:37:80:31:C0:69:4D:54:43:4F:53:73:02:01:02:45", NULL, NULL, + SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, + {NULL, NULL, NULL, 0, 0, NULL} +}; + +static struct sc_card_operations *iso_ops; +static struct sc_card_operations masktech_ops; +static struct sc_card_driver masktech_drv = { + "MaskTech Smart Card", + "MaskTech", + &masktech_ops, + masktech_atrs, 0, NULL +}; + +struct masktech_private_data { + /* save the key reference set at set_masktech_set_security_env to recover it as the signature step */ + int rsa_key_ref; + +}; + +static int masktech_match_card(sc_card_t * card) +{ + /* check if the ATR is in the known ATR */ + if (_sc_match_atr(card, masktech_atrs, &card->type) < 0) + return 0; + + return 1; +} + +static int masktech_init(sc_card_t * card) +{ + unsigned long flags; + struct masktech_private_data *data; + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "masktech_init()\n"); + + /* private data kept during the live of the driver */ + if (!(data = (struct masktech_private_data *) malloc(sizeof(*data)))) + return SC_ERROR_OUT_OF_MEMORY; + card->drv_data = data; + + /* supported RSA keys and how padding is done */ + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; + _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); + card->caps |= SC_CARD_CAP_APDU_EXT; + return SC_SUCCESS; +} + + +static int masktech_finish(sc_card_t *card) +{ + /* free the private data */ + if (card->drv_data) { + free(card->drv_data); + card->drv_data = NULL; + } + return 0; +} + +static int masktech_set_security_env(sc_card_t *card, + const sc_security_env_t *env, + int se_num) +{ + struct masktech_private_data *private_data; + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "masktech_set_security_env(), keyRef = 0x%0x, algo = 0x%0x\n", + *env->key_ref, env->algorithm_flags); + + private_data = (struct masktech_private_data *) card->drv_data; + if (!private_data) + return SC_ERROR_INTERNAL; + + /* save the key reference */ + if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { + if (env->key_ref_len != 1) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Invalid key reference supplied.\n"); + return SC_ERROR_NOT_SUPPORTED; + } + private_data->rsa_key_ref = env->key_ref[0]; + } + + return iso_ops->set_security_env(card, env, se_num); +} + +static int masktech_compute_signature(sc_card_t *card, + const u8 * data, + size_t datalen, + u8 * out, + size_t outlen) +{ + + struct masktech_private_data *private_data; + u8 sha256hash[32]; + static const u8 hdr_sha256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 + }; + assert(card != NULL && data != NULL && out != NULL); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "masktech_compute_signature()\n"); + + /* retrieve the key reference */ + private_data = (struct masktech_private_data *) card->drv_data; + if (!private_data) + return SC_ERROR_INTERNAL; + + if (private_data->rsa_key_ref == 0x88) + { + /* for this key reference, the card supports only SHA256 hash and the hash is computed using a digest info */ + /* check that it is a SHA256 with digest info*/ + if ((datalen != sizeof(hdr_sha256) + 32) || (memcmp(hdr_sha256, data, sizeof(hdr_sha256)) != 0)) + { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "It is not a SHA256 with digestinfo\n"); + return SC_ERROR_NOT_SUPPORTED; + } + /* extract the SHA-256 hash */ + memcpy(sha256hash, (u8 *)(data+(datalen-32)), 32);//only last 32 byte => sha256 + /* default ISO 7816 functions */ + return iso_ops->compute_signature(card, sha256hash, 32, out, outlen); + } + else + { + /* default ISO 7816 functions */ + return iso_ops->compute_signature(card, data, datalen, out, outlen); + } +} + +static int masktech_decipher(sc_card_t *card, + const u8 * crgram, + size_t crgram_len, + u8 * out, + size_t outlen) +{ + int r; + sc_apdu_t apdu; + u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + + assert(card != NULL && crgram != NULL && out != NULL); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "masktech_decipher()\n"); + + if (crgram_len > SC_MAX_EXT_APDU_BUFFER_SIZE) { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); + } + + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + /* the card doesn't support anything else here (+1 / -1 is not working) */ + apdu.le = 65536; + + apdu.data = crgram; + apdu.lc = crgram_len; + apdu.datalen = crgram_len; + + 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) { + size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; + + memcpy(out, apdu.resp, len); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len); + } + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); +} + +/* unblock pin cmd */ +static int masktech_pin_unblock(sc_card_t *card, + struct sc_pin_cmd_data *data, + int *tries_left) +{ + int rv = 0; + struct sc_pin_cmd_data verify_data; + struct sc_pin_cmd_data reset_data; + + /* Build a SC_PIN_CMD_VERIFY APDU on PUK */ + memset(&verify_data, 0, sizeof(verify_data)); + verify_data.cmd = SC_PIN_CMD_VERIFY; + verify_data.pin_type = 1; + verify_data.pin_reference = 0x83; + verify_data.pin1 = data->pin1; + verify_data.flags = data->flags; + verify_data.pin1.prompt = data->pin1.prompt; + + rv = iso_ops->pin_cmd(card, &verify_data, tries_left); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed - verify unblock PIN"); + + /* Build a SC_PIN_CMD_UNBLOCK APDU */ + memset(&reset_data, 0, sizeof(reset_data)); + reset_data.cmd = SC_PIN_CMD_UNBLOCK; + reset_data.pin_type = 1; + reset_data.pin_reference = 0x91; + /* pin1 is set to null on purpose and flag set to implicit change + => if there is a pinpad reader, do not ask for pin1 */ + reset_data.pin2 = data->pin2; + reset_data.flags = data->flags | SC_PIN_CMD_IMPLICIT_CHANGE; + reset_data.pin2.prompt = data->pin2.prompt; + + rv = iso_ops->pin_cmd(card, &reset_data, tries_left); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed - reset unblock PIN"); + + return 0; +} + +static int masktech_pin_change(sc_card_t *card, + struct sc_pin_cmd_data *data, + int *tries_left) +{ + int rv = 0; + struct sc_pin_cmd_data verify_data; + struct sc_pin_cmd_data change_data; + + /* Build a SC_PIN_CMD_VERIFY APDU */ + memset(&verify_data, 0, sizeof(verify_data)); + verify_data.cmd = SC_PIN_CMD_VERIFY; + verify_data.pin_type = 1; + verify_data.pin_reference = data->pin_reference; + verify_data.pin1 = data->pin1; + verify_data.flags = data->flags; + verify_data.pin1.prompt = data->pin1.prompt; + + rv = iso_ops->pin_cmd(card, &verify_data, tries_left); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed - verify change PIN"); + + /* Build a SC_PIN_CMD_CHANGE APDU */ + memset(&change_data, 0, sizeof(change_data)); + change_data.cmd = SC_PIN_CMD_CHANGE; + change_data.pin_type = 1; + change_data.pin_reference = data->pin_reference; + /* pin1 is set to null on purpose and flag set to implicit change + => if there is a pinpad reader, do not ask for pin1 */ + change_data.pin2 = data->pin2; + change_data.flags = data->flags | SC_PIN_CMD_IMPLICIT_CHANGE; + 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"); + + return 0; +} + +static int masktech_pin_cmd(sc_card_t *card, + struct sc_pin_cmd_data *data, + int *tries_left) +{ + int rv; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + switch(data->cmd) + { + case SC_PIN_CMD_UNBLOCK: + rv = masktech_pin_unblock(card, data, tries_left); + break; + case SC_PIN_CMD_CHANGE: + rv = masktech_pin_change(card, data, tries_left); + break; + default: + rv = iso_ops->pin_cmd(card, data, tries_left); + break; + } + return rv; + + +} + +static int masktech_get_serialnr(sc_card_t * card, sc_serial_number_t * serial) +{ + struct sc_apdu apdu; + unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE-2]; + int rv; + + if (!serial) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS); + + /* Get smart card serial number */ + card->cla = 0x80; + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x08, 0x00, 0x00); + apdu.resplen = sizeof(apdu_resp); + apdu.resp = apdu_resp; + + rv = sc_transmit_apdu(card, &apdu); + card->cla = 0x00; + + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed"); + + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) + return SC_ERROR_INTERNAL; + + if (SC_MAX_SERIALNR < apdu.resplen) + { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); + } + /* cache serial number */ + card->serialnr.len = apdu.resplen; + memcpy(card->serialnr.value, apdu.resp, card->serialnr.len); + + /* copy and return serial number */ + if (serial) + memcpy(serial, &card->serialnr, sizeof(*serial)); + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); +} + + +static int masktech_card_ctl(sc_card_t * card, unsigned long cmd, void *ptr) +{ + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "masktech_card_ctl()\n"); + switch (cmd) { + case SC_CARDCTL_GET_SERIALNR: + return masktech_get_serialnr(card, (sc_serial_number_t *) ptr); + default: + return SC_ERROR_NOT_SUPPORTED; + } +} + +static struct sc_card_driver *sc_get_driver(void) +{ + + if (iso_ops == NULL) + iso_ops = sc_get_iso7816_driver()->ops; + + masktech_ops = *iso_ops; + + masktech_ops.match_card = masktech_match_card; + masktech_ops.init = masktech_init; + masktech_ops.finish = masktech_finish; + masktech_ops.set_security_env = masktech_set_security_env; + masktech_ops.compute_signature = masktech_compute_signature; + masktech_ops.decipher = masktech_decipher; + masktech_ops.pin_cmd = masktech_pin_cmd; + masktech_ops.card_ctl = masktech_card_ctl; + return &masktech_drv; +} + +struct sc_card_driver *sc_get_masktech_driver(void) +{ + return sc_get_driver(); +} diff --git a/src/libopensc/card-mcrd.c b/src/libopensc/card-mcrd.c index 52d710f9..3b4481ce 100644 --- a/src/libopensc/card-mcrd.c +++ b/src/libopensc/card-mcrd.c @@ -22,7 +22,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -379,13 +381,13 @@ static int mcrd_init(sc_card_t * card) priv->curpathlen = 1; sc_format_path ("3f00", &tmppath); - sc_select_file (card, &tmppath, NULL); + r = sc_select_file (card, &tmppath, NULL); /* Not needed for the fixed EstEID profile */ if (!is_esteid_card(card)) load_special_files(card); - return SC_SUCCESS; + return r; } static int mcrd_finish(sc_card_t * card) @@ -419,6 +421,8 @@ static int load_special_files(sc_card_t * card) if (dfi && dfi->rule_file) return 0; /* yes. */ clear_special_files(dfi); + if (!dfi) + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); /* Read rule file. Note that we bypass our cache here. */ r = select_part(card, MCRD_SEL_EF, EF_Rule, NULL); @@ -1188,7 +1192,9 @@ static int mcrd_set_security_env(sc_card_t * card, /* Make sure we always start from MF */ sc_format_path ("3f00", &tmppath); - sc_select_file (card, &tmppath, NULL); + r = sc_select_file (card, &tmppath, NULL); + if (r < 0) + return r; /* We now know that cache is not valid */ select_esteid_df(card); switch (env->operation) { diff --git a/src/libopensc/card-miocos.c b/src/libopensc/card-miocos.c index 89638f5b..ad8add74 100644 --- a/src/libopensc/card-miocos.c +++ b/src/libopensc/card-miocos.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-muscle.c b/src/libopensc/card-muscle.c index 3b0562bf..d3e94a03 100644 --- a/src/libopensc/card-muscle.c +++ b/src/libopensc/card-muscle.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -41,6 +43,8 @@ static struct sc_card_driver muscle_drv = { }; static 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 */ { "3b:d5:18:00:81:31:3a:7d:80:73:c8:21:10:30", NULL, NULL, SC_CARD_TYPE_MUSCLE_ETOKEN_72K, 0, NULL }, /* JCOP31 v2.4.1 contact interface */ @@ -57,7 +61,7 @@ typedef struct muscle_private { unsigned short verifiedPins; mscfs_t *fs; int rsa_key_ref; - + } muscle_private_t; static int muscle_finish(sc_card_t *card) @@ -76,13 +80,13 @@ static int muscle_match_card(sc_card_t *card) sc_apdu_t apdu; u8 response[64]; int r; - + /* Since we send an APDU, the card's logout function may be called... * however it's not always properly nulled out... */ card->ops->logout = NULL; - if (msc_select_applet(card, muscleAppletId, 5) == 1) { - /* Muscle applet is present, check the protocol version to be sure */ + if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) == 1) { + /* Muscle applet is present, check the protocol version to be sure */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x3C, 0x00, 0x00); apdu.cla = 0xB0; apdu.le = 64; @@ -149,16 +153,16 @@ static int muscle_create_directory(sc_card_t *card, sc_file_t *file) int r; if(id == 0) /* No null name files */ return SC_ERROR_INVALID_ARGUMENTS; - + /* No nesting directories */ if(fs->currentPath[0] != 0x3F || fs->currentPath[1] != 0x00) return SC_ERROR_NOT_SUPPORTED; oid[0] = ((id & 0xFF00) >> 8) & 0xFF; oid[1] = id & 0xFF; oid[2] = oid[3] = 0; - + objectSize = file->size; - + muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm); r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm); mscfs_clear_cache(fs); @@ -180,9 +184,9 @@ static int muscle_create_file(sc_card_t *card, sc_file_t *file) return SC_ERROR_NOT_SUPPORTED; if(file->id == 0) /* No null name files */ return SC_ERROR_INVALID_ARGUMENTS; - + muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm); - + mscfs_lookup_local(fs, file->id, &objectId); r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm); mscfs_clear_cache(fs); @@ -197,7 +201,7 @@ static int muscle_read_binary(sc_card_t *card, unsigned int idx, u8* buf, size_t msc_id objectId; u8* oid = objectId.id; mscfs_file_t *file; - + r = mscfs_check_selection(fs, -1); if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); file = &fs->cache.array[fs->currentFileIndex]; @@ -223,7 +227,7 @@ static int muscle_update_binary(sc_card_t *card, unsigned int idx, const u8* buf r = mscfs_check_selection(fs, -1); if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); file = &fs->cache.array[fs->currentFileIndex]; - + objectId = file->objectId; /* memcpy(objectId.id, file->objectId.id, 4); */ if(!file->ef) { @@ -235,7 +239,7 @@ static int muscle_update_binary(sc_card_t *card, unsigned int idx, const u8* buf int newFileSize = idx + count; u8* buffer = malloc(newFileSize); 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 */ if(r < 0) goto update_bin_free_buffer; @@ -270,7 +274,7 @@ static int muscle_delete_mscfs_file(sc_card_t *card, mscfs_file_t *file_data) mscfs_file_t *childFile; /* Delete children */ mscfs_check_cache(fs); - + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DELETING Children of: %02X%02X%02X%02X\n", oid[0],oid[1],oid[2],oid[3]); @@ -278,7 +282,7 @@ static int muscle_delete_mscfs_file(sc_card_t *card, mscfs_file_t *file_data) msc_id objectId; childFile = &fs->cache.array[x]; objectId = childFile->objectId; - + if(0 == memcmp(oid + 2, objectId.id, 2)) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DELETING: %02X%02X%02X%02X\n", @@ -365,11 +369,11 @@ static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** f int r = 0; int objectIndex; u8* oid; - + mscfs_check_cache(fs); r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, &objectIndex); if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); - + /* Check if its the right type */ if(requiredType >= 0 && requiredType != file_data->ef) { SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS); @@ -387,7 +391,7 @@ static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** f fs->currentFile[0] = 0; fs->currentFile[1] = 0; } - + fs->currentFileIndex = objectIndex; if(file_out) { sc_file_t *file; @@ -401,7 +405,7 @@ static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** f file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; } - + /* Setup ACLS */ if(file_data->ef) { muscle_load_file_acls(file, file_data); @@ -409,7 +413,7 @@ static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** f muscle_load_dir_acls(file, file_data); /* Setup directory acls... */ } - + file->magic = SC_FILE_MAGIC; *file_out = file; } @@ -420,9 +424,9 @@ static int muscle_select_file(sc_card_t *card, const sc_path_t *path_in, sc_file_t **file_out) { int r; - + assert(card != NULL && path_in != NULL); - + switch (path_in->type) { case SC_PATH_TYPE_FILE_ID: r = select_item(card, path_in, file_out, 1); @@ -449,7 +453,7 @@ static int _listFile(mscfs_file_t *file, int reset, void *udata) static int muscle_init(sc_card_t *card) { muscle_private_t *priv; - + card->name = "MuscleApplet"; card->drv_data = malloc(sizeof(muscle_private_t)); if(!card->drv_data) { @@ -467,24 +471,28 @@ static int muscle_init(sc_card_t *card) priv->fs->listFile = _listFile; card->cla = 0xB0; - + card->flags |= SC_CARD_FLAG_RNG; card->caps |= SC_CARD_CAP_RNG; /* Card type detection */ _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->type == SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU) { + /* Tyfone JCOP v242R2 card that doesn't support extended APDUs */ + } /* FIXME: Card type detection */ if (1) { unsigned long flags; - + flags = SC_ALGORITHM_RSA_RAW; flags |= SC_ALGORITHM_RSA_HASH_NONE; flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; @@ -503,7 +511,7 @@ static int muscle_list_files(sc_card_t *card, u8 *buf, size_t bufLen) int count = 0; mscfs_check_cache(priv->fs); - + for(x = 0; x < fs->cache.size; x++) { u8* oid= fs->cache.array[x].objectId.id; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, @@ -585,7 +593,7 @@ static int muscle_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *cmd, return SC_ERROR_NOT_SUPPORTED; } - + } static int muscle_card_extract_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info) @@ -668,7 +676,7 @@ static int muscle_set_security_env(sc_card_t *card, /* ADJUST FOR PKCS1 padding support for decryption only */ if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) || (env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card supports only raw RSA.\n"); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card supports only raw RSA.\n"); return SC_ERROR_NOT_SUPPORTED; } if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { @@ -705,21 +713,21 @@ static int muscle_decipher(sc_card_t * card, size_t out_len) { muscle_private_t* priv = MUSCLE_DATA(card); - + u8 key_id; int r; /* saniti check */ if (priv->env.operation != SC_SEC_OPERATION_DECIPHER) return SC_ERROR_INVALID_ARGUMENTS; - + key_id = priv->rsa_key_ref * 2; /* Private key */ if (out_len < crgram_len) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Output buffer too small"); return SC_ERROR_BUFFER_TOO_SMALL; } - + r = msc_compute_crypt(card, key_id, 0x00, /* RSA NO PADDING */ @@ -738,14 +746,14 @@ static int muscle_compute_signature(sc_card_t *card, const u8 *data, muscle_private_t* priv = MUSCLE_DATA(card); u8 key_id; int r; - + key_id = priv->rsa_key_ref * 2; /* Private key */ - + if (outlen < data_len) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Output buffer too small"); return SC_ERROR_BUFFER_TOO_SMALL; } - + r = msc_compute_crypt(card, key_id, 0x00, /* RSA NO PADDING */ @@ -811,9 +819,9 @@ static struct sc_card_driver * sc_get_driver(void) muscle_ops.match_card = muscle_match_card; muscle_ops.init = muscle_init; muscle_ops.finish = muscle_finish; - + muscle_ops.get_challenge = muscle_get_challenge; - + muscle_ops.set_security_env = muscle_set_security_env; muscle_ops.restore_security_env = muscle_restore_security_env; muscle_ops.compute_signature = muscle_compute_signature; diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c index 2e5f9c68..9d6417f1 100644 --- a/src/libopensc/card-myeid.c +++ b/src/libopensc/card-myeid.c @@ -16,9 +16,11 @@ * 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 #include @@ -28,21 +30,21 @@ #include "cardctl.h" #include "types.h" -#define LOAD_KEY_MODULUS 0x80 -#define LOAD_KEY_PUBLIC_EXPONENT 0x81 -#define LOAD_KEY_PRIME_P 0x83 -#define LOAD_KEY_PRIME_Q 0x84 -#define LOAD_KEY_DP1 0x85 -#define LOAD_KEY_DQ1 0x86 -#define LOAD_KEY_INVQ 0x87 -#define LOAD_KEY_MODE_EC_PRIV 0x87 -#define LOAD_KEY_MODE_EC_PUB 0x86 +#define LOAD_KEY_MODULUS 0x80 +#define LOAD_KEY_PUBLIC_EXPONENT 0x81 +#define LOAD_KEY_PRIME_P 0x83 +#define LOAD_KEY_PRIME_Q 0x84 +#define LOAD_KEY_DP1 0x85 +#define LOAD_KEY_DQ1 0x86 +#define LOAD_KEY_INVQ 0x87 +#define LOAD_KEY_MODE_EC_PRIV 0x87 +#define LOAD_KEY_MODE_EC_PUB 0x86 -#define LOAD_KEY_EC_PRIVATE 0x97 -#define LOAD_KEY_EC_PUBLIC 0x96 +#define LOAD_KEY_EC_PRIVATE 0x97 +#define LOAD_KEY_EC_PUBLIC 0x96 -#define MYEID_STATE_CREATION 0x01 -#define MYEID_STATE_ACTIVATED 0x07 +#define MYEID_STATE_CREATION 0x01 +#define MYEID_STATE_ACTIVATED 0x07 #define MYEID_ECC_SUPPORT @@ -59,15 +61,37 @@ static struct sc_card_driver myeid_drv = { static const char *myeid_atrs[] = { "3B:F5:18:00:FF:81:31:FE:45:4D:79:45:49:44:65", "3B:F5:18:00:00:81:31:FE:45:4D:79:45:49:44:9A", - "3B:85:80:01:4D:79:45:49:44:78", - "3B:89:80:01:09:38:33:B1:4D:79:45:49:44:4C", - NULL + "3B:85:80:01:4D:79:45:49:44:78", + "3B:89:80:01:09:38:33:B1:4D:79:45:49:44:4C", + NULL }; typedef struct myeid_private_data { int card_state; + + unsigned short change_counter; + /* the driver sets sec_env pointer in myeid_set_security_env and + it is used immediately in myeid_decipher to differentiate between RSA decryption and + ECDH key agreement. Note that this pointer is usually not valid + after this pair of calls and must not be used elsewhere. */ + const struct sc_security_env* sec_env; } myeid_private_data_t; +static struct myeid_supported_ec_curves { + char *curve_name; + struct sc_object_id curve_oid; + size_t size; +} ec_curves[] = { + {"secp192r1", {{1, 2, 840, 10045, 3, 1, 1, -1}},192}, + /* {"secp224r1", {{1, 3, 132, 0, 33, -1}}, 224}, */ + {"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}, +}; + +static int myeid_get_info(struct sc_card *card, u8 *rbuf, size_t buflen); + static int myeid_match_card(struct sc_card *card) { int i, match = -1; @@ -95,20 +119,34 @@ static int myeid_match_card(struct sc_card *card) static int myeid_init(struct sc_card *card) { - unsigned long flags = 0, - ext_flags = 0; + unsigned long flags = 0, + ext_flags = 0; myeid_private_data_t *priv; + u8 appletInfo[20]; + size_t appletInfoLen; + int r; LOG_FUNC_CALLED(card->ctx); priv = calloc(1, sizeof(myeid_private_data_t)); if (!priv) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + priv->card_state = SC_FILE_STATUS_CREATION; card->drv_data = priv; + /* find out MyEID version */ + + appletInfoLen = 20; + + r = myeid_get_info(card, appletInfo, appletInfoLen); + + LOG_TEST_RET(card->ctx, r, "Failed to get MyEID applet information."); + + priv->change_counter = appletInfo[19] | appletInfo[18] << 8; + flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_ONBOARD_KEY_GEN; flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1; - + _sc_card_add_rsa_alg(card, 512, flags, 0); _sc_card_add_rsa_alg(card, 768, flags, 0); _sc_card_add_rsa_alg(card, 1024, flags, 0); @@ -116,14 +154,21 @@ static int myeid_init(struct sc_card *card) _sc_card_add_rsa_alg(card, 2048, flags, 0); #ifdef MYEID_ECC_SUPPORT - flags |= SC_ALGORITHM_ECDSA_RAW; - ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; - _sc_card_add_ec_alg(card, 192, flags, ext_flags); - _sc_card_add_ec_alg(card, 224, flags, ext_flags); - _sc_card_add_ec_alg(card, 256, flags, ext_flags); + /* show ECC algorithms if the applet version of the inserted card supports them */ + if ((card->version.fw_major == 3 && card->version.fw_minor > 5) || + card->version.fw_major >= 4) { + int i; + + flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN; + flags |= SC_ALGORITHM_ECDSA_HASH_NONE | SC_ALGORITHM_ECDSA_HASH_SHA1; + ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; + + for (i=0; ec_curves[i].curve_name != NULL; i++) + _sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].curve_oid); + } #endif - + /* State that we have an RNG */ card->caps |= SC_CARD_CAP_RNG; @@ -241,7 +286,7 @@ static int myeid_list_files(struct sc_card *card, u8 *buf, size_t buflen) struct sc_apdu apdu; int r; - LOG_FUNC_CALLED(card->ctx); + LOG_FUNC_CALLED(card->ctx); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0xA1); apdu.resp = buf; @@ -257,7 +302,7 @@ static int myeid_list_files(struct sc_card *card, u8 *buf, size_t buflen) } static int myeid_process_fci(struct sc_card *card, struct sc_file *file, - const u8 *buf, size_t buflen) + const u8 *buf, size_t buflen) { myeid_private_data_t *priv = (myeid_private_data_t *) card->drv_data; size_t taglen = 0; @@ -279,8 +324,8 @@ static int myeid_process_fci(struct sc_card *card, struct sc_file *file, } if(file->sec_attr_len >= 3) { - sc_log(card->ctx, "id (%X) sec_attr (%X %X %X)", file->id, - file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]); + sc_log(card->ctx, "id (%X) sec_attr (%X %X %X)", file->id, + file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]); } tag = sc_asn1_find_tag(NULL, buf, buflen, 0x8A, &taglen); if (tag != NULL && taglen > 0) @@ -302,17 +347,20 @@ static int myeid_process_fci(struct sc_card *card, struct sc_file *file, } static int encode_file_structure(sc_card_t *card, const sc_file_t *file, - u8 *out, size_t *outlen) + u8 *buf, size_t *outlen) { const sc_acl_entry_t *read, *update, *delete, *generate; - u8 buf[40]; - int i; + size_t i; LOG_FUNC_CALLED(card->ctx); + + if (!buf || !outlen || *outlen < 45) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + /* PrivateKey * 0E0000019 6217 81020400 820111 83024B01 8603000000 85028000 8A0100 RESULT 6984 - * 6217 81020400 820111 83024B01 8603000000 85021000 8A0100 */ - memset(buf, 0x0, sizeof(buf)); + * 6217 81020400 820111 83024B01 8603000000 85021000 8A0100 */ + memset(buf, 0x0, *outlen); buf[0] = 0x62; buf[1] = 0x17; @@ -340,17 +388,15 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file, buf[16] = 0xFF; buf[17] = 0xFF; - if (file->sec_attr_len == 3 && file->sec_attr) - { + if (file->sec_attr_len == 3 && file->sec_attr) { buf[15] = file->sec_attr[0]; buf[16] = file->sec_attr[1]; buf[17] = file->sec_attr[2]; sc_log(card->ctx, "id (%X), sec_attr %X %X %X", file->id, - file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]); + file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]); } - else - { + else { delete = sc_file_get_acl_entry(file, SC_AC_OP_DELETE); switch (file->type) { @@ -412,10 +458,10 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file, buf[25] = 0x84; buf[26] = (u8)file->namelen; - for(i=0;i < (int)file->namelen;i++) - buf[i + 26] = file->name[i]; + for(i=0;i < file->namelen;i++) + buf[i + 27] = file->name[i]; - buf[1] = 0x19 + file->namelen + 2; + buf[1] = 27 + file->namelen; } break; default: @@ -424,16 +470,15 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file, } *outlen = buf[1]+2; - memcpy(out, buf, *outlen); - LOG_FUNC_RETURN(card->ctx, 0); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } static int myeid_create_file(struct sc_card *card, struct sc_file *file) { sc_apdu_t apdu; - u8 sbuf[32]; - size_t buflen; + u8 sbuf[45]; + size_t buflen = sizeof sbuf; int r; LOG_FUNC_CALLED(card->ctx); @@ -479,14 +524,56 @@ static int myeid_delete_file(struct sc_card *card, const struct sc_path *path) LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); } +static int myeid_pin_info(sc_card_t *card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + sc_apdu_t apdu; + int r; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference); + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + + if (r == SC_ERROR_PIN_CODE_INCORRECT) { + data->pin1.tries_left = apdu.sw2 & 0xF; + r = SC_SUCCESS; + } else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) { + data->pin1.tries_left = 0; + r = SC_SUCCESS; + } + LOG_TEST_RET(card->ctx, r, "Check SW error"); + + if (r == SC_SUCCESS) + { + data->pin1.pad_length = data->pin2.pad_length = 8; + data->pin1.pad_char = data->pin2.pad_char = 0xFF; + } + + + if (tries_left != NULL) { + *tries_left = data->pin1.tries_left; + } + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, - int *tries_left) + int *tries_left) { myeid_private_data_t *priv = (myeid_private_data_t *) card->drv_data; LOG_FUNC_CALLED(card->ctx); + + if (data->cmd == SC_PIN_CMD_GET_INFO) + { + return myeid_pin_info(card, data, tries_left); + } + sc_log(card->ctx, "ref (%d), pin1 len(%d), pin2 len (%d)\n", - data->pin_reference, data->pin1.len, data->pin2.len); + data->pin_reference, data->pin1.len, data->pin2.len); if(data->pin1.len > 8 || data->pin2.len > 8) LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_PIN_LENGTH); @@ -508,7 +595,7 @@ static int myeid_set_security_env_rsa(sc_card_t *card, const sc_security_env_t * sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; - int r, locked = 0; + int r; assert(card != NULL && env != NULL); LOG_FUNC_CALLED(card->ctx); @@ -564,11 +651,6 @@ static int myeid_set_security_env_rsa(sc_card_t *card, const sc_security_env_t * apdu.datalen = r; apdu.data = sbuf; apdu.resplen = 0; - if (se_num > 0) { - r = sc_lock(card); - LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); - locked = 1; - } if (apdu.datalen != 0) { r = sc_transmit_apdu(card, &apdu); @@ -586,46 +668,37 @@ static int myeid_set_security_env_rsa(sc_card_t *card, const sc_security_env_t * goto err; } } - if (se_num <= 0) - return 0; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num); - r = sc_transmit_apdu(card, &apdu); - sc_unlock(card); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - return sc_check_sw(card, apdu.sw1, apdu.sw2); err: - if (locked) - sc_unlock(card); LOG_FUNC_RETURN(card->ctx, r); } -static int myeid_set_security_env_ec(sc_card_t *card, const sc_security_env_t *env, +static int myeid_set_security_env_ec(sc_card_t *card, const sc_security_env_t *env, int se_num) { sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; - int r, locked = 0; + int r; 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_ASYMMETRIC) { sc_log(card->ctx, "asymmetric keyref not supported.\n"); return SC_ERROR_NOT_SUPPORTED; } - if (se_num > 0) + if (se_num > 0) { sc_log(card->ctx, "restore security environment not supported.\n"); return SC_ERROR_NOT_SUPPORTED; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0); - switch (env->operation) + switch (env->operation) { case SC_SEC_OPERATION_DECIPHER: - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Decipher operation is not supported with EC keys.\n"); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Decipher operation is not supported with EC keys.\n"); return SC_ERROR_NOT_SUPPORTED; break; case SC_SEC_OPERATION_SIGN: @@ -637,20 +710,20 @@ static int myeid_set_security_env_ec(sc_card_t *card, const sc_security_env_t *e } apdu.le = 0; p = sbuf; - if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) + if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) { *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; *p++ = env->algorithm_ref & 0xFF; } - if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) + if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) { *p++ = 0x81; *p++ = 0x02; memcpy(p, env->file_ref.value, 2); p += 2; } - if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) + if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { *p++ = 0x84; *p++ = 1; @@ -661,45 +734,38 @@ static int myeid_set_security_env_ec(sc_card_t *card, const sc_security_env_t *e apdu.datalen = r; apdu.data = sbuf; apdu.resplen = 0; - if (se_num > 0) { - r = sc_lock(card); - LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); - locked = 1; - } - if (apdu.datalen != 0) + if (apdu.datalen != 0) { r = sc_transmit_apdu(card, &apdu); - if (r) + if (r) { sc_log(card->ctx, "%s: APDU transmit failed", sc_strerror(r)); goto err; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); - if (r) + if (r) { sc_log(card->ctx, "%s: Card returned error", sc_strerror(r)); goto err; } } - if (se_num <= 0) - return 0; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num); - r = sc_transmit_apdu(card, &apdu); - sc_unlock(card); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - return sc_check_sw(card, apdu.sw1, apdu.sw2); err: - if (locked) - sc_unlock(card); LOG_FUNC_RETURN(card->ctx, r); } static int myeid_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) { - LOG_FUNC_CALLED(card->ctx); + struct sc_context *ctx = card->ctx; + myeid_private_data_t* priv; + + LOG_FUNC_CALLED(ctx); + + priv = (myeid_private_data_t*) card->drv_data; + /* store security environment to differentiate between ECDH and RSA in decipher - Hannu*/ + priv->sec_env = env; if (env->flags & SC_SEC_ENV_ALG_PRESENT) { @@ -708,8 +774,8 @@ static int myeid_set_security_env(struct sc_card *card, tmp = *env; tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT; tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT; - - if (tmp.algorithm == SC_ALGORITHM_RSA) + + if (tmp.algorithm == SC_ALGORITHM_RSA) { tmp.algorithm_ref = 0x00; /* potential FIXME: return an error, if an unsupported @@ -719,43 +785,80 @@ static int myeid_set_security_env(struct sc_card *card, if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) tmp.algorithm_ref |= 0x10; - return myeid_set_security_env_rsa(card, &tmp, se_num); + return myeid_set_security_env_rsa(card, &tmp, se_num); } - else if (tmp.algorithm == SC_ALGORITHM_EC) - { + else if (tmp.algorithm == SC_ALGORITHM_EC) + { #ifdef MYEID_ECC_SUPPORT - /* TODO: Update the algorithm_ref */ - tmp.algorithm_ref = 0xAA; - tmp.algorithm_flags = 0; - return myeid_set_security_env_ec(card, &tmp, se_num); + tmp.algorithm_ref = 0x04; + tmp.algorithm_flags = 0; + return myeid_set_security_env_ec(card, &tmp, se_num); #else - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Elliptic curves are not supported in this version.\n"); + sc_log(ctx, "Elliptic curves are not supported in this version."); return SC_ERROR_NOT_SUPPORTED; #endif - } + } else { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported algorithm.\n"); + sc_log(ctx, "Unsupported algorithm."); return SC_ERROR_NOT_SUPPORTED; - } + } } return myeid_set_security_env_rsa(card, env, se_num); } -static int myeid_compute_signature(struct sc_card *card, const u8 * data, - size_t datalen, u8 * out, size_t outlen) + +static int +myeid_convert_ec_signature(struct sc_context *ctx, size_t s_len, unsigned char *data, size_t datalen) { + unsigned char *buf; + size_t buflen; int r; + + assert(data && datalen); + + if (*data != 0x30 || *(data + 1) != (datalen - 2) || *(data + 2) != 0x02) + return SC_ERROR_INVALID_DATA; + + buf = calloc(1, (s_len + 7)/8*2); + if (!buf) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + buflen = (s_len + 7)/8*2; + + r = sc_asn1_sig_value_sequence_to_rs(ctx, data, datalen, buf, buflen); + if (r < 0) + free(buf); + LOG_TEST_RET(ctx, r, "Failed to cenvert Sig-Value to the raw RS format"); + + if (buflen > datalen) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); + + memmove(data, buf, buflen); + return buflen; +} + + +static int +myeid_compute_signature(struct sc_card *card, const u8 * data, size_t datalen, + u8 * out, size_t outlen) +{ + struct sc_context *ctx = card->ctx; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; - - LOG_FUNC_CALLED(card->ctx); + struct myeid_private_data* priv; + int r; assert(card != NULL && data != NULL && out != NULL); + ctx = card->ctx; + LOG_FUNC_CALLED(ctx); + + priv = (myeid_private_data_t*) card->drv_data; + sc_log(ctx, "key type %i, key length %i", priv->sec_env->algorithm, priv->sec_env->algorithm_ref); + if (datalen > 256) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); /* INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x9E Resp: Digital Signature @@ -764,15 +867,13 @@ static int myeid_compute_signature(struct sc_card *card, const u8 * data, apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; - if (datalen == 256) - { + if (datalen == 256) { apdu.p2 = data[0]; memcpy(sbuf, data+1, datalen-1); apdu.lc = datalen - 1; apdu.datalen = datalen - 1; } - else - { + else { memcpy(sbuf, data, datalen); apdu.lc = datalen; apdu.datalen = datalen; @@ -780,40 +881,107 @@ static int myeid_compute_signature(struct sc_card *card, const u8 * data, apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + LOG_TEST_RET(ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(ctx, r, "compute_signature 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); + if (priv->sec_env->algorithm == SC_ALGORITHM_EC) { + r = myeid_convert_ec_signature(ctx, priv->sec_env->algorithm_ref, apdu.resp, apdu.resplen); + LOG_TEST_RET(ctx, r, "compute_signature convert signature failed"); + apdu.resplen = r; } - LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); + if (apdu.resplen > outlen) + LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL); + + memcpy(out, apdu.resp, apdu.resplen); + LOG_FUNC_RETURN(ctx, apdu.resplen); } + +/* takes other party's public key as input, performs ECDH key derivation and returns the shared secret in [out]. */ +int myeid_ecdh_derive(struct sc_card *card, const u8* pubkey, size_t pubkey_len, u8* out, size_t outlen) +{ + + /* MyEID uses GENERAL AUTHENTICATE ISO command for ECDH */ + + struct sc_apdu apdu; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + + int r; + + sc_format_apdu(card, &apdu, + SC_APDU_CASE_4_SHORT, + 0x86, 0x00, 0x00); + + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + + /* Fill in "Data objects in dynamic authentication template (tag 0x7C) structure */ + sbuf[0] = 0x7C; + sbuf[1] = pubkey_len + 4; + sbuf[2] = 0x85; + sbuf[3] = pubkey_len; + memcpy(&sbuf[4], pubkey, pubkey_len); + + apdu.lc = pubkey_len + 4; + apdu.datalen = apdu.lc; + apdu.data = sbuf; + + 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, "ECDH operation failed - GENERAL AUTHENTICATE returned error."); + + if (outlen < apdu.resplen) + { + r = SC_ERROR_BUFFER_TOO_SMALL; + LOG_TEST_RET(card->ctx, r, "Buffer too small to hold shared secret."); + } + + memcpy(out, rbuf, apdu.resplen); + + LOG_FUNC_RETURN(card->ctx, r); +} + + static int myeid_decipher(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) { - int r; - struct sc_apdu apdu; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + int r; + myeid_private_data_t* priv; + struct sc_apdu apdu; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; LOG_FUNC_CALLED(card->ctx); + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); - assert(card != NULL && crgram != NULL && out != NULL); - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); - if (crgram_len > 256) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + assert(card != NULL && crgram != NULL && out != NULL); - /* INS: 0x2A PERFORM SECURITY OPERATION - * P1: 0x80 Resp: Plain value - * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */ - sc_format_apdu(card, &apdu, - (crgram_len < 256) ? SC_APDU_CASE_4_SHORT : SC_APDU_CASE_3_SHORT, - 0x2A, 0x80, 0x86); + priv = (myeid_private_data_t*) card->drv_data; + + if (priv->sec_env && priv->sec_env->algorithm == SC_ALGORITHM_EC + && priv->sec_env->operation == SC_SEC_OPERATION_DERIVE + && priv->sec_env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW) + { + r = myeid_ecdh_derive(card, crgram, crgram_len, out, outlen); + priv->sec_env = NULL; /* clear after operation */ + LOG_FUNC_RETURN(card->ctx, r); + } + + if (crgram_len > 256) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + + /* INS: 0x2A PERFORM SECURITY OPERATION + * P1: 0x80 Resp: Plain value + * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */ + sc_format_apdu(card, &apdu, + (crgram_len < 256) ? SC_APDU_CASE_4_SHORT : SC_APDU_CASE_3_SHORT, + 0x2A, 0x80, 0x86); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); @@ -821,17 +989,17 @@ static int myeid_decipher(struct sc_card *card, const u8 * crgram, if (crgram_len == 256) { - apdu.le = 0; - /* padding indicator byte, 0x81 = first half of 2048 bit cryptogram */ - sbuf[0] = 0x81; - memcpy(sbuf + 1, crgram, crgram_len / 2); - apdu.lc = crgram_len / 2 + 1; + apdu.le = 0; + /* padding indicator byte, 0x81 = first half of 2048 bit cryptogram */ + sbuf[0] = 0x81; + memcpy(sbuf + 1, crgram, crgram_len / 2); + apdu.lc = crgram_len / 2 + 1; } else { - sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */ - memcpy(sbuf + 1, crgram, crgram_len); - apdu.lc = crgram_len + 1; + sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */ + memcpy(sbuf + 1, crgram, crgram_len); + apdu.lc = crgram_len + 1; } apdu.datalen = apdu.lc; @@ -841,43 +1009,44 @@ static int myeid_decipher(struct sc_card *card, const u8 * crgram, LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { - if (crgram_len == 256) - { - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, - 0x2A, 0x80, 0x86); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = crgram_len; - /* padding indicator byte, - * 0x82 = Second half of 2048 bit cryptogram */ - sbuf[0] = 0x82; - memcpy(sbuf + 1, crgram + crgram_len / 2, crgram_len / 2); - apdu.lc = crgram_len / 2 + 1; - apdu.datalen = apdu.lc; - apdu.data = sbuf; + if (crgram_len == 256) + { + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, + 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = crgram_len; + /* padding indicator byte, + * 0x82 = Second half of 2048 bit cryptogram */ + sbuf[0] = 0x82; + memcpy(sbuf + 1, crgram + crgram_len / 2, crgram_len / 2); + apdu.lc = crgram_len / 2 + 1; + apdu.datalen = apdu.lc; + apdu.data = sbuf; - r = sc_transmit_apdu(card, &apdu); + r = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + 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); - } - } - else - { - int len = apdu.resplen > outlen ? outlen : apdu.resplen; + 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); + } + } + else + { + 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)); + memcpy(out, apdu.resp, len); + LOG_FUNC_RETURN(card->ctx, len); + } + } + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); } + /* Write internal data, e.g. add default pin-records to pin */ static int myeid_putdata(struct sc_card *card, struct sc_cardctl_myeid_data_obj* data_obj) { @@ -1012,7 +1181,7 @@ static int myeid_loadkey(sc_card_t *card, int mode, u8* value, int value_len) apdu.data = sbuf; apdu.datalen = len; apdu.lc = len; - + r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); @@ -1045,22 +1214,22 @@ static int myeid_generate_store_key(struct sc_card *card, memcpy(sbuf + len, data->pubexp, data->pubexp_len); len += data->pubexp_len; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00); - apdu.data = sbuf; + apdu.data = sbuf; } else if(data->key_type == SC_CARDCTL_MYEID_KEY_EC) { - + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x46, 0x00, 0x00); - + apdu.data = NULL; apdu.resp = sbuf; apdu.resplen = 0x00; apdu.le = 0x00; } - + apdu.cla = 0x00; apdu.datalen = len; apdu.lc = len; - + r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); @@ -1088,9 +1257,9 @@ static int myeid_generate_store_key(struct sc_card *card, LOG_FUNC_RETURN(card->ctx, r); } else if(data->key_type == SC_CARDCTL_MYEID_KEY_EC) { - if((r = myeid_loadkey(card, LOAD_KEY_EC_PRIVATE, data->d, + if((r = myeid_loadkey(card, LOAD_KEY_EC_PRIVATE, data->d, data->d_len)) >= 0 && - (r = myeid_loadkey(card, LOAD_KEY_EC_PUBLIC, data->ecpublic_point, + (r = myeid_loadkey(card, LOAD_KEY_EC_PUBLIC, data->ecpublic_point, data->ecpublic_point_len)) >= 0) LOG_FUNC_RETURN(card->ctx, r); } @@ -1230,25 +1399,25 @@ static struct sc_card_driver * sc_get_driver(void) if (iso_ops == NULL) iso_ops = iso_drv->ops; - myeid_ops = *iso_drv->ops; - myeid_ops.match_card = myeid_match_card; - myeid_ops.init = myeid_init; - myeid_ops.finish = myeid_finish; + myeid_ops = *iso_drv->ops; + myeid_ops.match_card = myeid_match_card; + myeid_ops.init = myeid_init; + myeid_ops.finish = myeid_finish; /* no record oriented file services */ - myeid_ops.read_record = NULL; - myeid_ops.write_record = NULL; - myeid_ops.append_record = NULL; - myeid_ops.update_record = NULL; - myeid_ops.select_file = myeid_select_file; - myeid_ops.create_file = myeid_create_file; - myeid_ops.delete_file = myeid_delete_file; - myeid_ops.list_files = myeid_list_files; - myeid_ops.set_security_env = myeid_set_security_env; - myeid_ops.compute_signature = myeid_compute_signature; - myeid_ops.decipher = myeid_decipher; - myeid_ops.process_fci = myeid_process_fci; - myeid_ops.card_ctl = myeid_card_ctl; - myeid_ops.pin_cmd = myeid_pin_cmd; + myeid_ops.read_record = NULL; + myeid_ops.write_record = NULL; + myeid_ops.append_record = NULL; + myeid_ops.update_record = NULL; + myeid_ops.select_file = myeid_select_file; + myeid_ops.create_file = myeid_create_file; + myeid_ops.delete_file = myeid_delete_file; + myeid_ops.list_files = myeid_list_files; + myeid_ops.set_security_env = myeid_set_security_env; + myeid_ops.compute_signature = myeid_compute_signature; + myeid_ops.decipher = myeid_decipher; + myeid_ops.process_fci = myeid_process_fci; + myeid_ops.card_ctl = myeid_card_ctl; + myeid_ops.pin_cmd = myeid_pin_cmd; return &myeid_drv; } diff --git a/src/libopensc/card-oberthur.c b/src/libopensc/card-oberthur.c index 2a9dbe3f..b8a5cbc4 100644 --- a/src/libopensc/card-oberthur.c +++ b/src/libopensc/card-oberthur.c @@ -23,7 +23,9 @@ * best view with tabstop=4 */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_OPENSSL /* empty file without openssl */ #include @@ -397,7 +399,8 @@ auth_process_fci(struct sc_card *card, struct sc_file *file, case 0x38: file->type = SC_FILE_TYPE_DF; file->size = attr[0]; - sc_file_set_type_attr(file,attr,attr_len); + if (SC_SUCCESS != sc_file_set_type_attr(file,attr,attr_len)) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED); break; default: SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED); @@ -1108,16 +1111,17 @@ auth_compute_signature(struct sc_card *card, const unsigned char *in, size_t ile unsigned char resp[SC_MAX_APDU_BUFFER_SIZE]; int rv; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "inlen %i, outlen %i\n", ilen, olen); if (!card || !in || !out) { - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS); + return SC_ERROR_INVALID_ARGUMENTS; } else if (ilen > 96) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Illegal input length %d\n", ilen); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "Illegal input length"); } + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "inlen %i, outlen %i\n", ilen, olen); + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A); apdu.datalen = ilen; apdu.data = in; @@ -2012,7 +2016,7 @@ write_publickey (struct sc_card *card, unsigned int offset, sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "write_publickey in %d bytes :\n%s", count, debug_buf); - if (offset > sizeof(rsa_der)) + if (1+offset > sizeof(rsa_der)) SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "Invalid offset value"); len = offset+count > sizeof(rsa_der) ? sizeof(rsa_der) - offset : count; @@ -2111,7 +2115,7 @@ auth_read_binary(struct sc_card *card, unsigned int offset, if (auth_current_ef->magic==SC_FILE_MAGIC && auth_current_ef->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { int jj; - unsigned char resp[0x100], *out = NULL; + unsigned char resp[SC_MAX_APDU_BUFFER_SIZE], *out = NULL; size_t resp_len, out_len; struct sc_pkcs15_bignum bn[2]; struct sc_pkcs15_pubkey_rsa key; diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 4d39962f..610bd087 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -25,7 +25,9 @@ * http://www.g10code.de/docs/openpgp-card-2.0.pdf */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -359,8 +361,14 @@ pgp_init(sc_card_t *card) return r; } + /* defensive programming check */ + if (!file) { + pgp_finish(card); + return SC_ERROR_OBJECT_NOT_FOUND; + } + /* read information from AID */ - if (file && file->namelen == 16) { + if (file->namelen == 16) { /* OpenPGP card spec 1.1 & 2.0, section 4.2.1 & 4.1.2.1 */ priv->bcd_version = bebytes2ushort(file->name + 6); /* kludge: get card's serial number from manufacturer ID + serial number */ @@ -949,7 +957,7 @@ static unsigned int pgp_strip_path(sc_card_t *card, const sc_path_t *path) { unsigned int start_point = 0; /* start_point will move through the path string */ - if (path->value == NULL || path->len == 0) + if (path->len == 0) return 0; /* Ignore 3F00 (MF) at the beginning */ @@ -2074,7 +2082,10 @@ pgp_build_tlv(sc_context_t *ctx, unsigned int tag, u8 *data, size_t len, u8 **ou highest_order++; } highest_order--; - cla = tag >> 8*highest_order; + if (highest_order >= 4) + cla = 0x00; + else + cla = tag >> 8*highest_order; /* Restore class bits */ *out[0] |= cla; return SC_SUCCESS; @@ -2426,7 +2437,9 @@ static int pgp_erase_card(sc_card_t *card) /* ABI: card ctl: perform special card-specific operations */ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) { +#ifdef ENABLE_OPENSSL int r; +#endif /* ENABLE_OPENSSL */ LOG_FUNC_CALLED(card->ctx); diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index b1996541..c12c9bd4 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -22,7 +22,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -439,6 +441,7 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, unsigned int cla_out, tag_out; const u8 *body; size_t bodylen; + int find_len = 0; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); @@ -463,6 +466,11 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, recvbuf ? SC_APDU_CASE_4_SHORT: SC_APDU_CASE_3_SHORT, ins, p1, p2); apdu.flags |= SC_APDU_FLAGS_CHAINING; + /* if looking for length of object, dont try and read the rest of buffer here */ + if (rbuflen == 8 && card->reader->active_protocol == SC_PROTO_T1) { + apdu.flags |= SC_APDU_FLAGS_NO_GET_RESP; + find_len = 1; + } apdu.lc = sendbuflen; apdu.datalen = sendbuflen; @@ -491,7 +499,9 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, goto err; } - r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (!(find_len && apdu.sw1 == 0x61)) { + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + } /* TODO: - DEE look later at tag vs size read too */ if (r < 0) { @@ -784,8 +794,6 @@ static int piv_find_aid(sc_card_t * card, sc_file_t *aid_file) 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]); - if (aid_file->name == NULL) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NO_CARD_SUPPORT); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, i); } @@ -1558,8 +1566,10 @@ static int piv_general_mutual_authenticate(sc_card_t *card, } r = sc_lock(card); - if (r != SC_SUCCESS) - goto err; + if (r != SC_SUCCESS) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "sc_lock failed\n"); + goto err; /* cleanup */ + } locked = 1; p = sbuf; @@ -1828,8 +1838,10 @@ static int piv_general_external_authenticate(sc_card_t *card, } r = sc_lock(card); - if (r != SC_SUCCESS) - goto err; + if (r != SC_SUCCESS) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "sc_lock failed\n"); + goto err; /* cleanup */ + } locked = 1; p = sbuf; @@ -2143,7 +2155,9 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"challenge len=%d",len); - sc_lock(card); + r = sc_lock(card); + if (r != SC_SUCCESS) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); p = sbuf; *p++ = 0x7c; @@ -2179,9 +2193,9 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) rbuf = NULL; } - sc_unlock(card); + r = sc_unlock(card); - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 0); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } @@ -2875,11 +2889,11 @@ static int piv_init(sc_card_t *card) _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ - flags = SC_ALGORITHM_ECDSA_RAW; + 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, 256, flags, ext_flags); - _sc_card_add_ec_alg(card, 384, flags, ext_flags); + _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); + _sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL); card->caps |= SC_CARD_CAP_RNG; diff --git a/src/libopensc/card-rtecp.c b/src/libopensc/card-rtecp.c index d0634d04..8e3a4983 100644 --- a/src/libopensc/card-rtecp.c +++ b/src/libopensc/card-rtecp.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-rutoken.c b/src/libopensc/card-rutoken.c index efbf6b5b..295c23eb 100644 --- a/src/libopensc/card-rutoken.c +++ b/src/libopensc/card-rutoken.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/card-sc-hsm.c b/src/libopensc/card-sc-hsm.c index cb30ddcd..e4fab7bd 100644 --- a/src/libopensc/card-sc-hsm.c +++ b/src/libopensc/card-sc-hsm.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -234,7 +236,6 @@ static int sc_hsm_read_binary(sc_card_t *card, { sc_context_t *ctx = card->ctx; sc_apdu_t apdu; - u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 cmdbuff[4]; int r; @@ -248,14 +249,14 @@ static int sc_hsm_read_binary(sc_card_t *card, cmdbuff[2] = (idx >> 8) & 0xFF; cmdbuff[3] = idx & 0xFF; - assert(count <= (card->max_recv_size > 0 ? card->max_recv_size : 256)); - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xB1, 0x00, 0x00); + assert(count <= card->max_recv_size); + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0xB1, 0x00, 0x00); apdu.data = cmdbuff; apdu.datalen = 4; apdu.lc = 4; apdu.le = count; apdu.resplen = count; - apdu.resp = recvbuf; + apdu.resp = buf; r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, r, "APDU transmit failed"); @@ -265,8 +266,6 @@ static int sc_hsm_read_binary(sc_card_t *card, LOG_TEST_RET(ctx, r, "Check SW error"); } - memcpy(buf, recvbuf, apdu.resplen); - LOG_FUNC_RETURN(ctx, apdu.resplen); } @@ -1042,6 +1041,7 @@ static int sc_hsm_init(struct sc_card *card) _sc_card_add_rsa_alg(card, 2048, flags, 0); flags = SC_ALGORITHM_ECDSA_RAW| + SC_ALGORITHM_ECDH_CDH_RAW| SC_ALGORITHM_ECDSA_HASH_NONE| SC_ALGORITHM_ECDSA_HASH_SHA1| SC_ALGORITHM_ECDSA_HASH_SHA224| @@ -1053,14 +1053,15 @@ static int sc_hsm_init(struct sc_card *card) SC_ALGORITHM_EXT_EC_NAMEDCURVE| SC_ALGORITHM_EXT_EC_UNCOMPRESES| SC_ALGORITHM_ONBOARD_KEY_GEN; - _sc_card_add_ec_alg(card, 192, flags, ext_flags); - _sc_card_add_ec_alg(card, 224, flags, ext_flags); - _sc_card_add_ec_alg(card, 256, flags, ext_flags); - _sc_card_add_ec_alg(card, 320, flags, ext_flags); + _sc_card_add_ec_alg(card, 192, flags, ext_flags, NULL); + _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); card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT; card->max_send_size = 1431; // 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY + card->max_recv_size = 0; // Card supports sending with extended length APDU and without limit return 0; } diff --git a/src/libopensc/card-setcos.c b/src/libopensc/card-setcos.c index eb9e936b..2b0182a9 100644 --- a/src/libopensc/card-setcos.c +++ b/src/libopensc/card-setcos.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -438,7 +440,7 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file) const int* p_idx; int i; int len = 0; - u8 bBuf[32]; + u8 bBuf[64]; /* Get specific operation groups for specified file-type */ switch (file->type){ diff --git a/src/libopensc/card-starcos.c b/src/libopensc/card-starcos.c index 9d43e51d..cc87fadc 100644 --- a/src/libopensc/card-starcos.c +++ b/src/libopensc/card-starcos.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -32,6 +34,8 @@ static 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 }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -39,7 +43,7 @@ static struct sc_card_operations starcos_ops; static struct sc_card_operations *iso_ops = NULL; static struct sc_card_driver starcos_drv = { - "STARCOS SPK 2.3/2.4", + "STARCOS SPK 2.3/2.4/3.4", "starcos", &starcos_ops, NULL, 0, NULL @@ -70,6 +74,24 @@ typedef struct starcos_ex_data_st { unsigned int fix_digestInfo; } starcos_ex_data; +#define CHECK_NOT_SUPPORTED_V3_4(card) \ + do { \ + if ((card)->type == SC_CARD_TYPE_STARCOS_V3_4) { \ + sc_debug((card)->ctx, SC_LOG_DEBUG_NORMAL, \ + "not supported for STARCOS 3.4 cards"); \ + return SC_ERROR_NOT_SUPPORTED; \ + } \ + } 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) { @@ -103,15 +125,31 @@ static int starcos_init(sc_card_t *card) | SC_ALGORITHM_RSA_HASH_RIPEMD160 | SC_ALGORITHM_RSA_HASH_MD5_SHA1; - _sc_card_add_rsa_alg(card, 512, flags, 0x10001); - _sc_card_add_rsa_alg(card, 768, flags, 0x10001); - _sc_card_add_rsa_alg(card,1024, flags, 0x10001); - card->caps = SC_CARD_CAP_RNG; - /* we need read_binary&friends with max 128 bytes per read */ - card->max_send_size = 128; - card->max_recv_size = 128; + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + card->name = "STARCOS SPK 3.4"; + flags |= SC_CARD_FLAG_RNG + | SC_ALGORITHM_RSA_HASH_SHA224 + | SC_ALGORITHM_RSA_HASH_SHA256 + | SC_ALGORITHM_RSA_HASH_SHA384 + | SC_ALGORITHM_RSA_HASH_SHA512; + + _sc_card_add_rsa_alg(card, 512, flags, 0x10001); + _sc_card_add_rsa_alg(card, 768, flags, 0x10001); + _sc_card_add_rsa_alg(card,1024, flags, 0x10001); + _sc_card_add_rsa_alg(card,1728, flags, 0x10001); + _sc_card_add_rsa_alg(card,1976, flags, 0x10001); + _sc_card_add_rsa_alg(card,2048, flags, 0x10001); + } else { + _sc_card_add_rsa_alg(card, 512, flags, 0x10001); + _sc_card_add_rsa_alg(card, 768, flags, 0x10001); + _sc_card_add_rsa_alg(card,1024, flags, 0x10001); + + /* we need read_binary&friends with max 128 bytes per read */ + card->max_send_size = 128; + card->max_recv_size = 128; + } return 0; } @@ -215,6 +253,182 @@ static int process_fci(sc_context_t *ctx, sc_file_t *file, return SC_SUCCESS; } +static int process_fci_v3_4(sc_context_t *ctx, sc_file_t *file, + const u8 *buf, size_t buflen) +{ + size_t taglen, len = buflen; + const u8 *tag = NULL, *p; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "processing %d FCI bytes\n", buflen); + + if (buflen < 2) + return SC_ERROR_INTERNAL; + if (buf[0] != 0x6f) + return SC_ERROR_INVALID_DATA; + len = (size_t)buf[1]; + if (buflen - 2 < len) + return SC_ERROR_INVALID_DATA; + + /* defaults */ + file->type = SC_FILE_TYPE_WORKING_EF; + if (len == 0) { + SC_FUNC_RETURN(ctx, 2, SC_SUCCESS); + } + + p = buf + 2; + file->ef_structure = SC_FILE_TYPE_DF; + file->shareable = 1; + tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); + if (tag != NULL && taglen > 0 && taglen <= 16) { + memcpy(file->name, tag, taglen); + file->namelen = taglen; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "filename %s", + sc_dump_hex(file->name, file->namelen)); + } + return SC_SUCCESS; +} + +static int process_fcp_v3_4(sc_context_t *ctx, sc_file_t *file, + const u8 *buf, size_t buflen) +{ + size_t taglen, len = buflen; + const u8 *tag = NULL, *p; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "processing %d FCP bytes\n", buflen); + + if (buflen < 2) + return SC_ERROR_INTERNAL; + if (buf[0] != 0x62) + return SC_ERROR_INVALID_DATA; + len = (size_t)buf[1]; + if (buflen - 2 < len) + return SC_ERROR_INVALID_DATA; + p = buf + 2; + + 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, + " bytes in file: %d\n", bytes); + file->size = bytes; + } + + tag = sc_asn1_find_tag(ctx, p, len, 0xc5, &taglen); + if (tag != NULL && taglen >= 2) { + int bytes = (tag[0] << 8) + tag[1]; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + " bytes in file 2: %d\n", bytes); + file->size = bytes; + } + + tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); + if (tag != NULL) { + const char *type = "unknown"; + const char *structure = "unknown"; + + if (taglen >= 1) { + unsigned char byte = tag[0]; + if (byte & 0x40) { + file->shareable = 1; + } + if (byte == 0x38) { + type = "DF"; + file->type = SC_FILE_TYPE_DF; + file->shareable = 1; + } + switch (byte & 7) { + case 1: + /* transparent EF */ + type = "working EF"; + structure = "transparent"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_TRANSPARENT; + break; + case 2: + /* linear fixed EF */ + type = "working EF"; + structure = "linear fixed"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_LINEAR_FIXED; + break; + case 4: + /* linear variable EF */ + type = "working EF"; + structure = "linear variable"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE; + break; + case 6: + /* cyclic EF */ + type = "working EF"; + structure = "cyclic"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_CYCLIC; + break; + default: + /* use defaults from above */ + break; + } + } + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + " type: %s\n", type); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + " EF structure: %s\n", structure); + if (taglen >= 2) { + if (tag[1] != 0x41 || taglen != 5) { + SC_FUNC_RETURN(ctx, 2,SC_ERROR_INVALID_DATA); + } + /* formatted EF */ + file->record_length = (tag[2] << 8) + tag[3]; + file->record_count = tag[4]; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + " rec_len: %d rec_cnt: %d\n\n", + file->record_length, file->record_count); + } + } + + 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, " file identifier: 0x%02X%02X\n", + tag[0], tag[1]); + } + + tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); + if (tag != NULL && taglen > 0 && taglen <= 16) { + memcpy(file->name, tag, taglen); + file->namelen = taglen; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " filename %s", + sc_dump_hex(file->name, file->namelen)); + } + + tag = sc_asn1_find_tag(ctx, p, len, 0x8a, &taglen); + if (tag != NULL && taglen == 1) { + char* status = "unknown"; + switch (tag[0]) { + case 1: + status = "creation"; + file->status = SC_FILE_STATUS_CREATION; + break; + case 5: + status = "operational active"; + file->status = SC_FILE_STATUS_ACTIVATED; + break; + case 12: + case 13: + status = "creation"; + file->status = SC_FILE_STATUS_INVALIDATED; + break; + default: + break; + } + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, " file status: %s\n", status); + } + + file->magic = SC_FILE_MAGIC; + return SC_SUCCESS; +} + static int starcos_select_aid(sc_card_t *card, u8 aid[16], size_t len, sc_file_t **file_out) @@ -262,12 +476,14 @@ static int starcos_select_aid(sc_card_t *card, static int starcos_select_fid(sc_card_t *card, unsigned int id_hi, unsigned int id_lo, - sc_file_t **file_out) + sc_file_t **file_out, int is_file) { sc_apdu_t apdu; u8 data[] = {id_hi & 0xff, id_lo & 0xff}; u8 resp[SC_MAX_APDU_BUFFER_SIZE]; int bIsDF = 0, r; + int isFCP = 0; + int isMF = 0; /* request FCI to distinguish between EFs and DFs */ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00); @@ -279,6 +495,22 @@ static int starcos_select_fid(sc_card_t *card, apdu.data = (u8*)data; apdu.datalen = 2; + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + if (id_hi == 0x3f && id_lo == 0x0) { + apdu.p1 = 0x0; + apdu.p2 = 0x0; + isMF = 1; + } else if (file_out || is_file) { + // last component (i.e. file or path) + apdu.p1 = 0x2; + apdu.p2 = 0x4; + } else { + // path component + apdu.p1 = 0x1; + apdu.p2 = 0x0; + } + } + r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); @@ -291,7 +523,17 @@ static int starcos_select_fid(sc_card_t *card, 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 (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) { + } else if (card->type == SC_CARD_TYPE_STARCOS_V3_4 && apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) { + /* not a file, could be a path */ + bIsDF = 1; + apdu.p1 = 0x1; + apdu.p2 = 0x0; + apdu.resplen = sizeof(resp); + apdu.le = 256; + apdu.lc = 2; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU re-transmit failed"); + } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && !isMF)) { /* SELECT returned some data (possible FCI) => * try a READ BINARY to see if a EF is selected */ sc_apdu_t apdu2; @@ -303,16 +545,19 @@ static int starcos_select_fid(sc_card_t *card, apdu2.lc = 0; r = sc_transmit_apdu(card, &apdu2); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86) + if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86) { /* no current EF is selected => we have a DF */ bIsDF = 1; + } else { + isFCP = 1; + } } if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); /* update cache */ - if (bIsDF) { + if (bIsDF || isMF) { card->cache.current_path.type = SC_PATH_TYPE_PATH; card->cache.current_path.value[0] = 0x3f; card->cache.current_path.value[1] = 0x00; @@ -342,8 +587,18 @@ static int starcos_select_fid(sc_card_t *card, *file_out = file; } else { /* ok, assume we have a EF */ - r = process_fci(card->ctx, file, apdu.resp, - apdu.resplen); + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + if (isFCP) { + r = process_fcp_v3_4(card->ctx, file, apdu.resp, + apdu.resplen); + } else { + r = process_fci_v3_4(card->ctx, file, apdu.resp, + apdu.resplen); + } + } else { + r = process_fci(card->ctx, file, apdu.resp, + apdu.resplen); + } if (r != SC_SUCCESS) { sc_file_free(file); return r; @@ -385,7 +640,7 @@ static int starcos_select_file(sc_card_t *card, /* Select with 2byte File-ID */ if (pathlen != 2) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); - return starcos_select_fid(card, path[0], path[1], file_out); + return starcos_select_fid(card, path[0], path[1], file_out, 1); } else if (in_path->type == SC_PATH_TYPE_DF_NAME) { /* SELECT DF with AID */ @@ -418,15 +673,18 @@ static int starcos_select_file(sc_card_t *card, if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 )) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); - /* unify path (the first FID should be MF) */ - if (path[0] != 0x3f || path[1] != 0x00) - { - n_pathbuf[0] = 0x3f; - n_pathbuf[1] = 0x00; - for (i=0; i< pathlen; i++) - n_pathbuf[i+2] = pathbuf[i]; - path = n_pathbuf; - pathlen += 2; + if (card->type != SC_CARD_TYPE_STARCOS_V3_4 || + (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) + { + n_pathbuf[0] = 0x3f; + n_pathbuf[1] = 0x00; + for (i=0; i< pathlen; i++) + n_pathbuf[i+2] = pathbuf[i]; + path = n_pathbuf; + pathlen += 2; + } } /* check current working directory */ @@ -440,20 +698,28 @@ static int starcos_select_file(sc_card_t *card, if (card->cache.current_path.value[i] == path[i] && 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) { + /* we're in the wrong folder, start traversing from root */ + bMatch = 0; + card->cache.current_path.len = 0; + } } if ( card->cache.valid && bMatch >= 0 ) { if ( pathlen - bMatch == 2 ) /* we are in the rigth directory */ - return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out); + return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out, 1); else if ( pathlen - bMatch > 2 ) { /* two more steps to go */ sc_path_t new_path; /* first step: change directory */ - r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL); + r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL, 0); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); memset(&new_path, 0, sizeof(sc_path_t)); @@ -493,10 +759,10 @@ static int starcos_select_file(sc_card_t *card, /* no usable cache */ for ( i=0; ictx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); } - return starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out); + return starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out, 1); } } else @@ -681,6 +947,8 @@ static int starcos_create_mf(sc_card_t *card, sc_starcos_create_data *data) sc_apdu_t apdu; sc_context_t *ctx = card->ctx; + CHECK_NOT_SUPPORTED_V3_4(card); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "creating MF \n"); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); apdu.cla |= 0x80; @@ -710,6 +978,8 @@ static int starcos_create_df(sc_card_t *card, sc_starcos_create_data *data) sc_apdu_t apdu; sc_context_t *ctx = card->ctx; + CHECK_NOT_SUPPORTED_V3_4(card); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "creating DF\n"); /* first step: REGISTER DF */ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "calling REGISTER DF\n"); @@ -753,6 +1023,8 @@ static int starcos_create_ef(sc_card_t *card, sc_starcos_create_data *data) sc_apdu_t apdu; sc_context_t *ctx = card->ctx; + CHECK_NOT_SUPPORTED_V3_4(card); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "creating EF\n"); sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT,0xE0,0x03,0x00); @@ -784,6 +1056,8 @@ static int starcos_create_end(sc_card_t *card, sc_file_t *file) if (file->type != SC_FILE_TYPE_DF) return SC_ERROR_INVALID_ARGUMENTS; + CHECK_NOT_SUPPORTED_V3_4(card); + fid[0] = (file->id >> 8) & 0xff; fid[1] = file->id & 0xff; sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT, 0xE0, 0x02, 0x00); @@ -809,6 +1083,8 @@ static int starcos_create_file(sc_card_t *card, sc_file_t *file) int r; sc_starcos_create_data data; + CHECK_NOT_SUPPORTED_V3_4(card); + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (file->type == SC_FILE_TYPE_DF) { @@ -886,6 +1162,8 @@ static int starcos_write_key(sc_card_t *card, sc_starcos_wkey_data *data) size_t len = sizeof(sbuf), tlen, offset = 0; sc_apdu_t apdu; + CHECK_NOT_SUPPORTED_V3_4(card); + if (data->mode == 0) { /* mode == 0 => install */ /* install key header */ sbuf[0] = 0xc1; /* key header tag */ @@ -955,6 +1233,9 @@ static int starcos_gen_key(sc_card_t *card, sc_starcos_gen_key_data *data) sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 sbuf[2], *p, *q; + + CHECK_NOT_SUPPORTED_V3_4(card); + /* generate key */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, data->key_id); @@ -1021,6 +1302,51 @@ static int starcos_set_security_env(sc_card_t *card, 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 (!(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; + + /* algorithm / cipher selector? */ + *p++ = 0x89; + *p++ = 0x02; + *p++ = 0x13; + *p++ = 0x23; + + apdu.data = sbuf; + apdu.datalen = p - sbuf; + apdu.lc = p - sbuf; + apdu.le = 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) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); + + if (env->algorithm_flags == SC_ALGORITHM_RSA_PAD_PKCS1) { + // input data will be already padded + ex_data->fix_digestInfo = 0; + } else { + ex_data->fix_digestInfo = env->algorithm_flags; + } + ex_data->sec_ops = SC_SEC_OPERATION_SIGN; + return SC_SUCCESS; + } + /* copy key reference, if present */ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) @@ -1148,33 +1474,65 @@ static int starcos_compute_signature(sc_card_t *card, if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) { /* compute signature with the COMPUTE SIGNATURE command */ - /* set the hash value */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, - 0x90, 0x81); - 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(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) - SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, - sc_check_sw(card, apdu.sw1, apdu.sw2)); + if (card->type == SC_CARD_TYPE_STARCOS_V3_4) { + size_t tmp_len; - /* call COMPUTE SIGNATURE */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A, - 0x9E, 0x9A); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = 256; + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, + 0x9E, 0x9A); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 0; + if (ex_data->fix_digestInfo) { + // need to pad data + unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES; + if (flags == 0x00) { + flags = SC_ALGORITHM_RSA_HASH_NONE; + } + tmp_len = sizeof(sbuf); + r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_pkcs1_encode failed"); + } else { + memcpy(sbuf, data, datalen); + tmp_len = datalen; + } - 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"); + apdu.data = sbuf; + apdu.datalen = tmp_len; + apdu.lc = tmp_len; + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.le = 0; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); + } else { + /* set the hash value */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, + 0x90, 0x81); + 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(card, &apdu); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, + sc_check_sw(card, apdu.sw1, apdu.sw2)); + + /* call COMPUTE SIGNATURE */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A, + 0x9E, 0x9A); + 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) { size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); @@ -1182,6 +1540,7 @@ static int starcos_compute_signature(sc_card_t *card, } } else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) { size_t tmp_len; + CHECK_NOT_SUPPORTED_V3_4(card); /* call INTERNAL AUTHENTICATE */ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x10, 0x00); /* fix/create DigestInfo structure (if necessary) */ @@ -1265,6 +1624,7 @@ static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) 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; @@ -1341,6 +1701,20 @@ static int starcos_logout(sc_card_t *card) return sc_check_sw(card, apdu.sw1, apdu.sw2); } +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); + + 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); +} + static struct sc_card_driver * sc_get_driver(void) { struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); @@ -1359,6 +1733,7 @@ static struct sc_card_driver * sc_get_driver(void) starcos_ops.compute_signature = starcos_compute_signature; starcos_ops.card_ctl = starcos_card_ctl; starcos_ops.logout = starcos_logout; + starcos_ops.pin_cmd = starcos_pin_cmd; return &starcos_drv; } diff --git a/src/libopensc/card-tcos.c b/src/libopensc/card-tcos.c index d6362a38..f7d07f22 100644 --- a/src/libopensc/card-tcos.c +++ b/src/libopensc/card-tcos.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -161,8 +163,6 @@ static int tcos_construct_fci(const sc_file_t *file, /* Directory name */ if (file->type == SC_FILE_TYPE_DF) { if (file->namelen) { - if (file->namelen > 16 || !file->name) - return SC_ERROR_INVALID_ARGUMENTS; sc_asn1_put_tag(0x84, file->name, file->namelen, p, 16, &p); } diff --git a/src/libopensc/card-westcos.c b/src/libopensc/card-westcos.c index 1642eb7d..76788bcf 100644 --- a/src/libopensc/card-westcos.c +++ b/src/libopensc/card-westcos.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -1109,6 +1111,15 @@ static int westcos_sign_decipher(int mode, sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "westcos_sign_decipher outlen=%d\n", outlen); + +#ifndef ENABLE_OPENSSL + r = SC_ERROR_NOT_SUPPORTED; +#else + if (keyfile == NULL || mem == NULL || card->drv_data == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + priv_data = (priv_data_t *) card->drv_data; if(priv_data->flags & RSA_CRYPTO_COMPONENT) @@ -1134,14 +1145,6 @@ static int westcos_sign_decipher(int mode, sc_card_t *card, r = apdu.resplen; goto out2; } - -#ifndef ENABLE_OPENSSL - r = SC_ERROR_NOT_SUPPORTED; -#else - if (keyfile == NULL || mem == NULL || priv_data == NULL) { - r = SC_ERROR_OUT_OF_MEMORY; - goto out; - } if ((priv_data->env.flags) & SC_ALGORITHM_RSA_PAD_PKCS1) pad = RSA_PKCS1_PADDING; diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 9a331728..50da8ff8 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -29,6 +31,7 @@ #include "internal.h" #include "asn1.h" +#include "common/compat_strlcpy.h" /* #define INVALIDATE_CARD_CACHE_IN_UNLOCK @@ -94,15 +97,35 @@ static void sc_card_free(sc_card_t *card) { sc_free_apps(card); sc_free_ef_atr(card); + if (card->ef_dir != NULL) sc_file_free(card->ef_dir); + free(card->ops); - if (card->algorithms != NULL) + + if (card->algorithms != NULL) { + int i; + for (i=0; ialgorithm_count; i++) { + struct sc_algorithm_info *info = (card->algorithms + i); + if (info->algorithm == SC_ALGORITHM_EC) { + struct sc_ec_parameters ep = info->u._ec.params; + + free(ep.named_curve); + free(ep.der.value); + } + } free(card->algorithms); + + card->algorithms = NULL; + card->algorithm_count = 0; + } + if (card->cache.current_ef) sc_file_free(card->cache.current_ef); + if (card->cache.current_df) sc_file_free(card->cache.current_df); + if (card->mutex != NULL) { int r = sc_mutex_destroy(card->ctx, card->mutex); if (r != SC_SUCCESS) @@ -169,10 +192,14 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) } if (driver != NULL) { - /* Forced driver, or matched via ATR mapping from - * config file */ + /* Forced driver, or matched via ATR mapping from config file */ card->driver = driver; + memcpy(card->ops, card->driver->ops, sizeof(struct sc_card_operations)); + if (card->ops->match_card != NULL) + if (card->ops->match_card(card) != 1) + sc_log(ctx, "driver '%s' match_card() failed: %s (will continue anyway)", card->driver->name, sc_strerror(r)); + if (card->ops->init != NULL) { r = card->ops->init(card); if (r) { @@ -191,7 +218,8 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) if (ops == NULL || ops->match_card == NULL) { continue; } - else if (!ctx->enable_default_driver && !strcmp("default", drv->short_name)) { + else if (!(ctx->flags & SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER) + && !strcmp("default", drv->short_name)) { sc_log(ctx , "ignore 'default' card driver"); continue; } @@ -222,18 +250,27 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) } if (card->name == NULL) card->name = card->driver->name; - *card_out = card; - /* Override card limitations with reader limitations. - * Note that zero means no limitations at all. - */ - if ((card->max_recv_size == 0) || - ((reader->driver->max_recv_size != 0) && (reader->driver->max_recv_size < card->max_recv_size))) - card->max_recv_size = reader->driver->max_recv_size; + /* initialize max_send_size/max_recv_size to a meaningfull value */ + if (card->caps & SC_CARD_CAP_APDU_EXT) { + if (!card->max_send_size) + card->max_send_size = 65535; + if (!card->max_recv_size) + card->max_recv_size = 65536; + } else { + if (!card->max_send_size) + card->max_send_size = 255; + if (!card->max_recv_size) + card->max_recv_size = 256; + } - if ((card->max_send_size == 0) || - ((reader->driver->max_send_size != 0) && (reader->driver->max_send_size < card->max_send_size))) - card->max_send_size = reader->driver->max_send_size; + /* Override card limitations with reader limitations. */ + if (reader->max_recv_size != 0 + && (reader->max_recv_size < card->max_recv_size)) + card->max_recv_size = reader->max_recv_size; + if (reader->max_send_size != 0 + && (reader->max_send_size < card->max_send_size)) + card->max_send_size = reader->max_send_size; sc_log(ctx, "card info name:'%s', type:%i, flags:0x%X, max_send/recv_size:%i/%i", card->name, card->type, card->flags, card->max_send_size, card->max_recv_size); @@ -246,6 +283,7 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) goto err; } #endif + *card_out = card; LOG_FUNC_RETURN(ctx, SC_SUCCESS); err: @@ -334,6 +372,10 @@ int sc_lock(sc_card_t *card) /* invalidate cache */ memset(&card->cache, 0, sizeof(card->cache)); card->cache.valid = 0; +#ifdef ENABLE_SM + if (card->sm_ctx.ops.open) + card->sm_ctx.ops.open(card); +#endif r = card->reader->ops->lock(card->reader); } } @@ -403,10 +445,11 @@ int sc_create_file(sc_card_t *card, sc_file_t *file) { int r; char pbuf[SC_MAX_PATH_STRING_SIZE]; - const sc_path_t *in_path = &file->path; + const sc_path_t *in_path; - assert(card != NULL); + assert(card != NULL && file != NULL); + in_path = &file->path; r = sc_path_print(pbuf, sizeof(pbuf), in_path); if (r != SC_SUCCESS) pbuf[0] = '\0'; @@ -446,7 +489,7 @@ int sc_delete_file(sc_card_t *card, const sc_path_t *path) int sc_read_binary(sc_card_t *card, unsigned int idx, unsigned char *buf, size_t count, unsigned long flags) { - size_t max_le = card->max_recv_size > 0 ? card->max_recv_size : 256; + size_t max_le = card->max_recv_size; int r; assert(card != NULL && card->ops != NULL && buf != NULL); @@ -496,7 +539,7 @@ int sc_read_binary(sc_card_t *card, unsigned int idx, int sc_write_binary(sc_card_t *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { - size_t max_lc = card->max_send_size > 0 ? card->max_send_size : 255; + size_t max_lc = card->max_send_size; int r; assert(card != NULL && card->ops != NULL && buf != NULL); @@ -539,7 +582,7 @@ int sc_write_binary(sc_card_t *card, unsigned int idx, int sc_update_binary(sc_card_t *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { - size_t max_lc = card->max_send_size > 0 ? card->max_send_size : 255; + size_t max_lc = card->max_send_size; int r; assert(card != NULL && card->ops != NULL && buf != NULL); @@ -800,21 +843,27 @@ int _sc_card_add_algorithm(sc_card_t *card, const sc_algorithm_info_t *info) } int _sc_card_add_ec_alg(sc_card_t *card, unsigned int key_length, - unsigned long flags, unsigned long ext_flags) + unsigned long flags, unsigned long ext_flags, + struct sc_object_id *curve_oid) { sc_algorithm_info_t info; memset(&info, 0, sizeof(info)); + sc_init_oid(&info.u._ec.params.id); + info.algorithm = SC_ALGORITHM_EC; info.key_length = key_length; info.flags = flags; + info.u._ec.ext_flags = ext_flags; + if (curve_oid) + info.u._ec.params.id = *curve_oid; return _sc_card_add_algorithm(card, &info); } static sc_algorithm_info_t * sc_card_find_alg(sc_card_t *card, - unsigned int algorithm, unsigned int key_length) + unsigned int algorithm, unsigned int key_length, void *param) { int i; @@ -825,15 +874,20 @@ static sc_algorithm_info_t * sc_card_find_alg(sc_card_t *card, continue; if (info->key_length != key_length) continue; + if (param) { + if (info->algorithm == SC_ALGORITHM_EC) + if(!sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id)) + continue; + } return info; } return NULL; } sc_algorithm_info_t * sc_card_find_ec_alg(sc_card_t *card, - unsigned int key_length) + unsigned int key_length, struct sc_object_id *curve_name) { - return sc_card_find_alg(card, SC_ALGORITHM_EC, key_length); + return sc_card_find_alg(card, SC_ALGORITHM_EC, key_length, curve_name); } int _sc_card_add_rsa_alg(sc_card_t *card, unsigned int key_length, @@ -853,25 +907,27 @@ int _sc_card_add_rsa_alg(sc_card_t *card, unsigned int key_length, sc_algorithm_info_t * sc_card_find_rsa_alg(sc_card_t *card, unsigned int key_length) { - return sc_card_find_alg(card, SC_ALGORITHM_RSA, key_length); + return sc_card_find_alg(card, SC_ALGORITHM_RSA, key_length, NULL); } sc_algorithm_info_t * sc_card_find_gostr3410_alg(sc_card_t *card, unsigned int key_length) { - return sc_card_find_alg(card, SC_ALGORITHM_GOSTR3410, key_length); + 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) { - u8 *card_atr_bin = atr->value; - size_t card_atr_bin_len = atr->len; + u8 *card_atr_bin; + size_t card_atr_bin_len; char card_atr_hex[3 * SC_MAX_ATR_SIZE]; size_t card_atr_hex_len; unsigned int i = 0; if (ctx == NULL || table == NULL || atr == NULL) return -1; + card_atr_bin = atr->value; + card_atr_bin_len = atr->len; sc_bin_to_hex(card_atr_bin, card_atr_bin_len, card_atr_hex, sizeof(card_atr_hex), ':'); card_atr_hex_len = strlen(card_atr_hex); @@ -1075,6 +1131,31 @@ void sc_print_cache(struct sc_card *card) { sc_print_path(&card->cache.current_df->path)); } +int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src) +{ + if (!dst || !src) + return SC_ERROR_INVALID_ARGUMENTS; + + memset(dst, 0, sizeof(*dst)); + if (src->named_curve) { + dst->named_curve = strdup(src->named_curve); + if (!dst->named_curve) + return SC_ERROR_OUT_OF_MEMORY; + } + dst->id = src->id; + if (src->der.value && src->der.len) { + dst->der.value = malloc(src->der.len); + if (!dst->der.value) + return SC_ERROR_OUT_OF_MEMORY; + memcpy(dst->der.value, src->der.value, src->der.len); + dst->der.len = src->der.len; + } + src->type = dst->type; + src->field_length = dst->field_length; + + return SC_SUCCESS; +} + scconf_block * sc_match_atr_block(sc_context_t *ctx, struct sc_card_driver *driver, struct sc_atr *atr) { @@ -1119,20 +1200,20 @@ sc_card_sm_load(struct sc_card *card, const char *module_path, const char *in_mo #ifdef _WIN32 if (!module_path) { - rc = RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); + rc = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); if( rc == ERROR_SUCCESS ) { temp_len = PATH_MAX; - rc = RegQueryValueEx( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); + rc = RegQueryValueExA( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); if( (rc == ERROR_SUCCESS) && (temp_len < PATH_MAX) ) module_path = temp_path; RegCloseKey( hKey ); } } if (!module_path) { - rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); + rc = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); if( rc == ERROR_SUCCESS ) { temp_len = PATH_MAX; - rc = RegQueryValueEx( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); + rc = RegQueryValueExA( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); if(rc == ERROR_SUCCESS && temp_len < PATH_MAX) module_path = temp_path; RegCloseKey( hKey ); @@ -1255,8 +1336,8 @@ sc_card_sm_check(struct sc_card *card) rv = sc_card_sm_load(card, module_path, module_name); LOG_TEST_RET(ctx, rv, "Failed to load SM module"); - strncpy(card->sm_ctx.module.filename, module_name, sizeof(card->sm_ctx.module.filename)); - strncpy(card->sm_ctx.config_section, sm, sizeof(card->sm_ctx.config_section)); + strlcpy(card->sm_ctx.module.filename, module_name, sizeof(card->sm_ctx.module.filename)); + strlcpy(card->sm_ctx.config_section, sm, sizeof(card->sm_ctx.config_section)); /* allocate resources for the external SM module */ sc_log(ctx, "'module_init' handler %p", card->sm_ctx.module.ops.module_init); diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index b46185ab..cad32219 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -255,7 +255,14 @@ enum { */ SC_CARDCTL_DNIE_BASE = _CTL_PREFIX('D', 'N', 'I'), SC_CARDCTL_DNIE_GENERATE_KEY, - SC_CARDCTL_DNIE_GET_INFO + SC_CARDCTL_DNIE_GET_INFO, + + /* + * isoApplet Java Card Applet + */ + SC_CARDCTL_ISOAPPLET_BASE = _CTL_PREFIX('I','S','O'), + SC_CARDCTL_ISOAPPLET_GENERATE_KEY, + SC_CARDCTL_ISOAPPLET_IMPORT_KEY }; enum { @@ -832,10 +839,7 @@ typedef struct sc_rtecp_genkey_data { */ enum SC_CARDCTL_MYEID_KEY_TYPE { SC_CARDCTL_MYEID_KEY_RSA = 0x11, - SC_CARDCTL_MYEID_KEY_EC = 0x21, - /* SC_CARDCTL_MYEID_KEY_AES = 0x?, // for future use - SC_CARDCTL_MYEID_KEY_DES = 0x?, - SC_CARDCTL_MYEID_KEY_3DES = 0x?, */ + SC_CARDCTL_MYEID_KEY_EC = 0x22 }; struct sc_cardctl_myeid_data_obj { @@ -939,7 +943,7 @@ typedef struct sc_cardctl_sc_hsm_init_param { size_t user_pin_len; /* Length of user PIN */ u8 user_pin_retry_counter; /* Retry counter default value */ u8 options[2]; /* Initialization options */ - char dkek_shares; /* Number of DKEK shares, 0 for card generated, -1 for none */ + signed char dkek_shares; /* Number of DKEK shares, 0 for card generated, -1 for none */ char *label; /* Token label to be set in EF.TokenInfo (2F03) */ } sc_cardctl_sc_hsm_init_param_t; @@ -957,6 +961,59 @@ typedef struct sc_cardctl_sc_hsm_wrapped_key { size_t wrapped_key_length; /* Length of key blob */ } sc_cardctl_sc_hsm_wrapped_key_t; +/* + * isoApplet + */ + +#define SC_ISOAPPLET_ALG_REF_RSA_GEN_2048 0xF3 +#define SC_ISOAPPLET_ALG_REF_EC_GEN 0xEC + +typedef struct sc_cardctl_isoApplet_ec_parameters { + struct sc_lv_data prime; + struct sc_lv_data coefficientA; + struct sc_lv_data coefficientB; + struct sc_lv_data basePointG; + struct sc_lv_data order; + struct sc_lv_data coFactor; +} sc_cardctl_isoApplet_ec_parameters_t; + +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 */ + union { + struct + { + struct sc_lv_data modulus; + struct sc_lv_data exponent; + } rsa; + struct + { + sc_cardctl_isoApplet_ec_parameters_t params; + struct sc_lv_data ecPointQ; + } ec; + } pubkey; +} sc_cardctl_isoApplet_genkey_t; + +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 */ + union { + struct + { + struct sc_lv_data p; + struct sc_lv_data q; + struct sc_lv_data iqmp; + struct sc_lv_data dmp1; + struct sc_lv_data dmq1; + } rsa; + struct + { + sc_cardctl_isoApplet_ec_parameters_t params; + struct sc_lv_data privateD; + } ec; + } privkey; +} sc_cardctl_isoApplet_import_key_t; + #ifdef __cplusplus } #endif diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index a3f3634a..5c756af6 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -94,6 +94,7 @@ enum { /* starcos driver */ SC_CARD_TYPE_STARCOS_BASE = 7000, SC_CARD_TYPE_STARCOS_GENERIC, + SC_CARD_TYPE_STARCOS_V3_4, /* tcos driver */ SC_CARD_TYPE_TCOS_BASE = 8000, @@ -140,6 +141,7 @@ enum { SC_CARD_TYPE_MUSCLE_V2, SC_CARD_TYPE_MUSCLE_ETOKEN_72K, SC_CARD_TYPE_MUSCLE_JCOP241, + SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU, /* ACOS5 driver */ SC_CARD_TYPE_ACOS5_BASE = 16000, @@ -191,6 +193,7 @@ enum { SC_CARD_TYPE_IASECC_OBERTHUR, SC_CARD_TYPE_IASECC_SAGEM, SC_CARD_TYPE_IASECC_AMOS, + SC_CARD_TYPE_IASECC_MI, /* SmartCard-HSM */ SC_CARD_TYPE_SC_HSM = 26000, @@ -200,7 +203,15 @@ enum { SC_CARD_TYPE_DNIE_BLANK, /* ATR LC byte: 00 */ SC_CARD_TYPE_DNIE_ADMIN, /* ATR LC byte: 01 */ SC_CARD_TYPE_DNIE_USER, /* ATR LC byte: 03 */ - SC_CARD_TYPE_DNIE_TERMINATED /* ATR LC byte: 0F */ + SC_CARD_TYPE_DNIE_TERMINATED, /* ATR LC byte: 0F */ + + /* JavaCards with isoApplet */ + SC_CARD_TYPE_ISO_APPLET_BASE = 28000, + SC_CARD_TYPE_ISO_APPLET_GENERIC, + + /* Masktech cards */ + SC_CARD_TYPE_MASKTECH_BASE = 29000, + SC_CARD_TYPE_MASKTECH_GENERIC }; extern sc_card_driver_t *sc_get_default_driver(void); @@ -237,6 +248,8 @@ extern sc_card_driver_t *sc_get_authentic_driver(void); extern sc_card_driver_t *sc_get_iasecc_driver(void); extern sc_card_driver_t *sc_get_epass2003_driver(void); extern sc_card_driver_t *sc_get_dnie_driver(void); +extern sc_card_driver_t *sc_get_isoApplet_driver(void); +extern sc_card_driver_t *sc_get_masktech_driver(void); #ifdef __cplusplus } diff --git a/src/libopensc/compression.c b/src/libopensc/compression.c index d26ef1ff..9b38d822 100644 --- a/src/libopensc/compression.c +++ b/src/libopensc/compression.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_ZLIB /* empty file without zlib */ #include diff --git a/src/libopensc/ctbcs.c b/src/libopensc/ctbcs.c index 3dc773df..4b08ad6c 100644 --- a/src/libopensc/ctbcs.c +++ b/src/libopensc/ctbcs.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -45,7 +47,7 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d { const char *prompt; size_t buflen, count = 0, j = 0, len; - static u8 buf[254]; + static u8 buf[256]; u8 control; ctbcs_init_apdu(apdu, @@ -58,7 +60,7 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d prompt = data->pin1.prompt; if (prompt && *prompt) { len = strlen(prompt); - if (count + len + 2 > buflen || len > 255) + if (len + 2 > buflen) return SC_ERROR_BUFFER_TOO_SMALL; buf[count++] = CTBCS_TAG_PROMPT; buf[count++] = len; @@ -113,7 +115,7 @@ ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *da { const char *prompt; size_t buflen, count = 0, j = 0, len; - static u8 buf[254]; + static u8 buf[256]; u8 control; ctbcs_init_apdu(apdu, @@ -126,7 +128,7 @@ ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *da prompt = data->pin1.prompt; if (prompt && *prompt) { len = strlen(prompt); - if (count + len + 2 > buflen || len > 255) + if (len + 2 > buflen) return SC_ERROR_BUFFER_TOO_SMALL; buf[count++] = CTBCS_TAG_PROMPT; buf[count++] = len; diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index daade137..15312f7e 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -70,7 +72,6 @@ static const struct _sc_driver_entry internal_card_drivers[] = { #endif { "gemsafeV1", (void *(*)(void)) sc_get_gemsafeV1_driver }, { "miocos", (void *(*)(void)) sc_get_miocos_driver }, - { "mcrd", (void *(*)(void)) sc_get_mcrd_driver }, { "asepcos", (void *(*)(void)) sc_get_asepcos_driver }, { "starcos", (void *(*)(void)) sc_get_starcos_driver }, { "tcos", (void *(*)(void)) sc_get_tcos_driver }, @@ -100,14 +101,17 @@ static const struct _sc_driver_entry internal_card_drivers[] = { #ifdef ENABLE_OPENSSL { "dnie", (void *(*)(void)) sc_get_dnie_driver }, #endif + { "masktech", (void *(*)(void)) sc_get_masktech_driver }, /* Here should be placed drivers that need some APDU transactions to * recognise its cards. */ + { "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 }, { "itacns", (void *(*)(void)) sc_get_itacns_driver }, + { "isoApplet", (void *(*)(void)) sc_get_isoApplet_driver }, /* The default driver should be last, as it handles all the * unrecognized cards. */ { "default", (void *(*)(void)) sc_get_default_driver }, @@ -182,8 +186,7 @@ static void set_defaults(sc_context_t *ctx, struct _sc_ctx_options *opts) if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) fclose(ctx->debug_file); ctx->debug_file = stderr; - ctx->paranoid_memory = 0; - ctx->enable_default_driver = 0; + ctx->flags = 0; #ifdef __APPLE__ /* Override the default debug log for OpenSC.tokend to be different from PKCS#11. @@ -244,7 +247,7 @@ load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options * if (val) { #ifdef _WIN32 expanded_len = PATH_MAX; - expanded_len = ExpandEnvironmentStrings(val, expanded_val, expanded_len); + expanded_len = ExpandEnvironmentStringsA(val, expanded_val, expanded_len); if (expanded_len > 0) val = expanded_val; #endif @@ -254,11 +257,13 @@ load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options * sc_ctx_log_to_file(ctx, val); } - ctx->paranoid_memory = scconf_get_bool (block, "paranoid-memory", - ctx->paranoid_memory); + if (scconf_get_bool (block, "paranoid-memory", + ctx->flags & SC_CTX_FLAG_PARANOID_MEMORY)) + ctx->flags |= SC_CTX_FLAG_PARANOID_MEMORY; - ctx->enable_default_driver = scconf_get_bool (block, "enable_default_driver", - ctx->enable_default_driver); + if (scconf_get_bool (block, "enable_default_driver", + 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) { @@ -285,15 +290,28 @@ static void load_reader_driver_options(sc_context_t *ctx) { struct sc_reader_driver *driver = ctx->reader_driver; scconf_block *conf_block = NULL; - - driver->max_send_size = 0; - driver->max_recv_size = 0; + sc_reader_t *reader; + int max_send_size; + int max_recv_size; conf_block = sc_get_conf_block(ctx, "reader_driver", driver->short_name, 1); if (conf_block != NULL) { - driver->max_send_size = scconf_get_int(conf_block, "max_send_size", driver->max_send_size); - driver->max_recv_size = scconf_get_int(conf_block, "max_recv_size", driver->max_recv_size); + max_send_size = scconf_get_int(conf_block, "max_send_size", -1); + max_recv_size = scconf_get_int(conf_block, "max_recv_size", -1); + if (max_send_size >= 0 || max_recv_size >= 0) { + if (list_iterator_start(&ctx->readers)) { + reader = list_iterator_next(&ctx->readers); + while (reader) { + if (max_send_size >= 0) + reader->max_send_size = max_send_size; + if (max_recv_size >= 0) + reader->max_recv_size = max_recv_size; + reader = list_iterator_next(&ctx->readers); + } + list_iterator_stop(&ctx->readers); + } + } } } @@ -551,7 +569,7 @@ static void process_config_file(sc_context_t *ctx, struct _sc_ctx_options *opts) #ifdef _WIN32 conf_path = getenv("OPENSC_CONF"); if (!conf_path) { - rc = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey); + rc = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey); if (rc == ERROR_SUCCESS) { temp_len = PATH_MAX; rc = RegQueryValueEx( hKey, "ConfigFile", NULL, NULL, (LPBYTE) temp_path, &temp_len); @@ -562,7 +580,7 @@ static void process_config_file(sc_context_t *ctx, struct _sc_ctx_options *opts) } if (!conf_path) { - rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); + rc = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); if (rc == ERROR_SUCCESS) { temp_len = PATH_MAX; rc = RegQueryValueEx( hKey, "ConfigFile", NULL, NULL, (LPBYTE) temp_path, &temp_len); @@ -706,7 +724,9 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) return SC_ERROR_OUT_OF_MEMORY; } + ctx->flags = parm->flags; set_defaults(ctx, &opts); + list_init(&ctx->readers); list_attributes_seeker(&ctx->readers, reader_list_seeker); /* set thread context and create mutex object (if specified) */ @@ -735,7 +755,6 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) ctx->reader_driver = sc_get_openct_driver(); #endif - load_reader_driver_options(ctx); r = ctx->reader_driver->ops->init(ctx); if (r != SC_SUCCESS) { sc_release_context(ctx); @@ -751,6 +770,7 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) } del_drvs(&opts); sc_ctx_detect_readers(ctx); + load_reader_driver_options(ctx); *ctx_out = ctx; return SC_SUCCESS; @@ -840,7 +860,7 @@ int sc_set_card_driver(sc_context_t *ctx, const char *short_name) if (short_name == NULL) { ctx->forced_driver = NULL; match = 1; - } else while (ctx->card_drivers[i] != NULL && i < SC_MAX_CARD_DRIVERS) { + } else while (i < SC_MAX_CARD_DRIVERS && ctx->card_drivers[i] != NULL) { struct sc_card_driver *drv = ctx->card_drivers[i]; if (strcmp(short_name, drv->short_name) == 0) { @@ -873,7 +893,7 @@ int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize) /* If USERPROFILE isn't defined, assume it's a single-user OS * and put the cache dir in the Windows dir (usually C:\\WINDOWS) */ if (homedir == NULL || homedir[0] == '\0') { - GetWindowsDirectory(temp_path, sizeof(temp_path)); + GetWindowsDirectoryA(temp_path, sizeof(temp_path)); homedir = temp_path; } #endif diff --git a/src/libopensc/cwa-dnie.c b/src/libopensc/cwa-dnie.c index 62060db0..68a15a3f 100644 --- a/src/libopensc/cwa-dnie.c +++ b/src/libopensc/cwa-dnie.c @@ -42,6 +42,8 @@ #include #include +#define MAX_RESP_BUFFER_SIZE 2048 + /********************* Keys and certificates as published by DGP ********/ /** @@ -209,7 +211,7 @@ int dnie_read_file(sc_card_t * card, const sc_path_t * path, sc_file_t ** file, u8 ** buffer, size_t * length) { - u8 *data; + u8 *data = NULL; char *msg = NULL; int res = SC_SUCCESS; size_t fsize = 0; /* file size */ @@ -265,8 +267,12 @@ int dnie_read_file(sc_card_t * card, res = SC_SUCCESS; goto dnie_read_file_end; dnie_read_file_err: - if (*file) + if (data) + free(data); + if (*file) { sc_file_free(*file); + *file = NULL; + } dnie_read_file_end: if (msg) sc_log(ctx, msg); @@ -287,39 +293,37 @@ int dnie_read_file(sc_card_t * card, static int dnie_read_certificate(sc_card_t * card, char *certpath, X509 ** cert) { sc_file_t *file = NULL; - sc_path_t *path = NULL; - u8 *buffer = NULL; + sc_path_t path; + u8 *buffer = NULL, *buffer2 = NULL; char *msg = NULL; size_t bufferlen = 0; int res = SC_SUCCESS; LOG_FUNC_CALLED(card->ctx); - path = (sc_path_t *) calloc(1, sizeof(sc_path_t)); - if (!path) { - msg = "Cannot allocate path data for cert read"; - res = SC_ERROR_OUT_OF_MEMORY; - goto read_cert_end; - } - sc_format_path(certpath, path); - res = dnie_read_file(card, path, &file, &buffer, &bufferlen); + sc_format_path(certpath, &path); + res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); if (res != SC_SUCCESS) { msg = "Cannot get intermediate CA cert"; goto read_cert_end; } - *cert = d2i_X509(NULL, (const unsigned char **)&buffer, bufferlen); + buffer2 = buffer; + *cert = d2i_X509(NULL, (const unsigned char **)&buffer2, bufferlen); if (*cert == NULL) { /* received data is not a certificate */ res = SC_ERROR_OBJECT_NOT_VALID; - msg = "Readed data is not a certificate"; + msg = "Read data is not a certificate"; goto read_cert_end; } res = SC_SUCCESS; read_cert_end: + if (buffer) { + free(buffer); + buffer = NULL; + bufferlen = 0; + } if (file) { sc_file_free(file); file = NULL; - buffer = NULL; - bufferlen = 0; } if (msg) sc_log(card->ctx, msg); @@ -688,16 +692,14 @@ cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card) static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu) { - u8 *buf = NULL; /* use for store partial le responses */ + u8 buf[MAX_RESP_BUFFER_SIZE]; /* use for store partial le responses */ int res = SC_SUCCESS; cwa_provider_t *provider = NULL; if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL)) return SC_ERROR_INVALID_ARGUMENTS; LOG_FUNC_CALLED(card->ctx); provider = GET_DNIE_PRIV_DATA(card)->cwa_provider; - buf = calloc(2048, sizeof(u8)); - if (!buf) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + memset(buf, 0, sizeof(buf)); /* check if envelope is needed */ if (apdu->lc <= card->max_send_size) { @@ -711,8 +713,10 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu) if (tmp == SC_APDU_CASE_3_SHORT) apdu->cse = SC_APDU_CASE_4_SHORT; if (apdu->resplen == 0) { /* no response buffer: create */ - apdu->resp = buf; - apdu->resplen = 2048; + apdu->resp = calloc(1, MAX_RESP_BUFFER_SIZE); + if (apdu->resp == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + apdu->resplen = MAX_RESP_BUFFER_SIZE; apdu->le = card->max_recv_size; } } @@ -724,15 +728,15 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu) size_t e_txlen = 0; size_t index = 0; - sc_apdu_t *e_apdu = NULL; - u8 *e_tx = NULL; + sc_apdu_t e_apdu; + u8 * e_tx = NULL; /* envelope needed */ sc_log(card->ctx, "envelope tx required: lc:%d", apdu->lc); - e_apdu = calloc(1, sizeof(sc_apdu_t)); /* enveloped apdu */ e_tx = calloc(7 + apdu->datalen, sizeof(u8)); /* enveloped data */ - if (!e_apdu || !e_tx) + + if (!e_tx) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); /* copy apdu info into enveloped data */ @@ -753,35 +757,47 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu) index, len); /* compose envelope apdu command */ - sc_format_apdu(card, e_apdu, apdu->cse, 0xC2, 0x00, - 0x00); - e_apdu->cla = 0x90; /* propietary CLA */ - e_apdu->data = e_tx + index; - e_apdu->lc = len; - e_apdu->datalen = len; - e_apdu->le = apdu->le; - e_apdu->resp = apdu->resp; - e_apdu->resplen = apdu->resplen; + sc_format_apdu(card, &e_apdu, apdu->cse, 0xC2, 0x00, 0x00); + e_apdu.cla = 0x90; /* propietary CLA */ + e_apdu.data = e_tx + index; + e_apdu.lc = len; + e_apdu.datalen = len; + e_apdu.le = apdu->le; + e_apdu.resp = apdu->resp; + e_apdu.resplen = apdu->resplen; /* if SM is ON, ensure resp exists, and force getResponse() */ if (provider->status.session.state == CWA_SM_ACTIVE) { /* set up proper apdu type */ - if (e_apdu->cse == SC_APDU_CASE_3_SHORT) - e_apdu->cse = SC_APDU_CASE_4_SHORT; + if (e_apdu.cse == SC_APDU_CASE_3_SHORT) + e_apdu.cse = SC_APDU_CASE_4_SHORT; /* if no response buffer: create */ if (apdu->resplen == 0) { - e_apdu->resp = buf; - e_apdu->resplen = 2048; - e_apdu->le = card->max_recv_size; + e_apdu.resp = buf; + e_apdu.resplen = 2048; + e_apdu.le = card->max_recv_size; } } /* send data chunk bypassing apdu wrapping */ - res = sc_transmit_apdu(card, e_apdu); - LOG_TEST_RET(card->ctx, res, - "Error in envelope() send apdu"); + res = sc_transmit_apdu(card, &e_apdu); + if (res != SC_SUCCESS) { + if (e_tx) { + free(e_tx); + e_tx = NULL; + } + sc_log(card->ctx, "Error in envelope() send apdu"); + LOG_FUNC_RETURN(card->ctx, res); + } } /* for */ + if (e_tx) { + free(e_tx); + e_tx = NULL; + } /* last apdu sent contains response to enveloped cmd */ - apdu->resp = e_apdu->resp; - apdu->resplen = e_apdu->resplen; + apdu->resp = calloc(1, MAX_RESP_BUFFER_SIZE); + if (apdu->resp == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + memcpy(apdu->resp, e_apdu.resp, e_apdu.resplen); + apdu->resplen = e_apdu.resplen; res = SC_SUCCESS; } LOG_FUNC_RETURN(card->ctx, res); @@ -817,6 +833,7 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu) sc_context_t *ctx; cwa_provider_t *provider = NULL; int retries = 3; + char * msg = NULL; if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL)) return SC_ERROR_INVALID_ARGUMENTS; @@ -831,13 +848,18 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu) wrapped.resp = NULL; wrapped.resplen = 0; /* let get_response() assign space */ res = cwa_encode_apdu(card, provider, apdu, &wrapped); - LOG_TEST_RET(ctx, res, - "Error in cwa_encode_apdu process"); + if (res != SC_SUCCESS) { + msg = "Error in cwa_encode_apdu process"; + goto cleanup_and_return; + } } /* send apdu via envelope() cmd if needed */ res = dnie_transmit_apdu_internal(card, &wrapped); /* check for tx errors */ - LOG_TEST_RET(ctx, res, "Error in dnie_transmit_apdu process"); + if (res != SC_SUCCESS) { + msg = "Error in dnie_transmit_apdu process"; + goto cleanup_and_return; + } /* parse response and handle SM related errors */ res=card->ops->check_sw(card,wrapped.sw1,wrapped.sw2); @@ -852,7 +874,10 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu) /* SM was active: force restart SM and retry */ case CWA_SM_ACTIVE: res=cwa_create_secure_channel(card, provider, CWA_SM_COLD); - LOG_TEST_RET(ctx,res,"Cannot re-enable SM"); + if (res != SC_SUCCESS) { + msg = "Cannot re-enable SM"; + goto cleanup_and_return; + } continue; } } @@ -862,15 +887,24 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu) apdu->resp = NULL; apdu->resplen = 0; /* let cwa_decode_response() eval & create size */ res = cwa_decode_response(card, provider, &wrapped, apdu); - LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process"); + if (res != SC_SUCCESS) + msg = "Error in cwa_decode_response process"; + goto cleanup_and_return; } else { + if (apdu->resp != wrapped.resp) free(apdu->resp); /* memcopy result to original apdu */ memcpy(apdu, &wrapped, sizeof(sc_apdu_t)); + LOG_FUNC_RETURN(ctx, res); } - LOG_FUNC_RETURN(ctx, res); } - sc_log(ctx,"Too many retransmissions. Abort and return"); - LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); + msg = "Too many retransmissions. Abort and return"; + res = SC_ERROR_INTERNAL; + +cleanup_and_return: + if (apdu->resp != wrapped.resp) free(wrapped.resp); + if (msg) + sc_log(ctx, msg); + LOG_FUNC_RETURN(ctx, res); } int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu) diff --git a/src/libopensc/cwa14890.c b/src/libopensc/cwa14890.c index dbbd599b..2d7e27f5 100644 --- a/src/libopensc/cwa14890.c +++ b/src/libopensc/cwa14890.c @@ -43,6 +43,23 @@ #include "cwa14890.h" +/** + * Structure used to compose BER-TLV encoded data + * 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 + * Also, encodings for data length longer than 0x01000000 bytes + * are not supported (tag 0x84) + */ +typedef struct cwa_tlv_st { + u8 *buf; /** local copy of TLV byte array */ + size_t buflen; /** lengt of buffer */ + unsigned int tag; /** tag ID */ + size_t len; /** length of data field */ + u8 *data; /** pointer to start of data in buf buffer */ +} cwa_tlv_t; + /*********************** utility functions ************************/ /** @@ -242,13 +259,13 @@ static int cwa_compose_tlv(sc_card_t * card, * @return SC_SUCCESS if OK; else error code */ static int cwa_parse_tlv(sc_card_t * card, - u8 * data, size_t datalen, cwa_tlv_t tlv_array[] + u8 * buffer, size_t datalen, + cwa_tlv_t tlv_array[] ) { size_t n = 0; size_t next = 0; sc_context_t *ctx = NULL; - u8 *buffer = NULL; /* preliminary checks */ if (!card || !card->ctx) @@ -257,14 +274,9 @@ static int cwa_parse_tlv(sc_card_t * card, ctx = card->ctx; LOG_FUNC_CALLED(ctx); - if (!data || !tlv_array) + if (!tlv_array) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - /* create buffer and copy data into */ - buffer = calloc(datalen, sizeof(u8)); - if (!buffer) - LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - memcpy(buffer, data, datalen); for (n = 0; n < datalen; n += next) { cwa_tlv_t *tlv = NULL; /* pointer to TLV structure to store info */ size_t j = 2; /* TLV has at least two bytes */ @@ -1385,6 +1397,10 @@ int cwa_create_secure_channel(sc_card_t * card, /* arriving here means ok: cleanup */ res = SC_SUCCESS; csc_end: + if (icc_cert) + X509_free(icc_cert); + if (ca_cert) + X509_free(ca_cert); if (icc_pubkey) EVP_PKEY_free(icc_pubkey); if (ifd_privkey) @@ -1418,9 +1434,9 @@ int cwa_create_secure_channel(sc_card_t * card, int cwa_encode_apdu(sc_card_t * card, cwa_provider_t * provider, sc_apdu_t * from, sc_apdu_t * to) { - u8 *apdubuf; /* to store resulting apdu */ + u8 *apdubuf = NULL; /* to store resulting apdu */ size_t apdulen; - u8 *ccbuf; /* where to store data to eval cryptographic checksum CC */ + u8 *ccbuf = NULL; /* where to store data to eval cryptographic checksum CC */ size_t cclen = 0; u8 macbuf[8]; /* to store and compute CC */ DES_key_schedule k1; @@ -1434,10 +1450,6 @@ int cwa_encode_apdu(sc_card_t * card, u8 *msgbuf = NULL; /* to encrypt apdu data */ u8 *cryptbuf = NULL; - /* reserve extra bytes for padding and tlv header */ - msgbuf = calloc(12 + from->lc, sizeof(u8)); /* to encrypt apdu data */ - cryptbuf = calloc(12 + from->lc, sizeof(u8)); - /* mandatory check */ if (!card || !card->ctx || !provider) return SC_ERROR_INVALID_ARGUMENTS; @@ -1450,6 +1462,10 @@ int cwa_encode_apdu(sc_card_t * card, LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED); if (sm_session->state != CWA_SM_ACTIVE) LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL); + + /* reserve extra bytes for padding and tlv header */ + msgbuf = calloc(12 + from->lc, sizeof(u8)); /* to encrypt apdu data */ + cryptbuf = calloc(12 + from->lc, sizeof(u8)); if (!msgbuf || !cryptbuf) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); @@ -1477,6 +1493,7 @@ int cwa_encode_apdu(sc_card_t * card, /* reserve enougth space for apdulen+tlv bytes * to-be-crypted buffer and result apdu buffer */ + /* TODO DEE add 4 more bytes for testing.... */ apdubuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen), sizeof(u8)); @@ -1532,14 +1549,16 @@ int cwa_encode_apdu(sc_card_t * card, } /* if le byte is declared, compose and add Le TLV */ - /* TODO: study why original driver checks for le>=256? */ - if (from->le > 0) { - u8 le = 0xff & from->le; - res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen); - if (res != SC_SUCCESS) { - msg = "Encode APDU compose_tlv(0x97) failed"; - goto encode_end; - } + /* FIXME: For DNIe we must not send the le bytes + when le == 256 but this goes against the standard + and might break other cards reusing this code */ + if ((0xff & from->le) > 0) { + u8 le = 0xff & from->le; + res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen); + if (res != SC_SUCCESS) { + msg = "Encode APDU compose_tlv(0x97) failed"; + goto encode_end; + } } /* copy current data to apdu buffer (skip header and header padding) */ memcpy(apdubuf, ccbuf + 8, cclen - 8); @@ -1591,12 +1610,20 @@ int cwa_encode_apdu(sc_card_t * card, goto encode_end; } } + /* that's all folks */ res = SC_SUCCESS; + goto encode_end_apdu_valid; - encode_end: +encode_end: + if (apdubuf) + free(apdubuf); +encode_end_apdu_valid: if (msg) sc_log(ctx, msg); + free(msgbuf); + free(cryptbuf); + free(ccbuf); LOG_FUNC_RETURN(ctx, res); } @@ -1624,6 +1651,7 @@ int cwa_decode_response(sc_card_t * card, cwa_tlv_t *e_tlv = &tlv_array[1]; /* to store pad encoded data (Tag 0x87) */ cwa_tlv_t *m_tlv = &tlv_array[2]; /* to store mac CC (Tag 0x8E) */ cwa_tlv_t *s_tlv = &tlv_array[3]; /* to store sw1-sw2 status (Tag 0x99) */ + u8 *buffer = NULL; /* buffer for data. pointers to this buffer are in tlv_array */ u8 *ccbuf = NULL; /* buffer for mac CC calculation */ size_t cclen = 0; /* ccbuf len */ u8 macbuf[8]; /* where to calculate mac */ @@ -1687,8 +1715,16 @@ int cwa_decode_response(sc_card_t * card, /* parse response to find TLV's data and check results */ memset(tlv_array, 0, 4 * sizeof(cwa_tlv_t)); + /* create buffer and copy data into */ + buffer = calloc(from->resplen, sizeof(u8)); + if (!buffer) { + msg = "Cannot allocate space for response buffer"; + res = SC_ERROR_OUT_OF_MEMORY; + goto response_decode_end; + } + memcpy(buffer, from->resp, from->resplen); - res = cwa_parse_tlv(card, from->resp, from->resplen, tlv_array); + res = cwa_parse_tlv(card, buffer, from->resplen, tlv_array); if (res != SC_SUCCESS) { msg = "Error in TLV parsing"; goto response_decode_end; @@ -1789,7 +1825,7 @@ int cwa_decode_response(sc_card_t * card, if (to->resp) { /* if response apdu provides buffer, try to use it */ if (to->resplen < resplen) { msg = - "Provided buffer has not enought size to store response"; + "Provided buffer has not enough size to store response"; res = SC_ERROR_OUT_OF_MEMORY; goto response_decode_end; } @@ -1857,7 +1893,7 @@ int cwa_decode_response(sc_card_t * card, res = provider->cwa_decode_post_ops(card, provider, from, to); if (res != SC_SUCCESS) { sc_log(ctx, "Decode APDU: provider post_ops() failed"); - LOG_FUNC_RETURN(ctx, res); + goto response_decode_end; } } @@ -1865,6 +1901,8 @@ int cwa_decode_response(sc_card_t * card, res = SC_SUCCESS; response_decode_end: + if (buffer) + free(buffer); if (ccbuf) free(ccbuf); if (msg) { diff --git a/src/libopensc/cwa14890.h b/src/libopensc/cwa14890.h index 10a0e0ee..5cebe728 100644 --- a/src/libopensc/cwa14890.h +++ b/src/libopensc/cwa14890.h @@ -51,23 +51,6 @@ #include #include -/** - * Structure used to compose BER-TLV encoded data - * 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 lenght - * Also, encodings for data lenght longer than 0x01000000 bytes - * are not supported (tag 0x84) - */ -typedef struct cwa_tlv_st { - u8 *buf; /** local copy of TLV byte array */ - size_t buflen; /** lengt of buffer */ - unsigned int tag; /** tag ID */ - size_t len; /** lenght of data field */ - u8 *data; /** pointer to start of data in buf buffer */ -} cwa_tlv_t; - /** * Structure used to handle keys and sequence counter once SM session * is stablished diff --git a/src/libopensc/dir.c b/src/libopensc/dir.c index 8281fbc6..5d448516 100644 --- a/src/libopensc/dir.c +++ b/src/libopensc/dir.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -36,7 +38,8 @@ struct app_entry { static const struct app_entry apps[] = { { (const u8 *) "\xA0\x00\x00\x00\x63PKCS-15", 12, "PKCS #15" }, { (const u8 *) "\xA0\x00\x00\x01\x77PKCS-15", 12, "Belgian eID" }, - { (const u8 *) "\x44\x46\x20\x69\x73\x73\x75\x65\x72", 9, "Portugal eID" } + { (const u8 *) "\x44\x46\x20\x69\x73\x73\x75\x65\x72", 9, "Portugal eID" }, + { (const u8 *) "\xE8\x28\xBD\x08\x0F\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E", 15, "ESIGN"} }; static const struct sc_asn1_entry c_asn1_dirrecord[] = { @@ -91,7 +94,7 @@ parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr) else app->label = NULL; - if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT) { + if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT && path_len > 0) { /* application path present: ignore AID */ if (path_len > SC_MAX_PATH_SIZE) { free(app); diff --git a/src/libopensc/errors.c b/src/libopensc/errors.c index adc55b87..b6c6eb48 100644 --- a/src/libopensc/errors.c +++ b/src/libopensc/errors.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include diff --git a/src/libopensc/iasecc-sdo.c b/src/libopensc/iasecc-sdo.c index ea5aa971..d274c74b 100644 --- a/src/libopensc/iasecc-sdo.c +++ b/src/libopensc/iasecc-sdo.c @@ -985,7 +985,8 @@ iasecc_sdo_encode_create(struct sc_context *ctx, struct iasecc_sdo *sdo, unsigne rv = sc_asn1_encode(ctx, asn1_create_data, out, &out_len); LOG_TEST_RET(ctx, rv, "Encode create data error"); - sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Create data: %s", sc_dump_hex(*out, out_len)); + if (out) + sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Create data: %s", sc_dump_hex(*out, out_len)); LOG_FUNC_RETURN(ctx, out_len); } @@ -1287,4 +1288,15 @@ iasecc_docp_copy(struct sc_context *ctx, struct iasecc_sdo_docp *in, struct iase LOG_FUNC_RETURN(ctx, SC_SUCCESS); } +#else + +/* we need to define the functions below to export them */ +#include "errors.h" + +int +iasecc_sdo_encode_update_field() +{ + return SC_ERROR_NOT_SUPPORTED; +} + #endif /* ENABLE_OPENSSL */ diff --git a/src/libopensc/iasecc-sm.c b/src/libopensc/iasecc-sm.c index 7fdffbdc..4996c234 100644 --- a/src/libopensc/iasecc-sm.c +++ b/src/libopensc/iasecc-sm.c @@ -25,6 +25,7 @@ #include "internal.h" #include "asn1.h" #include "cardctl.h" +#include "common/compat_strlcpy.h" #include "sm.h" #include "iasecc.h" @@ -36,12 +37,15 @@ static int sm_save_sc_context (struct sc_card *card, struct sm_info *sm_info) { - struct sc_context *ctx = card->ctx; - struct sc_card_cache *cache = &card->cache; + struct sc_context *ctx; + struct sc_card_cache *cache; if (!card || !sm_info) return SC_ERROR_INVALID_ARGUMENTS; + ctx = card->ctx; + cache = &card->cache; + sc_log(ctx, "SM save context: cache(valid:%i,current_df:%p)", cache->valid, cache->current_df); if (cache->valid && cache->current_df) { sm_info->current_path_df = cache->current_df->path; @@ -156,7 +160,7 @@ iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int * if (card->sm_ctx.sm_mode == SM_MODE_NONE) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot do 'External Authentication' without SM activated "); - strncpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); + strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); sm_info->cmd = SM_CMD_EXTERNAL_AUTH; sm_info->serialnr = card->serialnr; sm_info->card_type = card->type; @@ -296,7 +300,7 @@ iasecc_sm_initialize(struct sc_card *card, unsigned se_num, unsigned cmd) LOG_FUNC_CALLED(ctx); - strncpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); + strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); sm_info->cmd = cmd; sm_info->serialnr = card->serialnr; sm_info->card_type = card->type; diff --git a/src/libopensc/internal-winscard.h b/src/libopensc/internal-winscard.h index 7d0b6fdc..2389d0c5 100644 --- a/src/libopensc/internal-winscard.h +++ b/src/libopensc/internal-winscard.h @@ -20,6 +20,13 @@ typedef unsigned __int8 uint8_t; #ifdef __APPLE__ #include #endif +// allow unicode built where SCARD_READERSTATE is defined as SCARD_READERSTATEW and SCardGetStatusChange renamed to SCardGetStatusChangeW +#ifdef WIN32 +#ifdef UNICODE +#define SCARD_READERSTATE SCARD_READERSTATEA +#undef SCardGetStatusChange +#endif +#endif #else /* mingw32 does not have winscard.h */ @@ -193,6 +200,7 @@ typedef LONG (PCSC_API *SCardGetAttrib_t)(SCARDHANDLE hCard, DWORD dwAttrId,\ #define PCSCv2_PART10_PROPERTY_bMaxPINSize 7 #define PCSCv2_PART10_PROPERTY_sFirmwareID 8 #define PCSCv2_PART10_PROPERTY_bPPDUSupport 9 +#define PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize 10 /* structures used (but not defined) in PCSC Part 10: * "IFDs with Secure Pin Entry Capabilities" */ diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h index 4edad3d8..418e4179 100644 --- a/src/libopensc/internal.h +++ b/src/libopensc/internal.h @@ -74,7 +74,6 @@ struct sc_atr_table { /* Internal use only */ int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader); -int _sc_delete_reader(struct sc_context *ctx, struct sc_reader *reader); int _sc_parse_atr(struct sc_reader *reader); /* Add an ATR to the card driver's struct sc_atr_table */ @@ -121,7 +120,8 @@ int _sc_card_add_algorithm(struct sc_card *card, const struct sc_algorithm_info int _sc_card_add_rsa_alg(struct sc_card *card, unsigned int key_length, unsigned long flags, unsigned long exponent); int _sc_card_add_ec_alg(struct sc_card *card, unsigned int key_length, - unsigned long flags, unsigned long ext_flags); + unsigned long flags, unsigned long ext_flags, + struct sc_object_id *curve_oid); /********************************************************************/ /* pkcs1 padding/encoding functions */ diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 4defc7f0..39b71868 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -31,37 +31,19 @@ static void fixup_transceive_length(const struct sc_card *card, - struct sc_apdu *apdu) + struct sc_apdu *apdu) { - size_t max_send_size; - size_t max_recv_size; - assert(card != NULL && apdu != NULL); - max_send_size = card->max_send_size; - max_recv_size = card->max_recv_size; - - if (card->caps & SC_CARD_CAP_APDU_EXT) { - if (!max_send_size) - max_send_size = 65535; - if (!max_recv_size) - max_recv_size = 65536; - } else { - if (!max_send_size) - max_send_size = 255; - if (!max_recv_size) - max_recv_size = 256; - } - - if (apdu->lc > max_send_size) { + if (apdu->lc > card->max_send_size) { /* The lower layers will automatically do chaining */ apdu->flags |= SC_APDU_FLAGS_CHAINING; } - if (apdu->le > max_recv_size) { + if (apdu->le > card->max_recv_size) { /* The lower layers will automatically do a GET RESPONSE, if possible. * All other workarounds must be carried out by the upper layers. */ - apdu->le = max_recv_size; + apdu->le = card->max_recv_size; } } @@ -105,7 +87,7 @@ static const struct sc_card_error iso7816_errors[] = { { 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"}, + { 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" }, @@ -350,6 +332,7 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file, { struct sc_context *ctx = card->ctx; size_t taglen, len = buflen; + int i; const unsigned char *tag = NULL, *p = buf; sc_log(ctx, "processing FCI bytes"); @@ -359,17 +342,25 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file, sc_log(ctx, " file identifier: 0x%02X%02X", tag[0], tag[1]); } - tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen); - if (tag == NULL) { - tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen); - } - if (tag != NULL && taglen > 0 && taglen < 3) { - file->size = tag[0]; - if (taglen == 2) - file->size = (file->size << 8) + 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: %d", file->size); - } else { - file->size = 0; + break; } tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); @@ -430,6 +421,10 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file, 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) @@ -452,17 +447,46 @@ iso7816_select_file(struct sc_card *card, const struct sc_path *in_path, struct struct sc_apdu apdu; unsigned char buf[SC_MAX_APDU_BUFFER_SIZE]; unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; - int r, pathlen; + int r, pathlen, pathtype; + int select_mf = 0; struct sc_file *file = NULL; assert(card != NULL && in_path != NULL); ctx = card->ctx; memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; + pathtype = in_path->type; + + if (file_out != NULL) { + *file_out = NULL; + } + if (in_path->aid.len) { + if (!pathlen) { + memcpy(path, in_path->aid.value, in_path->aid.len); + pathlen = in_path->aid.len; + pathtype = SC_PATH_TYPE_DF_NAME; + } else { + /* First, select the application */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 4, 0); + apdu.data = in_path->aid.value; + apdu.datalen = in_path->aid.len; + apdu.lc = in_path->aid.len; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + LOG_FUNC_RETURN(ctx, r); + + if (pathtype == SC_PATH_TYPE_PATH + || pathtype == SC_PATH_TYPE_DF_NAME) + pathtype = SC_PATH_TYPE_FROM_CURRENT; + } + } sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); - switch (in_path->type) { + switch (pathtype) { case SC_PATH_TYPE_FILE_ID: apdu.p1 = 0; if (pathlen != 2) @@ -475,6 +499,7 @@ iso7816_select_file(struct sc_card *card, const struct sc_path *in_path, struct apdu.p1 = 8; if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) { if (pathlen == 2) { /* only 3F00 supplied */ + select_mf = 1; apdu.p1 = 0; break; } @@ -501,7 +526,7 @@ iso7816_select_file(struct sc_card *card, const struct sc_path *in_path, struct apdu.p2 = 0; /* first record, return FCI */ apdu.resp = buf; apdu.resplen = sizeof(buf); - apdu.le = card->max_recv_size > 0 && card->max_recv_size < 256 ? card->max_recv_size : 256; + apdu.le = card->max_recv_size < 256 ? card->max_recv_size : 256; } else { apdu.p2 = 0x0C; /* first record, return nothing */ @@ -527,6 +552,19 @@ iso7816_select_file(struct sc_card *card, const struct sc_path *in_path, struct if (r) LOG_FUNC_RETURN(ctx, r); + if (file_out && (apdu.resplen == 0)) { + /* For some cards 'SELECT' MF or DF_NAME do not return FCI. */ + if (select_mf || pathtype == SC_PATH_TYPE_DF_NAME) { + file = sc_file_new(); + if (file == NULL) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + file->path = *in_path; + + *file_out = file; + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + } + } + if (apdu.resplen < 2) LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); switch (apdu.resp[0]) { @@ -632,7 +670,7 @@ iso7816_construct_fci(struct sc_card *card, const sc_file_t *file, p, *outlen - (p - out), &p); } if (file->sec_attr_len) { - assert(sizeof(buf) >= file->prop_attr_len); + assert(sizeof(buf) >= file->sec_attr_len); memcpy(buf, file->sec_attr, file->sec_attr_len); sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p); @@ -681,7 +719,7 @@ iso7816_get_response(struct sc_card *card, size_t *count, u8 *buf) size_t rlen; /* request at most max_recv_size bytes */ - if (card->max_recv_size > 0 && *count > card->max_recv_size) + if (*count > card->max_recv_size) rlen = card->max_recv_size; else rlen = *count; @@ -955,7 +993,7 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, break; case SC_PIN_CMD_CHANGE: ins = 0x24; - if (data->pin1.len != 0 || use_pin_pad) { + if (data->pin1.len != 0 || (use_pin_pad && !( data->flags & SC_PIN_CMD_IMPLICIT_CHANGE))) { if ((r = sc_build_pin(buf, buf_len, &data->pin1, pad)) < 0) return r; len += r; @@ -972,15 +1010,14 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, * but expect the new one to be entered on the keypad. */ if (data->pin1.len && data->pin2.len == 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Special case - initial pin provided - but new pin asked on keypad"); + sc_log(card->ctx, "Special case - initial pin provided - but new pin asked on keypad"); data->flags |= SC_PIN_CMD_IMPLICIT_CHANGE; }; len += r; break; case SC_PIN_CMD_UNBLOCK: ins = 0x2C; - if (data->pin1.len != 0 || use_pin_pad) { + if (data->pin1.len != 0 || (use_pin_pad && !( data->flags & SC_PIN_CMD_IMPLICIT_CHANGE))) { if ((r = sc_build_pin(buf, buf_len, &data->pin1, pad)) < 0) return r; len += r; @@ -1073,6 +1110,38 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l } +static int iso7816_get_data(struct sc_card *card, unsigned int tag, u8 *buf, size_t len) +{ + int r, cse; + struct sc_apdu apdu; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (buf && len) + cse = SC_APDU_CASE_2; + else + cse = SC_APDU_CASE_1; + + sc_format_apdu(card, &apdu, cse, 0xCA, (tag >> 8) & 0xff, tag & 0xff); + apdu.le = len; + apdu.resp = buf; + apdu.resplen = len; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "GET_DATA returned error"); + + if (apdu.resplen > len) + r = SC_ERROR_WRONG_LENGTH; + else + r = apdu.resplen; + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); +} + + + static int iso7816_init(struct sc_card *card) { @@ -1120,7 +1189,7 @@ static struct sc_card_operations iso_ops = { iso7816_process_fci, iso7816_construct_fci, iso7816_pin_cmd, - NULL, /* get_data */ + iso7816_get_data, NULL, /* put_data */ NULL, /* delete_record */ NULL /* read_public_key */ diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 0b98db2a..cea8d42f 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -51,6 +51,8 @@ sc_asn1_put_tag sc_asn1_skip_tag sc_asn1_verify_tag sc_asn1_write_element +sc_asn1_sig_value_sequence_to_rs +sc_asn1_sig_value_rs_to_sequence sc_base64_decode sc_base64_encode sc_bin_to_hex @@ -75,6 +77,7 @@ sc_ctx_get_reader_by_name sc_ctx_get_reader_count sc_ctx_log_to_file sc_ctx_use_reader +_sc_delete_reader sc_decipher sc_delete_file sc_delete_record @@ -235,6 +238,7 @@ sc_pkcs15emu_add_ec_prkey sc_pkcs15emu_add_ec_pubkey sc_pkcs15emu_add_x509_cert sc_pkcs15emu_object_add +sc_pkcs15_bind_internal sc_print_path sc_put_data sc_read_binary @@ -315,6 +319,7 @@ sc_pkcs15_convert_pubkey sc_sm_parse_answer sc_sm_update_apdu_response sc_sm_single_transmit +sc_sm_stop iasecc_sm_create_file iasecc_sm_delete_file iasecc_sm_external_authentication diff --git a/src/libopensc/log.c b/src/libopensc/log.c index 70b67824..cac82803 100644 --- a/src/libopensc/log.c +++ b/src/libopensc/log.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -73,9 +75,7 @@ static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int lin FILE *outf = NULL; int n; - assert(ctx != NULL); - - if (ctx->debug < level) + if (!ctx || ctx->debug < level) return; p = buf; @@ -167,9 +167,7 @@ void sc_hex_dump(struct sc_context *ctx, int level, const u8 * in, size_t count, char *p = buf; int lines = 0; - assert(ctx != NULL); - - if (ctx->debug < level) + if (!ctx || ctx->debug < level) return; assert(buf != NULL && (in != NULL || count == 0)); @@ -235,3 +233,17 @@ sc_dump_hex(const u8 * in, size_t count) return dump_buf; } + +char * +sc_dump_oid(const struct sc_object_id *oid) +{ + static char dump_buf[SC_MAX_OBJECT_ID_OCTETS * 20]; + size_t ii; + + memset(dump_buf, 0, sizeof(dump_buf)); + if (oid) + for (ii=0; iivalue[ii] != -1; ii++) + snprintf(dump_buf + strlen(dump_buf), sizeof(dump_buf) - strlen(dump_buf), "%s%i", (ii ? "." : ""), oid->value[ii]); + + return dump_buf; +} diff --git a/src/libopensc/log.h b/src/libopensc/log.h index d9b9c438..e1e8c698 100644 --- a/src/libopensc/log.h +++ b/src/libopensc/log.h @@ -60,7 +60,7 @@ void _sc_log(struct sc_context *ctx, const char *format, ...); 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); #define SC_FUNC_CALLED(ctx, level) do { \ sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, "called\n"); \ } while (0) @@ -89,6 +89,16 @@ char * sc_dump_hex(const u8 * in, size_t count); } while(0) #define LOG_TEST_RET(ctx, r, text) SC_TEST_RET((ctx), SC_LOG_DEBUG_NORMAL, (r), (text)) +#define SC_TEST_GOTO_ERR(ctx, level, r, text) do { \ + int _ret = (r); \ + if (_ret < 0) { \ + sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, \ + "%s: %d (%s)\n", (text), _ret, sc_strerror(_ret)); \ + goto err; \ + } \ +} while(0) +#define LOG_TEST_GOTO_ERR(ctx, r, text) SC_TEST_GOTO_ERR((ctx), SC_LOG_DEBUG_NORMAL, (r), (text)) + #ifdef __cplusplus } #endif diff --git a/src/libopensc/muscle-filesystem.c b/src/libopensc/muscle-filesystem.c index f54d263f..602c40dd 100644 --- a/src/libopensc/muscle-filesystem.c +++ b/src/libopensc/muscle-filesystem.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -42,6 +44,8 @@ static const u8* ignoredFiles[] = { mscfs_t *mscfs_new(void) { mscfs_t *fs = malloc(sizeof(mscfs_t)); + if (!fs) + return NULL; memset(fs, 0, sizeof(mscfs_t)); memcpy(fs->currentPath, "\x3F\x00", 2); return fs; diff --git a/src/libopensc/muscle.c b/src/libopensc/muscle.c index ef9322f2..f0b1e921 100644 --- a/src/libopensc/muscle.c +++ b/src/libopensc/muscle.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include @@ -662,8 +664,7 @@ int msc_compute_crypt_init(sc_card_t *card, SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { short receivedData = outputBuffer[0] << 8 | outputBuffer[1]; - *outputDataLength = receivedData; - *outputDataLength = 0; + *outputDataLength = receivedData; assert(receivedData <= MSC_MAX_APDU); memcpy(outputData, outputBuffer + 2, receivedData); diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 5df97687..e9a4d19a 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -191,10 +191,23 @@ struct sc_pbes2_params { struct sc_algorithm_id key_encr_alg; }; -struct sc_ec_params { +/* + * The ecParameters can be presented as + * - name of curve; + * - OID of named curve; + * - implicit parameters. + * + * type - type(choice) of 'EC domain parameters' as it present in CKA_EC_PARAMS (PKCS#11). + Recommended value '1' -- namedCurve. + * field_length - EC key size in bits. + */ +struct sc_ec_parameters { + char *named_curve; + struct sc_object_id id; + struct sc_lv_data der; + int type; - u8 * der; - size_t der_len; + size_t field_length; }; typedef struct sc_algorithm_info { @@ -208,6 +221,7 @@ typedef struct sc_algorithm_info { } _rsa; struct sc_ec_info { unsigned ext_flags; + struct sc_ec_parameters params; } _ec; } u; } sc_algorithm_info_t; @@ -261,8 +275,6 @@ struct sc_reader_driver { const char *short_name; struct sc_reader_operations *ops; - size_t max_send_size; /* Max Lc supported by the reader layer */ - size_t max_recv_size; /* Mac Le supported by the reader layer */ void *dll; }; @@ -272,6 +284,7 @@ struct sc_reader_driver { #define SC_READER_CARD_INUSE 0x00000004 #define SC_READER_CARD_EXCLUSIVE 0x00000008 #define SC_READER_HAS_WAITING_AREA 0x00000010 +#define SC_READER_REMOVED 0x00000020 /* reader capabilities */ #define SC_READER_CAP_DISPLAY 0x00000001 @@ -290,6 +303,8 @@ typedef struct sc_reader { unsigned long flags, capabilities; unsigned int supported_protocols, active_protocol; + size_t max_send_size; /* Max Lc supported by the reader layer */ + size_t max_recv_size; /* Mac Le supported by the reader layer */ struct sc_atr atr; struct _atr_info { @@ -310,7 +325,7 @@ typedef struct sc_reader { #define SC_PIN_CMD_GET_INFO 3 #define SC_PIN_CMD_USE_PINPAD 0x0001 -#define SC_PIN_CMD_NEED_PADDING 0x0002 +#define SC_PIN_CMD_NEED_PADDING 0x0002 #define SC_PIN_CMD_IMPLICIT_CHANGE 0x0004 #define SC_PIN_ENCODING_ASCII 0 @@ -320,14 +335,18 @@ typedef struct sc_reader { struct sc_pin_cmd_pin { const char *prompt; /* Prompt to display */ - const u8 *data; /* PIN, if given by the appliction */ + const unsigned char *data; /* PIN, if given by the appliction */ int len; /* set to -1 to get pin from pin pad */ - size_t min_length; /* min/max length of PIN */ - size_t max_length; + size_t min_length; /* min length of PIN */ + size_t max_length; /* max length of PIN */ + size_t stored_length; /* stored length of PIN */ + unsigned int encoding; /* ASCII-numeric, BCD, etc */ + size_t pad_length; /* filled in by the card driver */ - u8 pad_char; + unsigned char pad_char; + size_t offset; /* PIN offset in the APDU */ size_t length_offset; /* Effective PIN length offset in the APDU */ @@ -349,73 +368,6 @@ struct sc_pin_cmd_data { struct sc_apdu *apdu; /* APDU of the PIN command */ }; -#if 0 -#define PACE_PIN_ID_MRZ 0x01 -#define PACE_PIN_ID_CAN 0x02 -#define PACE_PIN_ID_PIN 0x03 -#define PACE_PIN_ID_PUK 0x04 -/** - * Input data for EstablishPACEChannel() - */ -struct establish_pace_channel_input { - /** Type of secret (CAN, MRZ, PIN or PUK). */ - unsigned char pin_id; - - /** Length of \a chat */ - size_t chat_length; - /** Card holder authorization template */ - const unsigned char *chat; - - /** Length of \a pin */ - size_t pin_length; - /** Secret */ - const unsigned char *pin; - - /** Length of \a certificate_description */ - size_t certificate_description_length; - /** Certificate description */ - const unsigned char *certificate_description; -}; - -/** - * Output data for EstablishPACEChannel() - */ -struct establish_pace_channel_output { - /** PACE result (TR-03119) */ - unsigned int result; - - /** MSE: Set AT status byte */ - unsigned char mse_set_at_sw1; - /** MSE: Set AT status byte */ - unsigned char mse_set_at_sw2; - - /** Length of \a ef_cardaccess */ - size_t ef_cardaccess_length; - /** EF.CardAccess */ - unsigned char *ef_cardaccess; - - /** Length of \a recent_car */ - size_t recent_car_length; - /** Most recent certificate authority reference */ - unsigned char *recent_car; - - /** Length of \a previous_car */ - size_t previous_car_length; - /** Previous certificate authority reference */ - unsigned char *previous_car; - - /** Length of \a id_icc */ - size_t id_icc_length; - /** ICC identifier */ - unsigned char *id_icc; - - /** Length of \a id_pcd */ - size_t id_pcd_length; - /** PCD identifier */ - unsigned char *id_pcd; -}; -#endif - struct sc_reader_operations { /* Called during sc_establish_context(), when the driver * is loaded */ @@ -687,13 +639,25 @@ typedef struct { unsigned long (*thread_id)(void); } sc_thread_context_t; +/** Stop modifing 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 + * the duplicated card handles for the parent process. With this flag the child + * process indicates that shall the reader shall ignore those resources when + * calling sc_disconnect_card. + */ +#define SC_CTX_FLAG_TERMINATE 0x00000001 +#define SC_CTX_FLAG_PARANOID_MEMORY 0x00000002 +#define SC_CTX_FLAG_DEBUG_MEMORY 0x00000004 +#define SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER 0x00000008 + typedef struct sc_context { scconf_context *conf; scconf_block *conf_blocks[3]; char *app_name; int debug; - int paranoid_memory; - int enable_default_driver; + unsigned long flags; FILE *debug_file; char *debug_filename; @@ -767,7 +731,7 @@ typedef struct { * dependend configuration data). If NULL the name "default" * will be used. */ const char *app_name; - /** flags, currently unused */ + /** context flags */ unsigned long flags; /** mutex functions to use (optional) */ sc_thread_context_t *thread_ctx; @@ -851,6 +815,8 @@ sc_reader_t *sc_ctx_get_reader_by_id(sc_context_t *ctx, unsigned int id); */ unsigned int sc_ctx_get_reader_count(sc_context_t *ctx); +int _sc_delete_reader(sc_context_t *ctx, sc_reader_t *reader); + /** * Redirects OpenSC debug log to the specified file * @param ctx existing OpenSC context @@ -1282,7 +1248,7 @@ void sc_print_cache(struct sc_card *card); struct sc_algorithm_info * sc_card_find_rsa_alg(struct sc_card *card, unsigned int key_length); struct sc_algorithm_info * sc_card_find_ec_alg(struct sc_card *card, - unsigned int field_length); + unsigned int field_length, struct sc_object_id *curve_oid); struct sc_algorithm_info * sc_card_find_gostr3410_alg(struct sc_card *card, unsigned int key_length); @@ -1301,6 +1267,15 @@ unsigned sc_crc32(unsigned char *value, size_t len); */ void sc_remote_data_init(struct sc_remote_data *rdata); + +/** + * Copy and allocate if needed EC parameters data + * @dst destination + * @src source + */ +int sc_copy_ec_params(struct sc_ec_parameters *, struct sc_ec_parameters *); + + struct sc_card_error { unsigned int SWs; int errorno; diff --git a/src/libopensc/p15card-helper.c b/src/libopensc/p15card-helper.c index 3bf698c8..1a16da7d 100644 --- a/src/libopensc/p15card-helper.c +++ b/src/libopensc/p15card-helper.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_OPENSSL /* empty file without openssl */ #include diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c index 21a56098..290e6160 100644 --- a/src/libopensc/padding.c +++ b/src/libopensc/padding.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-actalis.c b/src/libopensc/pkcs15-actalis.c index de335891..9391418a 100644 --- a/src/libopensc/pkcs15-actalis.c +++ b/src/libopensc/pkcs15-actalis.c @@ -22,7 +22,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -122,10 +124,6 @@ static int sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card, info.modulus_length = modulus_length; info.usage = usage; info.native = 1; - info.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE - | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE - | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE - | SC_PKCS15_PRKEY_ACCESS_LOCAL; info.key_reference = ref; if (path) diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c index ce06f4e6..8fa1ca7b 100644 --- a/src/libopensc/pkcs15-algo.c +++ b/src/libopensc/pkcs15-algo.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -249,8 +251,8 @@ asn1_free_pbes2_params(void *ptr) free(params); } -static const struct sc_asn1_entry c_asn1_ec_params[] = { - { "ecParameters", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, +static const struct sc_asn1_entry c_asn1_ec_params[] = { + { "ecParameters", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { "namedCurve", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL}, { "implicityCA", SC_ASN1_NULL, SC_ASN1_TAG_NULL, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } @@ -263,73 +265,71 @@ asn1_decode_ec_params(sc_context_t *ctx, void **paramp, int r; struct sc_object_id curve; struct sc_asn1_entry asn1_ec_params[4]; - struct sc_ec_params * ecp; + struct sc_ec_parameters *ecp; sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params %p:%d %d", buf, buflen, depth); memset(&curve, 0, sizeof(curve)); - ecp = malloc(sizeof(struct sc_ec_params)); - if (ecp == NULL) - return SC_ERROR_OUT_OF_MEMORY; - memset(ecp,0,sizeof(struct sc_ec_params)); - - /* We only want to copy the parms if they are a namedCurve - * or ecParameters nullParam aka implicityCA is not to be + /* We only want to copy the parms if they are a namedCurve + * or ecParameters nullParam aka implicityCA is not to be * used with PKCS#11 2.20 */ sc_copy_asn1_entry(c_asn1_ec_params, asn1_ec_params); sc_format_asn1_entry(asn1_ec_params + 1, &curve, 0, 0); /* Some signature algorithms will not have any data */ - if (buflen == 0 || buf == NULL) { - free(ecp); + if (buflen == 0 || buf == NULL) return 0; - } r = sc_asn1_decode_choice(ctx, asn1_ec_params, buf, buflen, NULL, NULL); - /* r = index into asn1_ec_params */ - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params r=%d", r); - if (r < 0) { - free(ecp); + /* r = index in asn1_ec_params */ + sc_debug(ctx, SC_LOG_DEBUG_ASN1, "asn1_decode_ec_params r=%d", r); + if (r < 0) return r; - } + + ecp = calloc(sizeof(struct sc_ec_parameters), 1); + if (ecp == NULL) + return SC_ERROR_OUT_OF_MEMORY; + if (r <= 1) { - ecp->der = malloc(buflen); - - if (ecp->der == NULL) + ecp->der.value = malloc(buflen); + if (ecp->der.value == NULL) { + free(ecp); return SC_ERROR_OUT_OF_MEMORY; - - ecp->der_len = buflen; - - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params paramp=%p %p:%d %d", - ecp, ecp->der, ecp->der_len, ecp->type); - memcpy(ecp->der, buf, buflen); /* copy der parameters */ - } else + } + ecp->der.len = buflen; + memcpy(ecp->der.value, buf, buflen); + } + else { r = 0; + } + ecp->type = r; /* but 0 = ecparams if any, 1=named curve */ *paramp = ecp; - return 0; + return SC_SUCCESS; }; static int asn1_encode_ec_params(sc_context_t *ctx, void *params, -u8 **buf, size_t *buflen, int depth) +u8 **buf, size_t *buflen, int depth) { - struct sc_ec_params * ecp = (struct sc_ec_params *) params; + struct sc_ec_parameters *ecp = (struct sc_ec_parameters *) params; /* Only handle named curves. They may be absent too */ - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_encode_ec_params"); + sc_debug(ctx, SC_LOG_DEBUG_ASN1, "asn1_encode_ec_params() called"); *buf = NULL; *buflen = 0; - if (ecp && ecp->type == 1 && ecp->der) { /* named curve */ - *buf = malloc(ecp->der_len); + if (ecp && ecp->type == 1 && ecp->der.value) { /* named curve */ + *buf = malloc(ecp->der.len); if (*buf == NULL) return SC_ERROR_OUT_OF_MEMORY; - memcpy(*buf, ecp->der, ecp->der_len); - *buflen = ecp->der_len; - } else - sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - Not named curve"); + memcpy(*buf, ecp->der.value, ecp->der.len); + *buflen = ecp->der.len; + } + else { + sc_debug(ctx, SC_LOG_DEBUG_ASN1, "Not named curve"); + } return 0; } @@ -337,10 +337,13 @@ u8 **buf, size_t *buflen, int depth) static void asn1_free_ec_params(void *params) { - struct sc_ec_params * ecp = (struct sc_ec_params *) params; + struct sc_ec_parameters *ecp = (struct sc_ec_parameters *) params; + if (ecp) { - if (ecp->der) - free(ecp->der); + if (ecp->der.value) + free(ecp->der.value); + if (ecp->named_curve) + free(ecp->named_curve); free(ecp); } } @@ -468,52 +471,51 @@ sc_asn1_get_algorithm_info(const struct sc_algorithm_id *id) return NULL; } -static const struct sc_asn1_entry c_asn1_alg_id[6] = { +static const struct sc_asn1_entry c_asn1_alg_id[3] = { { "algorithm", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL }, { "nullParam", SC_ASN1_NULL, SC_ASN1_TAG_NULL, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; int -sc_asn1_decode_algorithm_id(sc_context_t *ctx, const u8 *in, +sc_asn1_decode_algorithm_id(struct sc_context *ctx, const unsigned char *in, size_t len, struct sc_algorithm_id *id, int depth) { - struct sc_asn1_pkcs15_algorithm_info *alg_info; + struct sc_asn1_pkcs15_algorithm_info *alg_info = NULL; struct sc_asn1_entry asn1_alg_id[3]; int r; + LOG_FUNC_CALLED(ctx); sc_copy_asn1_entry(c_asn1_alg_id, asn1_alg_id); sc_format_asn1_entry(asn1_alg_id + 0, &id->oid, NULL, 0); memset(id, 0, sizeof(*id)); r = _sc_asn1_decode(ctx, asn1_alg_id, in, len, &in, &len, 0, depth + 1); - if (r < 0) - return r; + LOG_TEST_RET(ctx, r, "ASN.1 parsing of algo ID failed"); + + sc_log(ctx, "decoded OID '%s'", sc_dump_oid(&(id->oid))); /* See if we understand the algorithm, and if we do, check * whether we know how to decode any additional parameters */ id->algorithm = (unsigned int ) -1; - if ((alg_info = sc_asn1_get_algorithm_info(id)) != NULL) { + alg_info = sc_asn1_get_algorithm_info(id); + if (alg_info != NULL) { id->algorithm = alg_info->id; if (alg_info->decode) { -/* TODO: -DEE why the test for SC_ASN1_PRESENT? - * If it looking for SC_ASN1_NULL, thats valid for EC, in some cases - */ if (asn1_alg_id[1].flags & SC_ASN1_PRESENT) { - sc_debug( ctx,SC_LOG_DEBUG_NORMAL,"SC_ASN1_PRESENT was set, so invalid"); - return SC_ERROR_INVALID_ASN1_OBJECT; + sc_log(ctx, "SC_ASN1_PRESENT was set, so invalid"); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); } r = alg_info->decode(ctx, &id->params, in, len, depth); } } - return r; + LOG_FUNC_RETURN(ctx, r); } int -sc_asn1_encode_algorithm_id(sc_context_t *ctx, - u8 **buf, size_t *len, +sc_asn1_encode_algorithm_id(struct sc_context *ctx, u8 **buf, size_t *len, const struct sc_algorithm_id *id, int depth) { @@ -525,10 +527,12 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, int r; u8 *tmp; + LOG_FUNC_CALLED(ctx); + sc_log(ctx, "type of algorithm to encode: %i", id->algorithm); alg_info = sc_asn1_get_algorithm_info(id); if (alg_info == NULL) { sc_log(ctx, "Cannot encode unknown algorithm %u", id->algorithm); - return SC_ERROR_INVALID_ARGUMENTS; + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); } /* Set the oid if not yet given */ @@ -538,6 +542,7 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, id = &temp_id; } + sc_log(ctx, "encode algo %s", sc_dump_oid(&(id->oid))); sc_copy_asn1_entry(c_asn1_alg_id, asn1_alg_id); sc_format_asn1_entry(asn1_alg_id + 0, (void *) &id->oid, NULL, 1); @@ -546,8 +551,7 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, asn1_alg_id[1].flags |= SC_ASN1_PRESENT; r = _sc_asn1_encode(ctx, asn1_alg_id, buf, len, depth + 1); - if (r < 0) - return r; + LOG_TEST_RET(ctx, r, "ASN.1 encode of algorithm failed"); /* Encode any parameters */ if (id->params && alg_info->encode) { @@ -555,7 +559,7 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, if (r < 0) { if (obj) free(obj); - return r; + LOG_FUNC_RETURN(ctx, r); } } @@ -565,7 +569,7 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, free(*buf); *buf = NULL; free(obj); - return SC_ERROR_OUT_OF_MEMORY; + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } *buf = tmp; memcpy(*buf + *len, obj, obj_len); @@ -574,7 +578,7 @@ sc_asn1_encode_algorithm_id(sc_context_t *ctx, } sc_log(ctx, "return encoded algorithm ID: %s", sc_dump_hex(*buf, *len)); - return 0; + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } void diff --git a/src/libopensc/pkcs15-atrust-acos.c b/src/libopensc/pkcs15-atrust-acos.c index f59539bb..69bdb50e 100644 --- a/src/libopensc/pkcs15-atrust-acos.c +++ b/src/libopensc/pkcs15-atrust-acos.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-cache.c b/src/libopensc/pkcs15-cache.c index 2e18bf9f..66f5fb76 100644 --- a/src/libopensc/pkcs15-cache.c +++ b/src/libopensc/pkcs15-cache.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -112,12 +114,17 @@ int sc_pkcs15_read_cached_file(struct sc_pkcs15_card *p15card, free(data); return SC_ERROR_FILE_NOT_FOUND; } - if (offset) - fseek(f, (long)offset, SEEK_SET); + if (offset) { + if (0 != fseek(f, (long)offset, SEEK_SET)) { + fclose(f); + free(data); + return SC_ERROR_FILE_NOT_FOUND; + } + } if (data) *buf = data; got = fread(*buf, 1, count, f); - fclose(f); + fclose(f); if (got != count) { if (data) free(data); diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c index a930311a..80051b51 100644 --- a/src/libopensc/pkcs15-cert.c +++ b/src/libopensc/pkcs15-cert.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-data.c b/src/libopensc/pkcs15-data.c index e70d6684..800cd60d 100644 --- a/src/libopensc/pkcs15-data.c +++ b/src/libopensc/pkcs15-data.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -60,9 +62,14 @@ sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card, } sc_der_copy(&der, &info->data); + if (!der.value) + LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate memory for der value"); + data_object = calloc(sizeof(struct sc_pkcs15_data), 1); - if (!data_object && !der.value) + if (!data_object) { + free(der.value); LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate memory for data object"); + } data_object->data = der.value; data_object->data_len = der.len; diff --git a/src/libopensc/pkcs15-dnie.c b/src/libopensc/pkcs15-dnie.c index 1a98260d..8be431fe 100644 --- a/src/libopensc/pkcs15-dnie.c +++ b/src/libopensc/pkcs15-dnie.c @@ -21,7 +21,9 @@ #include #include +#if HAVE_CONFIG_H #include "config.h" +#endif #include "libopensc/log.h" #include "libopensc/asn1.h" #include "libopensc/pkcs15.h" @@ -40,11 +42,19 @@ int dump_ef(sc_card_t * card, const char *path, u8 * buf, size_t * buf_len) { int rv; sc_file_t *file = sc_file_new(); - sc_format_path(path, &file->path); - sc_select_file(card, &file->path, &file); - if (file->size > *buf_len) + sc_path_t scpath; + sc_format_path(path, &scpath); + rv = sc_select_file(card, &scpath, &file); + if (rv < 0) { + sc_file_free(file); + return rv; + } + if (file->size > *buf_len) { + sc_file_free(file); return SC_ERROR_BUFFER_TOO_SMALL; + } rv = sc_read_binary(card, 0, buf, file->size, 0); + sc_file_free(file); if (rv < 0) return rv; *buf_len = rv; @@ -100,8 +110,9 @@ int parse_odf(const u8 * buf, size_t buflen, struct sc_pkcs15_card *p15card) }; struct sc_asn1_entry asn1_odf[10]; - sc_path_t *path_prefix = calloc(1, sizeof(sc_path_t)); - sc_format_path("3F005015", path_prefix); + sc_path_t path_prefix; + + sc_format_path("3F005015", &path_prefix); sc_copy_asn1_entry(c_asn1_odf, asn1_odf); for (i = 0; asn1_odf[i].name != NULL; i++) @@ -114,7 +125,7 @@ int parse_odf(const u8 * buf, size_t buflen, struct sc_pkcs15_card *p15card) if (r < 0) return r; type = r; - r = sc_pkcs15_make_absolute_path(path_prefix, &path); + r = sc_pkcs15_make_absolute_path(&path_prefix, &path); if (r < 0) return r; r = sc_pkcs15_add_df(p15card, odf_indexes[type], &path); @@ -131,6 +142,7 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) sc_pkcs15_object_t *p15_obj; size_t len = sizeof(buf); int rv; + struct sc_pkcs15_cert_info *p15_info = NULL; sc_context_t *ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); @@ -220,6 +232,15 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) && (p15_obj->auth_id.len == 0)) { p15_obj->auth_id.value[0] = 0x01; p15_obj->auth_id.len = 1; + }; + /* Set path count to -1 for public certificates, as they + will need to be decompressed and read_binary()'d, so + we make sure we end up reading the file->size and not the + path->count which is the compressed size on newer + DNIe versions */ + if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_CDF) ) { + p15_info = (struct sc_pkcs15_cert_info *) p15_obj ->data; + p15_info ->path.count = -1; } /* Remove found public keys as cannot be read_binary()'d */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) { diff --git a/src/libopensc/pkcs15-esinit.c b/src/libopensc/pkcs15-esinit.c index f551b5bb..cabdb47e 100644 --- a/src/libopensc/pkcs15-esinit.c +++ b/src/libopensc/pkcs15-esinit.c @@ -15,7 +15,9 @@ */ /* Initially written by Weitao Sun (weitao@ftsafe.com) 2008*/ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-esteid.c b/src/libopensc/pkcs15-esteid.c index 6975fe10..3b4062f3 100644 --- a/src/libopensc/pkcs15-esteid.c +++ b/src/libopensc/pkcs15-esteid.c @@ -21,7 +21,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-gemsafeGPK.c b/src/libopensc/pkcs15-gemsafeGPK.c index 551b0a3b..f31d9af2 100644 --- a/src/libopensc/pkcs15-gemsafeGPK.c +++ b/src/libopensc/pkcs15-gemsafeGPK.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-gemsafeV1.c b/src/libopensc/pkcs15-gemsafeV1.c index aa928421..b757b116 100644 --- a/src/libopensc/pkcs15-gemsafeV1.c +++ b/src/libopensc/pkcs15-gemsafeV1.c @@ -17,7 +17,9 @@ /* Initially written by David Mattes */ /* Support for multiple key containers by Lukas Wunner */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -183,11 +185,9 @@ static int gemsafe_get_cert_len(sc_card_t *card) * (allocated EF space is much greater!) */ objlen = (((size_t) ibuf[0]) << 8) | ibuf[1]; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Stored object is of size: %d\n", objlen); + sc_log(card->ctx, "Stored object is of size: %d", objlen); if (objlen < 1 || objlen > GEMSAFE_MAX_OBJLEN) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Invalid object size: %d\n", objlen); + sc_log(card->ctx, "Invalid object size: %d", objlen); return SC_ERROR_INTERNAL; } @@ -209,15 +209,14 @@ static int gemsafe_get_cert_len(sc_card_t *card) while (ibuf[ind] == 0x01) { if (ibuf[ind+1] == 0xFE) { gemsafe_prkeys[i].ref = ibuf[ind+4]; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Key container %d is allocated and uses key_ref %d\n", i+1, - gemsafe_prkeys[i].ref); + sc_log(card->ctx, "Key container %d is allocated and uses key_ref %d", + i+1, gemsafe_prkeys[i].ref); ind += 9; - } else { + } + else { gemsafe_prkeys[i].label = NULL; gemsafe_cert[i].label = NULL; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Key container %d is unallocated\n", i+1); + sc_log(card->ctx, "Key container %d is unallocated", i+1); ind += 8; } i++; @@ -239,8 +238,7 @@ static int gemsafe_get_cert_len(sc_card_t *card) r = sc_read_binary(card, iptr - ibuf, iptr, MIN(GEMSAFE_READ_QUANTUM, objlen - (iptr - ibuf)), 0); if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Could not read cert object\n"); + sc_log(card->ctx, "Could not read cert object"); return SC_ERROR_INTERNAL; } iptr += GEMSAFE_READ_QUANTUM; @@ -254,15 +252,12 @@ static int gemsafe_get_cert_len(sc_card_t *card) while (i < gemsafe_cert_max && gemsafe_cert[i].label == NULL) i++; if (i == gemsafe_cert_max) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Warning: Found orphaned certificate at offset %d\n", ind); + sc_log(card->ctx, "Warning: Found orphaned certificate at offset %d", ind); return SC_SUCCESS; } /* DER cert len is encoded this way */ certlen = ((((size_t) ibuf[ind+2]) << 8) | ibuf[ind+3]) + 4; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Found certificate of key container %d at offset %d, len %d\n", - i+1, ind, certlen); + sc_log(card->ctx, "Found certificate of key container %d at offset %d, len %d", i+1, ind, certlen); gemsafe_cert[i].index = ind; gemsafe_cert[i].count = certlen; ind += certlen; @@ -276,8 +271,7 @@ static int gemsafe_get_cert_len(sc_card_t *card) */ for (; i < gemsafe_cert_max; i++) { if (gemsafe_cert[i].label) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Warning: Certificate of key container %d is missing\n", i+1); + sc_log(card->ctx, "Warning: Certificate of key container %d is missing", i+1); gemsafe_prkeys[i].label = NULL; gemsafe_cert[i].label = NULL; } @@ -304,7 +298,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting pkcs15 parameters\n"); + sc_log(p15card->card->ctx, "Setting pkcs15 parameters"); if (p15card->tokeninfo->label) free(p15card->tokeninfo->label); @@ -330,7 +324,8 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) 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"); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return SC_ERROR_INTERNAL; if (r != SC_SUCCESS) @@ -350,7 +345,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) return SC_ERROR_INTERNAL; /* set certs */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting certificates\n"); + sc_log(p15card->card->ctx, "Setting certificates"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; @@ -367,7 +362,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } /* set gemsafe_pin */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting PIN\n"); + sc_log(p15card->card->ctx, "Setting PIN"); for (i=0; i < gemsafe_pin_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; @@ -388,11 +383,11 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) }; /* set private keys */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting private keys\n"); + sc_log(p15card->card->ctx, "Setting private keys"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id, authId, *pauthId; struct sc_path path; - int key_ref = 0x03; + int key_ref = 0x03; if (gemsafe_prkeys[i].label == NULL) continue; @@ -403,7 +398,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } else pauthId = NULL; sc_format_path(gemsafe_prkeys[i].path, &path); - /* + /* * The key ref may be different for different sites; * by adding flags=n where the low order 4 bits can be * the key ref we can force it. @@ -423,7 +418,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } /* select the application DF */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,"Selecting application DF\n"); + sc_log(p15card->card->ctx, "Selecting application DF"); sc_format_path(GEMSAFE_APP_PATH, &path); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS || !file) @@ -511,8 +506,7 @@ sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type, df_type = SC_PKCS15_CDF; break; default: - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, - "Unknown PKCS15 object type %d\n", type); + sc_log(p15card->card->ctx, "Unknown PKCS15 object type %d", type); free(obj); return SC_ERROR_INVALID_ARGUMENTS; } @@ -534,6 +528,9 @@ sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card, sc_pkcs15_auth_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + info->auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; info->auth_method = SC_AC_CHV; info->auth_id = *id; @@ -549,9 +546,7 @@ sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card, if (path) info->path = *path; - return sc_pkcs15emu_add_object(p15card, - SC_PKCS15_TYPE_AUTH_PIN, - label, info, NULL, obj_flags); + return sc_pkcs15emu_add_object(p15card, SC_PKCS15_TYPE_AUTH_PIN, label, info, NULL, obj_flags); } static int @@ -563,6 +558,10 @@ sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card, { sc_pkcs15_cert_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + { + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + } info->id = *id; info->authority = authority; if (path) @@ -582,6 +581,10 @@ sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + { + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + } info->id = *id; info->modulus_length = modulus_length; info->usage = usage; diff --git a/src/libopensc/pkcs15-infocamere.c b/src/libopensc/pkcs15-infocamere.c index 1504d40d..208036da 100644 --- a/src/libopensc/pkcs15-infocamere.c +++ b/src/libopensc/pkcs15-infocamere.c @@ -21,7 +21,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -117,10 +119,6 @@ static int sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card, info.modulus_length = modulus_length; info.usage = usage; info.native = 1; - info.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE - | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE - | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE - | SC_PKCS15_PRKEY_ACCESS_LOCAL; info.key_reference = ref; if (path) @@ -244,6 +242,8 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) if (r != SC_SUCCESS || file->size > 255) { /* Not EF.GDO */ + if (file) + sc_file_free(file); return SC_ERROR_WRONG_CARD; } @@ -251,6 +251,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) if (ef_gdo[0] != 0x5A || file->size < 3) { /* Not EF.GDO */ + sc_file_free(file); return SC_ERROR_WRONG_CARD; } @@ -262,8 +263,10 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) if (file->size < (size_t) (len_iccsn + 5)) { /* Not CHN */ + sc_file_free(file); return SC_ERROR_WRONG_CARD; } + sc_file_free(file); if (! (ef_gdo[len_iccsn + 2] == 0x5F diff --git a/src/libopensc/pkcs15-itacns.c b/src/libopensc/pkcs15-itacns.c index 0977af9d..55e9f31b 100644 --- a/src/libopensc/pkcs15-itacns.c +++ b/src/libopensc/pkcs15-itacns.c @@ -319,11 +319,6 @@ static int itacns_add_prkey(sc_pkcs15_card_t *p15card, info.usage = usage; info.native = 1; info.key_reference = ref; - info.access_flags = - SC_PKCS15_PRKEY_ACCESS_SENSITIVE - | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE - | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE - | SC_PKCS15_PRKEY_ACCESS_LOCAL; if (path) info.path = *path; @@ -504,6 +499,8 @@ static int itacns_add_data_files(sc_pkcs15_card_t *p15card) sizeof(obj.label)); data.path = path; rv = sc_pkcs15emu_add_data_object(p15card, &obj, &data); + SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, rv, + "Could not add data file"); } /* diff --git a/src/libopensc/pkcs15-oberthur.c b/src/libopensc/pkcs15-oberthur.c index bbdd14fd..db849930 100644 --- a/src/libopensc/pkcs15-oberthur.c +++ b/src/libopensc/pkcs15-oberthur.c @@ -800,10 +800,6 @@ sc_pkcs15emu_oberthur_add_prvkey(struct sc_pkcs15_card *p15card, kinfo.modulus_length = size; kinfo.native = 1; - kinfo.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE - | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE - | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE - | SC_PKCS15_PRKEY_ACCESS_LOCAL; kinfo.key_reference = file_id & 0xFF; kinfo.usage = sc_oberthur_decode_usage(flags); diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c index 4cc1c39b..69442050 100644 --- a/src/libopensc/pkcs15-openpgp.c +++ b/src/libopensc/pkcs15-openpgp.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index 9ae07405..6f0239bd 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -498,15 +500,10 @@ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card, if (!puk_info) { sc_log(ctx, "Unable to get puk object, using pin object instead!"); puk_info = auth_info; - - /* make sure the puk is in valid range */ - r = _validate_pin(p15card, puk_info, puklen); - LOG_TEST_RET(ctx, r, "PIN do not conforms PIN policy"); - } - else { - r = sc_pkcs15_verify_pin(p15card, puk_obj, puk, puklen); - LOG_TEST_RET(ctx, r, "cannot verify PUK"); } + /* make sure the puk is in valid range */ + r = _validate_pin(p15card, puk_info, puklen); + LOG_TEST_RET(ctx, r, "PIN do not conforms PIN policy"); r = sc_lock(card); LOG_TEST_RET(ctx, r, "sc_lock() failed"); diff --git a/src/libopensc/pkcs15-piv.c b/src/libopensc/pkcs15-piv.c index 7f465987..549a91b9 100644 --- a/src/libopensc/pkcs15-piv.c +++ b/src/libopensc/pkcs15-piv.c @@ -24,7 +24,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -735,11 +737,13 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) ckis[i].cert_found = 1; /* cache it using the PKCS15 emulation objects */ /* as it does not change */ - if (cert_der.value) { - cert_info.value.value = cert_der.value; - cert_info.value.len = cert_der.len; - cert_info.path.len = 0; /* use in mem cert from now on */ - } + if (cert_der.value) { + cert_info.value.value = cert_der.value; + cert_info.value.len = cert_der.len; + if (!p15card->opts.use_file_cache) { + cert_info.path.len = 0; /* use in mem cert from now on */ + } + } /* following will find the cached cert in cert_info */ r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out); if (r < 0 || cert_out->key == NULL) { diff --git a/src/libopensc/pkcs15-postecert.c b/src/libopensc/pkcs15-postecert.c index 8d40e031..6842bda4 100644 --- a/src/libopensc/pkcs15-postecert.c +++ b/src/libopensc/pkcs15-postecert.c @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -112,10 +114,6 @@ static int sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card, info.modulus_length = modulus_length; info.usage = usage; info.native = 1; - info.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE - | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE - | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE - | SC_PKCS15_PRKEY_ACCESS_LOCAL; info.key_reference = ref; if (path) @@ -225,7 +223,7 @@ static int sc_pkcs15emu_postecert_init(sc_pkcs15_card_t * p15card) count_cert[o] = (*(certi + i + 2) << 8) + *(certi + i + 3) + 4; o++; - if (o > 4) + if (o >= 4) break; i += (*(certi + i + 2) << 8) + *(certi + i + 3); } diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index 7b8a6af3..a7f2c84a 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -681,6 +683,7 @@ sc_pkcs15_convert_prkey(struct sc_pkcs15_prkey *pkcs15_key, void *evp_key) assert(EC_KEY_get0_public_key(src)); pkcs15_key->algorithm = SC_ALGORITHM_EC; + if (!sc_pkcs15_convert_bignum(&dst->privateD, EC_KEY_get0_private_key(src))) return SC_ERROR_INCOMPATIBLE_KEY; @@ -696,17 +699,33 @@ sc_pkcs15_convert_prkey(struct sc_pkcs15_prkey *pkcs15_key, void *evp_key) /* Decode EC_POINT from a octet string */ buflen = EC_POINT_point2oct(grp, (const EC_POINT *) EC_KEY_get0_public_key(src), POINT_CONVERSION_UNCOMPRESSED, buf, buflen, NULL); + if (!buflen) + return SC_ERROR_INCOMPATIBLE_KEY; /* copy the public key */ - if (buflen > 0) { - dst->ecpointQ.value = malloc(buflen); - memcpy(dst->ecpointQ.value, buf, buflen); - dst->ecpointQ.len = buflen; - /* calculate the field length */ - dst->params.field_length = (buflen - 1) / 2 * 8; - } - else { - return SC_ERROR_INCOMPATIBLE_KEY; + dst->ecpointQ.value = malloc(buflen); + memcpy(dst->ecpointQ.value, buf, buflen); + dst->ecpointQ.len = buflen; + + /* + * In OpenSC the field_length is in bits. Not all curves are a mutiple of 8. + * EC_POINT_point2oct handles this and returns octstrings that can handle + * these curves. Get real field_length from OpenSSL. + */ + dst->params.field_length = EC_GROUP_get_degree(grp); + + /* Octetstring may need leading zeros if BN is to short */ + if (dst->privateD.len < (dst->params.field_length + 7) / 8) { + size_t d = (dst->params.field_length + 7) / 8 - dst->privateD.len; + + dst->privateD.data = realloc(dst->privateD.data, dst->privateD.len + d); + if (!dst->privateD.data) + return SC_ERROR_OUT_OF_MEMORY; + + memmove(dst->privateD.data + d, dst->privateD.data, dst->privateD.len); + memset(dst->privateD.data, 0, d); + + dst->privateD.len += d; } break; diff --git a/src/libopensc/pkcs15-pteid.c b/src/libopensc/pkcs15-pteid.c index 028ef27d..da9c0887 100644 --- a/src/libopensc/pkcs15-pteid.c +++ b/src/libopensc/pkcs15-pteid.c @@ -35,7 +35,9 @@ * */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 4afd3bbf..294c3125 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -75,7 +77,7 @@ static const struct sc_asn1_entry c_asn1_rsakey_value_choice[C_ASN1_RSAKEY_VALUE #define C_ASN1_RSAKEY_ATTR_SIZE 4 static const struct sc_asn1_entry c_asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE] = { - { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, + { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, { "modulusLength", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, { "keyInfo", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } @@ -90,9 +92,7 @@ static const struct sc_asn1_entry c_asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_C #define C_ASN1_ECKEY_ATTR_SIZE 3 static const struct sc_asn1_entry c_asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE] = { - { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, - /* VTA: 'fieldSize' is not in PKCS#15 specification */ - /* { "fieldSize", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, */ + { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, { "keyInfo", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; @@ -270,8 +270,6 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, sc_format_asn1_entry(asn1_eckey_value_choice + 1, &der->value, &der->len, 0); sc_format_asn1_entry(asn1_eckey_attr + 0, asn1_eckey_value_choice, NULL, 0); - /* VTA: TODO 'fieldSize' is not in PKCS#15 specification */ - /* sc_format_asn1_entry(asn1_eckey_attr + 1, &info.field_length, NULL, 0); */ sc_format_asn1_entry(asn1_dsa_type_attr + 0, asn1_dsakey_attr, NULL, 0); @@ -339,8 +337,8 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, sc_log(ctx, "PubKey path '%s'", sc_print_path(&info.path)); /* OpenSC 0.11.4 and older encoded "keyReference" as a negative - value. Fixed in 0.11.5 we need to add a hack, so old cards - continue to work. */ + value. Fixed in 0.11.5 we need to add a hack, so old cards + continue to work. */ if (info.key_reference < -1) info.key_reference += 256; @@ -491,8 +489,6 @@ sc_pkcs15_encode_pukdf_entry(struct sc_context *ctx, const struct sc_pkcs15_obje } sc_format_asn1_entry(asn1_eckey_attr + 0, asn1_eckey_value_choice, NULL, 1); - /* VTA: TODO 'fieldSize' is not in PKCS#15 specification */ - /* sc_format_asn1_entry(asn1_eckey_attr + 1, &pubkey->field_length, NULL, 1); */ break; default: @@ -727,6 +723,11 @@ sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx, key->ecpointQ.len = ecpoint_len; key->ecpointQ.value = ecpoint_data; + /* + * Only get here if raw point is stored in pkcs15 without curve name + * spki has the curvename, so we can get the field_length + * Following only true for curves that are multiple of 8 + */ key->params.field_length = (ecpoint_len - 1)/2 * 8; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -771,7 +772,7 @@ sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, static const struct sc_asn1_entry c_asn1_spki_key_items[] = { { "algorithm", SC_ASN1_ALGORITHM_ID, SC_ASN1_CONS| SC_ASN1_TAG_SEQUENCE, 0, NULL, NULL}, - { "key", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, + { "key", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; @@ -787,7 +788,7 @@ int sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubkey, u8 **buf, size_t *len) { - int r; + int r = 0; struct sc_asn1_entry asn1_spki_key[2], asn1_spki_key_items[3]; struct sc_pkcs15_u8 pkey; size_t key_len; @@ -816,9 +817,26 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk key_len = pubkey->u.ec.ecpointQ.len * 8; pkey.value = pubkey->u.ec.ecpointQ.value; pkey.len = 0; /* flag as do not delete */ - /* TODO make sure algorithm params are available*/ - /* if not can we copy them from the u.ec */ - r = 0; + + if (pubkey->u.ec.params.named_curve || pubkey->u.ec.params.der.value) { + struct sc_ec_parameters *ec_params = NULL; + + r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); + LOG_TEST_RET(ctx, r, "failed to fix EC parameters"); + + ec_params = calloc(1, sizeof(struct sc_ec_parameters)); + if (!ec_params) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + ec_params->type = 1; + ec_params->der.value = calloc(pubkey->u.ec.params.der.len, 1); + if (!ec_params->der.value) { + free(ec_params); + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + } + memcpy(ec_params->der.value, pubkey->u.ec.params.der.value, pubkey->u.ec.params.der.len); + ec_params->der.len = pubkey->u.ec.params.der.len; + pubkey->alg_id->params = ec_params; + } break; case SC_ALGORITHM_GOSTR3410: /* TODO is this needed? does it cause mem leak? */ @@ -915,18 +933,18 @@ sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_obj if (info->direct.spki.value && info->direct.spki.len) { sc_log(ctx, "Using direct SPKI value, tag 0x%X", *(info->direct.spki.value)); r = sc_pkcs15_pubkey_from_spki_sequence(ctx, info->direct.spki.value, info->direct.spki.len, &pubkey); - LOG_TEST_RET(ctx, r, "Failed to decode 'SPKI' direct value"); + LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode 'SPKI' direct value"); } else if (info->direct.raw.value && info->direct.raw.len) { sc_log(ctx, "Using direct RAW value"); r = sc_pkcs15_decode_pubkey(ctx, pubkey, info->direct.raw.value, info->direct.raw.len); - LOG_TEST_RET(ctx, r, "Failed to decode 'RAW' direct value"); + LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode 'RAW' direct value"); sc_log(ctx, "TODO: for EC keys 'raw' data needs to be completed with referenced algorithm from TokenInfo"); } else if (obj->content.value && obj->content.len) { sc_log(ctx, "Using object content"); r = sc_pkcs15_decode_pubkey(ctx, pubkey, obj->content.value, obj->content.len); - LOG_TEST_RET(ctx, r, "Failed to decode object content value"); + LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode object content value"); sc_log(ctx, "TODO: for EC keys 'raw' data needs to be completed with referenced algorithm from TokenInfo"); } else if (p15card->card->ops->read_public_key) { @@ -934,28 +952,34 @@ sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_obj r = p15card->card->ops->read_public_key(p15card->card, algorithm, (struct sc_path *)&info->path, info->key_reference, info->modulus_length, &data, &len); - LOG_TEST_RET(ctx, r, "Card specific 'read-public' procedure failed."); + LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'read-public' procedure failed."); r = sc_pkcs15_decode_pubkey(ctx, pubkey, data, len); - LOG_TEST_RET(ctx, r, "Decode public key error"); + LOG_TEST_GOTO_ERR(ctx, r, "Decode public key error"); } else if (info->path.len) { sc_log(ctx, "Read from EF and decode"); r = sc_pkcs15_read_file(p15card, &info->path, &data, &len); - LOG_TEST_RET(ctx, r, "Failed to read public key file."); + LOG_TEST_GOTO_ERR(ctx, r, "Failed to read public key file."); if (algorithm == SC_ALGORITHM_EC && *data == (SC_ASN1_TAG_SEQUENCE | SC_ASN1_TAG_CONSTRUCTED)) r = sc_pkcs15_pubkey_from_spki_sequence(ctx, data, len, &pubkey); else r = sc_pkcs15_decode_pubkey(ctx, pubkey, data, len); - LOG_TEST_RET(ctx, r, "Decode public key error"); + LOG_TEST_GOTO_ERR(ctx, r, "Decode public key error"); } else { - LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "No way to get public key"); + r = SC_ERROR_NOT_IMPLEMENTED; + LOG_TEST_GOTO_ERR(ctx, r, "No way to get public key"); } - *out = pubkey; - LOG_FUNC_RETURN(ctx, SC_SUCCESS); +err: + if (r) + sc_pkcs15_free_pubkey(pubkey); + else + *out = pubkey; + + LOG_FUNC_RETURN(ctx, r); } @@ -1010,12 +1034,14 @@ sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prv break; case SC_ALGORITHM_EC: pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len); + if (!pubkey->u.ec.ecpointQ.value) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len); pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len; break; default: sc_log(ctx, "Unsupported private key algorithm"); - return SC_ERROR_NOT_SUPPORTED; + rv = SC_ERROR_NOT_SUPPORTED; } if (rv) @@ -1227,9 +1253,7 @@ sc_pkcs15_read_der_file(sc_context_t *ctx, char * filename, rbuf = NULL; r = rbuflen; out: - if (rbuf) - free(rbuf); - if (f > 0) + if (f >= 0) close(f); LOG_FUNC_RETURN(ctx, r); @@ -1251,7 +1275,7 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke unsigned char *tmp_buf = NULL; int r; - sc_log(ctx, "sc_pkcs15_pubkey_from_spki_fields %p:%d %s", buf, buflen, sc_dump_hex(buf, buflen)); + sc_log(ctx, "sc_pkcs15_pubkey_from_spki_fields() called: %p:%d\n%s", buf, buflen, sc_dump_hex(buf, buflen)); tmp_buf = malloc(buflen); if (!tmp_buf) @@ -1265,6 +1289,7 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke pubkey = calloc(1, sizeof(sc_pkcs15_pubkey_t)); if (pubkey == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + *outpubkey = pubkey; sc_copy_asn1_entry(c_asn1_pkinfo, asn1_pkinfo); @@ -1287,19 +1312,25 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke if (pk_alg.algorithm == SC_ALGORITHM_EC) { /* EC public key is not encapsulated into BIT STRING -- it's a BIT STRING */ - if (pubkey->alg_id->params) { - struct sc_ec_params *ecp = (struct sc_ec_params *)pubkey->alg_id->params; + /* + * sc_pkcs15_fix_ec_parameters below will set field_length from curve. + * if no alg_id->params, assume field_length is multiple of 8 + */ + pubkey->u.ec.params.field_length = (pk.len - 1) / 2 * 8; - pubkey->u.ec.params.der.value = malloc(ecp->der_len); + if (pubkey->alg_id->params) { + struct sc_ec_parameters *ecp = (struct sc_ec_parameters *)pubkey->alg_id->params; + + pubkey->u.ec.params.der.value = malloc(ecp->der.len); if (pubkey->u.ec.params.der.value == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - memcpy(pubkey->u.ec.params.der.value, ecp->der, ecp->der_len); - pubkey->u.ec.params.der.len = ecp->der_len; - sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); + memcpy(pubkey->u.ec.params.der.value, ecp->der.value, ecp->der.len); + pubkey->u.ec.params.der.len = ecp->der.len; + r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); + LOG_TEST_RET(ctx, r, "failed to fix EC parameters"); } - pubkey->u.ec.params.field_length = (pk.len - 1)/2 * 8; pubkey->u.ec.ecpointQ.value = malloc(pk.len); if (pubkey->u.ec.ecpointQ.value == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); @@ -1317,48 +1348,50 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke if (tmp_buf) free(tmp_buf); - *outpubkey = pubkey; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } int -sc_pkcs15_pubkey_from_spki_sequence(sc_context_t *ctx, const u8 *buf, size_t buflen, - sc_pkcs15_pubkey_t ** outpubkey) +sc_pkcs15_pubkey_from_spki_sequence(struct sc_context *ctx, const unsigned char *buf, size_t buflen, + struct sc_pkcs15_pubkey ** outpubkey) { - int r; - sc_pkcs15_pubkey_t * pubkey = NULL; + struct sc_pkcs15_pubkey * pubkey = NULL; struct sc_asn1_entry asn1_spki[] = { { "subjectPublicKeyInfo", SC_ASN1_CALLBACK, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, sc_pkcs15_pubkey_from_spki_fields, &pubkey}, { NULL, 0, 0, 0, NULL, NULL } }; + int r; - *outpubkey = NULL; + LOG_FUNC_CALLED(ctx); r = sc_asn1_decode(ctx, asn1_spki, buf, buflen, NULL, NULL); + LOG_TEST_RET(ctx, r, "ASN.1 cannot parse subjectPublicKeyInfo"); - *outpubkey = pubkey; - return r; + if(outpubkey) + *outpubkey = pubkey; + + LOG_FUNC_RETURN(ctx, r); } int -sc_pkcs15_pubkey_from_spki_file(sc_context_t *ctx, char * filename, - sc_pkcs15_pubkey_t ** outpubkey) +sc_pkcs15_pubkey_from_spki_file(struct sc_context *ctx, char * filename, + struct sc_pkcs15_pubkey ** outpubkey) { int r; u8 * buf = NULL; size_t buflen = 0; + LOG_FUNC_CALLED(ctx); + r = sc_pkcs15_read_der_file(ctx, filename, &buf, &buflen); - if (r < 0) - return r; + LOG_TEST_RET(ctx, r, "Cannot read SPKI DER file"); r = sc_pkcs15_pubkey_from_spki_sequence(ctx, buf, buflen, outpubkey); - if (buf) free(buf); - return r; + LOG_FUNC_RETURN(ctx, r); } @@ -1369,18 +1402,31 @@ static struct ec_curve_info { size_t size; } ec_curve_infos[] = { {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"prime192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, + {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, + {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, + + {"secp224r1", "1.3.132.0.33", "06052b81040021", 224}, + {"nistp224", "1.3.132.0.33", "06052b81040021", 224}, + {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, + {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, + {"nistp256", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, + {"secp384r1", "1.3.132.0.34", "06052B81040022", 384}, {"prime384v1", "1.3.132.0.34", "06052B81040022", 384}, + {"nistp384", "1.3.132.0.34", "06052B81040022", 384}, {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384}, + + {"secp521r1", "1.3.132.0.35", "06052B81040023", 521}, + {"nistp521", "1.3.132.0.35", "06052B81040023", 521}, + {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192}, {"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}, + {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192}, {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256}, {NULL, NULL, NULL, 0}, @@ -1388,7 +1434,7 @@ static struct ec_curve_info { int -sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_pkcs15_ec_parameters *ecparams) +sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecparams) { int rv, ii; @@ -1438,8 +1484,10 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_pkcs15_ec_paramete if (!strcmp(ec_curve_infos[ii].oid_str, ecparams->named_curve)) break; } - if (!ec_curve_infos[ii].name) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported named curve"); + if (!ec_curve_infos[ii].name) { + sc_log(ctx, "Named curve '%s' not supported", ecparams->named_curve); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } rv = sc_format_oid(&ecparams->id, ec_curve_infos[ii].oid_str); LOG_TEST_RET(ctx, rv, "Invalid OID format"); @@ -1557,6 +1605,8 @@ sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key) /* copy the public key */ if (buflen > 0) { dst->ecpointQ.value = malloc(buflen); + if (!dst->ecpointQ.value) + return SC_ERROR_OUT_OF_MEMORY; memcpy(dst->ecpointQ.value, buf, buflen); dst->ecpointQ.len = buflen; /* calculate the field length */ diff --git a/src/libopensc/pkcs15-sc-hsm.c b/src/libopensc/pkcs15-sc-hsm.c index 0266637d..40411095 100644 --- a/src/libopensc/pkcs15-sc-hsm.c +++ b/src/libopensc/pkcs15-sc-hsm.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -374,7 +376,7 @@ static int sc_pkcs15emu_sc_hsm_get_rsa_public_key(struct sc_context *ctx, sc_cvc static int sc_pkcs15emu_sc_hsm_get_ec_public_key(struct sc_context *ctx, sc_cvc_t *cvc, struct sc_pkcs15_pubkey *pubkey) { - struct sc_ec_params *ecp; + struct sc_ec_parameters *ecp; const struct sc_lv_data *oid; int r; @@ -384,18 +386,18 @@ static int sc_pkcs15emu_sc_hsm_get_ec_public_key(struct sc_context *ctx, sc_cvc_ if (r != SC_SUCCESS) return r; - ecp = calloc(1, sizeof(struct sc_ec_params)); + ecp = calloc(1, sizeof(struct sc_ec_parameters)); if (!ecp) return SC_ERROR_OUT_OF_MEMORY; - ecp->der_len = oid->len + 2; - ecp->der = calloc(ecp->der_len, 1); - if (!ecp->der) + ecp->der.len = oid->len + 2; + ecp->der.value = calloc(ecp->der.len, 1); + if (!ecp->der.value) return SC_ERROR_OUT_OF_MEMORY; - ecp->der[0] = 0x06; - ecp->der[1] = (u8)oid->len; - memcpy(ecp->der + 2, oid->value, oid->len); + *(ecp->der.value + 0) = 0x06; + *(ecp->der.value + 1) = (u8)oid->len; + memcpy(ecp->der.value + 2, oid->value, oid->len); ecp->type = 1; // Named curve pubkey->alg_id = (struct sc_algorithm_id *)calloc(1, sizeof(struct sc_algorithm_id)); @@ -411,11 +413,11 @@ static int sc_pkcs15emu_sc_hsm_get_ec_public_key(struct sc_context *ctx, sc_cvc_ memcpy(pubkey->u.ec.ecpointQ.value, cvc->publicPoint, cvc->publicPointlen); pubkey->u.ec.ecpointQ.len = cvc->publicPointlen; - pubkey->u.ec.params.der.value = malloc(ecp->der_len); + pubkey->u.ec.params.der.value = malloc(ecp->der.len); if (!pubkey->u.ec.params.der.value) return SC_ERROR_OUT_OF_MEMORY; - memcpy(pubkey->u.ec.params.der.value, ecp->der, ecp->der_len); - pubkey->u.ec.params.der.len = ecp->der_len; + memcpy(pubkey->u.ec.params.der.value, ecp->der.value, ecp->der.len); + pubkey->u.ec.params.der.len = ecp->der.len; sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); @@ -426,7 +428,7 @@ static int sc_pkcs15emu_sc_hsm_get_ec_public_key(struct sc_context *ctx, sc_cvc_ int sc_pkcs15emu_sc_hsm_get_public_key(struct sc_context *ctx, sc_cvc_t *cvc, struct sc_pkcs15_pubkey *pubkey) { - if (cvc->publicPoint || cvc->publicPointlen) { + if (cvc->publicPoint && cvc->publicPointlen) { return sc_pkcs15emu_sc_hsm_get_ec_public_key(ctx, cvc, pubkey); } else { return sc_pkcs15emu_sc_hsm_get_rsa_public_key(ctx, cvc, pubkey); @@ -504,9 +506,12 @@ static int sc_pkcs15emu_sc_hsm_add_pubkey(sc_pkcs15_card_t *p15card, sc_pkcs15_p memset(&pubkey_info, 0, sizeof(pubkey_info)); memset(&pubkey_obj, 0, sizeof(pubkey_obj)); - sc_pkcs15_encode_pubkey(ctx, &pubkey, &pubkey_obj.content.value, &pubkey_obj.content.len); - sc_pkcs15_encode_pubkey(ctx, &pubkey, &pubkey_info.direct.raw.value, &pubkey_info.direct.raw.len); - sc_pkcs15_encode_pubkey_as_spki(ctx, &pubkey, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); + r = sc_pkcs15_encode_pubkey(ctx, &pubkey, &pubkey_obj.content.value, &pubkey_obj.content.len); + LOG_TEST_RET(ctx, r, "Could not encode public key"); + r = sc_pkcs15_encode_pubkey(ctx, &pubkey, &pubkey_info.direct.raw.value, &pubkey_info.direct.raw.len); + LOG_TEST_RET(ctx, r, "Could not encode public key"); + r = sc_pkcs15_encode_pubkey_as_spki(ctx, &pubkey, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); + LOG_TEST_RET(ctx, r, "Could not encode public key"); pubkey_info.id = key_info->id; strlcpy(pubkey_obj.label, label, sizeof(pubkey_obj.label)); @@ -515,6 +520,7 @@ static int sc_pkcs15emu_sc_hsm_add_pubkey(sc_pkcs15_card_t *p15card, sc_pkcs15_p pubkey_info.modulus_length = pubkey.u.rsa.modulus.len << 3; r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); } else { + /* TODO fix if support of non multiple of 8 curves are added */ pubkey_info.field_length = cvc.primeOrModuluslen << 3; r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); } diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index e6ebafe0..df78f604 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -212,14 +214,14 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_EC: - alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length); + alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL); if (alg_info == NULL) { sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } - if (out == NULL || *poutlen < (prkey->field_length +7) / 8) { - *poutlen = (prkey->field_length +7) / 8; + if (out == NULL || *poutlen < (prkey->field_length + 7) / 8) { + *poutlen = (prkey->field_length + 7) / 8; r = 0; /* say no data to return */ goto out; } @@ -352,7 +354,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, case SC_PKCS15_TYPE_PRKEY_EC: modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */ - alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length); + alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL); if (alg_info == NULL) { sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); diff --git a/src/libopensc/pkcs15-starcert.c b/src/libopensc/pkcs15-starcert.c index 19faefc8..96e0b8ac 100644 --- a/src/libopensc/pkcs15-starcert.c +++ b/src/libopensc/pkcs15-starcert.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index d2c086c0..b886366f 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -204,15 +206,13 @@ sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card) free(blocks); } - /* Total failure */ - LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD); - -out: if (r == SC_SUCCESS) { +out: + if (r == SC_SUCCESS) { p15card->magic = SC_PKCS15_CARD_MAGIC; p15card->flags |= SC_PKCS15_CARD_FLAG_EMULATED; - } - else if (r != SC_ERROR_WRONG_CARD) { - sc_log(ctx, "Failed to load card emulator: %s", sc_strerror(r)); + } else { + if (r != SC_ERROR_WRONG_CARD) + sc_log(ctx, "Failed to load card emulator: %s", sc_strerror(r)); } LOG_FUNC_RETURN(ctx, r); @@ -227,7 +227,7 @@ static int parse_emu_block(sc_pkcs15_card_t *p15card, scconf_block *conf) void *handle = NULL; int (*init_func)(sc_pkcs15_card_t *); int (*init_func_ex)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); - int r, force = 0; + int r; const char *driver, *module_name; driver = conf->name->data; @@ -237,8 +237,6 @@ static int parse_emu_block(sc_pkcs15_card_t *p15card, scconf_block *conf) memset(&opts, 0, sizeof(opts)); opts.blk = conf; - if (force != 0) - opts.flags = SC_PKCS15EMU_FLAGS_NO_CHECK; module_name = scconf_get_str(conf, "module", builtin_name); if (!strcmp(module_name, "builtin")) { @@ -272,10 +270,15 @@ static int parse_emu_block(sc_pkcs15_card_t *p15card, scconf_block *conf) /* try to get version of the driver/api */ get_version = (const char *(*)(void)) sc_dlsym(handle, "sc_driver_version"); if (get_version) { - sscanf(get_version(), "%u.%u.%u", &major, &minor, &fix); + if (3 != sscanf(get_version(), "%u.%u.%u", &major, &minor, &fix)) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, + "unable to get modules version number\n"); + sc_dlclose(handle); + return SC_ERROR_INTERNAL; + } } - if (!get_version || (major == 0 && minor <= 9 && fix < 3) < 0) { + if (!get_version || (major == 0 && minor <= 9 && fix < 3)) { /* no sc_driver_version function => assume old style * init function (note: this should later give an error */ diff --git a/src/libopensc/pkcs15-tccardos.c b/src/libopensc/pkcs15-tccardos.c index 42103987..1715752d 100644 --- a/src/libopensc/pkcs15-tccardos.c +++ b/src/libopensc/pkcs15-tccardos.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/pkcs15-tcos.c b/src/libopensc/pkcs15-tcos.c index 4c98518e..29712888 100644 --- a/src/libopensc/pkcs15-tcos.c +++ b/src/libopensc/pkcs15-tcos.c @@ -18,13 +18,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include #include #include "common/compat_strlcpy.h" +#include "common/compat_strlcat.h" #include "internal.h" #include "pkcs15.h" #include "cardctl.h" @@ -260,8 +263,9 @@ static int insert_pin( static char *dirpath(char *dir, const char *path){ static char buf[SC_MAX_PATH_STRING_SIZE]; - strcpy(buf,dir); - return strcat(buf,path); + strlcpy(buf,dir,sizeof buf); + strlcat(buf,path,sizeof buf); + return buf; } static int detect_netkey( diff --git a/src/libopensc/pkcs15-westcos.c b/src/libopensc/pkcs15-westcos.c index 8bd4d645..7974fe62 100644 --- a/src/libopensc/pkcs15-westcos.c +++ b/src/libopensc/pkcs15-westcos.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -70,7 +72,7 @@ static int sc_pkcs15emu_westcos_init(sc_pkcs15_card_t * p15card) } else { - for (i = 0; i < 1; i++) { + for (i = 0; i <= 1; i++) { unsigned int flags; struct sc_pkcs15_auth_info pin_info; struct sc_pkcs15_object pin_obj; diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index 5219ae5b..ba9d6125 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -911,14 +911,19 @@ sc_dup_app_info(const struct sc_app_info *info) if (info->label) { out->label = strdup(info->label); - if (!out->label) + if (!out->label) { + free(out); return NULL; + } } else out->label = NULL; out->ddo.value = malloc(info->ddo.len); - if (!out->ddo.value) + if (!out->ddo.value) { + free(out->label); + free(out); return NULL; + } memcpy(out->ddo.value, info->ddo.value, info->ddo.len); return out; @@ -957,6 +962,7 @@ sc_pkcs15_get_application_by_type(struct sc_card * card, char *app_type) char *type = (char *)scconf_get_str(blocks[0], "type", app_type); if (!strcmp(type, app_type)) { out = app_info; + free(blocks); break; } } @@ -968,7 +974,7 @@ sc_pkcs15_get_application_by_type(struct sc_card * card, char *app_type) } -static int +int sc_pkcs15_bind_internal(struct sc_pkcs15_card *p15card, struct sc_aid *aid) { struct sc_path tmppath; @@ -1310,8 +1316,8 @@ __sc_pkcs15_search_objects(struct sc_pkcs15_card *p15card, unsigned int class_ma continue; /* Enumerate the DF's, so p15card->obj_list is * populated. */ - /* FIXME dont ignore errors */ - sc_pkcs15_parse_df(p15card, df); + if (SC_SUCCESS != sc_pkcs15_parse_df(p15card, df)) + continue; } /* And now loop over all objects */ @@ -2696,7 +2702,7 @@ sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15 struct sc_serial_number serialnr; struct sc_pkcs15_id id; unsigned char guid_bin[SC_PKCS15_MAX_ID_SIZE + SC_MAX_SERIALNR]; - int rv; + int rv, guid_bin_size; LOG_FUNC_CALLED(ctx); if(!out || !out_size) @@ -2724,29 +2730,57 @@ sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15 rv = sc_pkcs15_get_object_id(obj, &id); LOG_TEST_RET(ctx, rv, "Cannot get object's ID"); - rv = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serialnr); - LOG_TEST_RET(ctx, rv, "'GET_SERIALNR' failed"); + if (p15card->tokeninfo && p15card->tokeninfo->serial_number) { + /* The serial from EF(TokenInfo) is preferred because of the + * "--serial" parameter of pkcs15-init. */ + serialnr.len = SC_MAX_SERIALNR; + rv = sc_hex_to_bin(p15card->tokeninfo->serial_number, serialnr.value, &serialnr.len); + if (rv) { + /* Fallback in case hex_to_bin fails due to unexpected characters */ + serialnr.len = strlen(p15card->tokeninfo->serial_number); + if (serialnr.len > SC_MAX_SERIALNR) + serialnr.len = SC_MAX_SERIALNR; + + memcpy(serialnr.value, p15card->tokeninfo->serial_number, serialnr.len); + } + } else if (p15card->card->serialnr.len) { + serialnr = p15card->card->serialnr; + } else { + rv = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serialnr); + LOG_TEST_RET(ctx, rv, "'GET_SERIALNR' CTL failed and other serial numbers not present"); + } memset(guid_bin, 0, sizeof(guid_bin)); memcpy(guid_bin, id.value, id.len); memcpy(guid_bin + id.len, serialnr.value, serialnr.len); + guid_bin_size = id.len + serialnr.len; - // If OpenSSL is available (SHA1), then rather use the hash of the data - // - this also protects against data being too short + /* + * If OpenSSL is available (SHA1), then rather use the hash of the data + * - this also protects against data being too short + */ #ifdef ENABLE_OPENSSL - SHA1(guid_bin, id.len + serialnr.len, guid_bin); - id.len = SHA_DIGEST_LENGTH; - serialnr.len = 0; + SHA1(guid_bin, guid_bin_size, guid_bin); + guid_bin_size = SHA_DIGEST_LENGTH; +#else + /* If guid_bin has a size larger than 16 bytes + * force the remaining bytes up to 16 bytes to be zero + * so sc_pkcs15_serialize_guid won't fail because the size is less than 16 + */ + if (guid_bin_size < 16) + guid_bin_size = 16; #endif - rv = sc_pkcs15_serialize_guid(guid_bin, id.len + serialnr.len, flags, (char *)out, *out_size); + rv = sc_pkcs15_serialize_guid(guid_bin, guid_bin_size, flags, (char *)out, *out_size); LOG_TEST_RET(ctx, rv, "Serialize GUID error"); *out_size = strlen((char *)out); LOG_FUNC_RETURN(ctx, rv); } -void sc_pkcs15_free_key_params(struct sc_pkcs15_key_params *params) + +void +sc_pkcs15_free_key_params(struct sc_pkcs15_key_params *params) { if (!params) return; diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 629902ce..1ceb9eb8 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -200,19 +200,6 @@ struct sc_pkcs15_prkey_dsa { sc_pkcs15_bignum_t priv; }; -/* - * The ecParameters can be presented as - * - named curve; - * - OID of named curve; - * - implicit parameters. - */ -struct sc_pkcs15_ec_parameters { - char *named_curve; - struct sc_object_id id; - struct sc_pkcs15_der der; - size_t field_length; /* in bits */ -}; - struct sc_pkcs15_gost_parameters { struct sc_object_id key; struct sc_object_id hash; @@ -220,12 +207,12 @@ struct sc_pkcs15_gost_parameters { }; struct sc_pkcs15_pubkey_ec { - struct sc_pkcs15_ec_parameters params; + struct sc_ec_parameters params; struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */ }; struct sc_pkcs15_prkey_ec { - struct sc_pkcs15_ec_parameters params; + struct sc_ec_parameters params; sc_pkcs15_bignum_t privateD; /* note this is bignum */ struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */ }; @@ -681,6 +668,7 @@ int sc_pkcs15_bind(struct sc_card *card, struct sc_aid *aid, /* sc_pkcs15_unbind: Releases a PKCS #15 card object, and frees any * memory allocations done on the card object. */ int sc_pkcs15_unbind(struct sc_pkcs15_card *card); +int sc_pkcs15_bind_internal(struct sc_pkcs15_card *p15card, struct sc_aid *aid); int sc_pkcs15_get_objects(struct sc_pkcs15_card *card, unsigned int type, struct sc_pkcs15_object **ret, size_t ret_count); @@ -964,7 +952,7 @@ struct sc_supported_algo_info *sc_pkcs15_get_supported_algo(struct sc_pkcs15_car int sc_pkcs15_add_supported_algo_ref(struct sc_pkcs15_object *, struct sc_supported_algo_info *); -int sc_pkcs15_fix_ec_parameters(struct sc_context *, struct sc_pkcs15_ec_parameters *); +int sc_pkcs15_fix_ec_parameters(struct sc_context *, struct sc_ec_parameters *); /* Convert the OpenSSL key data type into the OpenSC key */ int sc_pkcs15_convert_bignum(sc_pkcs15_bignum_t *dst, const void *bignum); diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index a3d0cce1..9fa1f98e 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_CTAPI #include @@ -114,6 +116,9 @@ static int refresh_attributes(sc_reader_t *reader) u8 cmd[5], rbuf[256], sad, dad; unsigned short lr; + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_STATUS; cmd[2] = CTBCS_P1_CT_KERNEL; @@ -156,7 +161,10 @@ static int ctapi_internal_transmit(sc_reader_t *reader, u8 dad, sad; unsigned short lr; char rv; - + + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + if (control) dad = 1; else @@ -164,14 +172,14 @@ static int ctapi_internal_transmit(sc_reader_t *reader, sad = 2; lr = *recvsize; - + rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, (unsigned short)sendsize, (u8 *) sendbuf, &lr, recvbuf); if (rv != 0) { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Error transmitting APDU: %d\n", rv); return SC_ERROR_TRANSMIT_FAILED; } *recvsize = lr; - + return 0; } @@ -211,14 +219,14 @@ out: sc_mem_clear(rbuf, rbuflen); free(rbuf); } - + return r; } static int ctapi_detect_card_presence(sc_reader_t *reader) { int r; - + r = refresh_attributes(reader); if (r) return r; @@ -233,6 +241,9 @@ static int ctapi_connect(sc_reader_t *reader) unsigned short lr; int r; + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_REQUEST; cmd[2] = CTBCS_P1_INTERFACE1; @@ -278,7 +289,9 @@ static int ctapi_release(sc_reader_t *reader) { struct ctapi_private_data *priv = GET_PRIV_DATA(reader); - priv->funcs.CT_close(priv->ctn); + + if (!(reader->ctx->flags & SC_CTX_FLAG_TERMINATE)) + priv->funcs.CT_close(priv->ctn); free(priv); return 0; @@ -290,7 +303,7 @@ static struct sc_reader_driver ctapi_drv = { "CT-API module", "ctapi", &ctapi_ops, - 0, 0, NULL + NULL }; static struct ctapi_module * add_module(struct ctapi_global_private_data *gpriv, @@ -304,7 +317,7 @@ static struct ctapi_module * add_module(struct ctapi_global_private_data *gpriv, gpriv->modules[i].dlhandle = dlhandle; gpriv->modules[i].ctn_count = 0; gpriv->module_count++; - + return &gpriv->modules[i]; } @@ -321,8 +334,8 @@ static int ctapi_load_module(sc_context_t *ctx, u8 cmd[5], rbuf[256], sad, dad; unsigned short lr; - - + + list = scconf_find_list(conf, "ports"); if (list == NULL) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "No ports configured.\n"); @@ -353,7 +366,7 @@ static int ctapi_load_module(sc_context_t *ctx, char rv; sc_reader_t *reader; struct ctapi_private_data *priv; - + if (sscanf(list->data, "%d", &port) != 1) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Port '%s' is not a number.\n", list->data); continue; @@ -363,7 +376,7 @@ static int ctapi_load_module(sc_context_t *ctx, sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "CT_init() failed with %d\n", rv); continue; } - + reader = calloc(1, sizeof(sc_reader_t)); priv = calloc(1, sizeof(struct ctapi_private_data)); if (!priv || !reader) { @@ -386,9 +399,9 @@ static int ctapi_load_module(sc_context_t *ctx, free(reader); break; } - - /* Detect functional units of the reader according to CT-BCS spec version 1.0 - (14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */ + + /* Detect functional units of the reader according to CT-BCS spec version 1.0 + (14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */ cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_STATUS; cmd[2] = CTBCS_P1_CT_KERNEL; @@ -397,7 +410,7 @@ static int ctapi_load_module(sc_context_t *ctx, dad = 1; sad = 2; lr = 256; - + rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Error getting status of terminal: %d, using defaults\n", rv); @@ -470,7 +483,7 @@ static int ctapi_load_module(sc_context_t *ctx, if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY) reader->capabilities |= SC_READER_CAP_DISPLAY; } - + ctapi_reset(reader); refresh_attributes(reader); mod->ctn_count++; @@ -492,7 +505,7 @@ static int ctapi_init(sc_context_t *ctx) if (gpriv == NULL) return SC_ERROR_OUT_OF_MEMORY; ctx->reader_drv_data = gpriv; - + for (i = 0; ctx->conf_blocks[i] != NULL; i++) { blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "reader_driver", "ctapi"); @@ -508,7 +521,7 @@ static int ctapi_init(sc_context_t *ctx) for (i = 0; blocks != NULL && blocks[i] != NULL; i++) ctapi_load_module(ctx, gpriv, blocks[i]); free(blocks); - + return 0; } @@ -518,10 +531,10 @@ static int ctapi_finish(sc_context_t *ctx) if (priv) { int i; - + for (i = 0; i < priv->module_count; i++) { struct ctapi_module *mod = &priv->modules[i]; - + free(mod->name); sc_dlclose(mod->dlhandle); } @@ -529,7 +542,7 @@ static int ctapi_finish(sc_context_t *ctx) free(priv->modules); free(priv); } - + return 0; } @@ -548,7 +561,7 @@ struct sc_reader_driver * sc_get_ctapi_driver(void) ctapi_ops.perform_verify = ctbcs_pin_cmd; ctapi_ops.perform_pace = NULL; ctapi_ops.use_reader = NULL; - + return &ctapi_drv; } #endif diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index c127306e..d2038a2b 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -4,7 +4,9 @@ * Copyright (C) 2003 Olaf Kirch */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_OPENCT /* empty file without openct */ #include @@ -44,7 +46,7 @@ static struct sc_reader_driver openct_reader_driver = { "OpenCT reader", "openct", &openct_ops, - 0, 0, NULL + NULL }; /* private data structures */ @@ -117,7 +119,7 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info) reader->drv_data = data; reader->name = strdup(data->info.ct_name); - if ((rc = _sc_add_reader(ctx, reader)) < 0) { + if ((rc = _sc_add_reader(ctx, reader)) < 0) { free(data); free(reader->name); free(reader); @@ -152,13 +154,13 @@ static int openct_reader_release(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); if (data) { - if (data->h) + if (data->h && !(reader->ctx->flags & SC_CTX_FLAG_TERMINATE)) ct_reader_disconnect(data->h); sc_mem_clear(data, sizeof(*data)); reader->drv_data = NULL; free(data); } - + return SC_SUCCESS; } @@ -172,6 +174,9 @@ static int openct_reader_detect_card_presence(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + reader->flags = 0; if (!data->h && !(data->h = ct_reader_connect(data->num))) return 0; @@ -195,6 +200,9 @@ openct_reader_connect(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + if (data->h) ct_reader_disconnect(data->h); @@ -240,7 +248,7 @@ static int openct_reader_disconnect(sc_reader_t *reader) struct driver_data *data = (struct driver_data *) reader->drv_data; SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); - if (data->h) + if (data->h && !(reader->flags & SC_TERMINATE)) ct_reader_disconnect(data->h); data->h = NULL; return SC_SUCCESS; @@ -254,6 +262,9 @@ openct_reader_internal_transmit(sc_reader_t *reader, struct driver_data *data = (struct driver_data *) reader->drv_data; int rc; + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + /* Hotplug check */ if ((rc = openct_reader_reconnect(reader)) < 0) return rc; @@ -310,7 +321,7 @@ out: sc_mem_clear(rbuf, rbuflen); free(rbuf); } - + return r; } @@ -322,6 +333,9 @@ static int openct_reader_perform_verify(sc_reader_t *reader, struct sc_pin_cmd_d u8 buf[254]; int rc; + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + /* Hotplug check */ if ((rc = openct_reader_reconnect(reader)) < 0) return rc; @@ -380,6 +394,9 @@ static int openct_reader_lock(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + /* Hotplug check */ if ((rc = openct_reader_reconnect(reader)) < 0) return rc; @@ -406,6 +423,9 @@ static int openct_reader_unlock(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + /* Not connected */ if (data->h == NULL) return 0; diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index b6a33c7a..b850db20 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #ifdef ENABLE_PCSC /* empty file without pcsc */ #include @@ -182,6 +184,9 @@ static int pcsc_internal_transmit(sc_reader_t *reader, SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL); card = priv->pcsc_card; + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + sSendPci.dwProtocol = opensc_proto_to_pcsc(reader->active_protocol); sSendPci.cbPciLength = sizeof(sSendPci); sRecvPci.dwProtocol = opensc_proto_to_pcsc(reader->active_protocol); @@ -282,6 +287,9 @@ static int refresh_attributes(sc_reader_t *reader) sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "%s check", reader->name); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + if (priv->reader_state.szReader == NULL) { priv->reader_state.szReader = reader->name; priv->reader_state.dwCurrentState = SCARD_STATE_UNAWARE; @@ -503,7 +511,8 @@ static int pcsc_disconnect(sc_reader_t * reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL); - priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->disconnect_action); + if (!(reader->ctx->flags & SC_CTX_FLAG_TERMINATE)) + priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->disconnect_action); reader->flags = 0; return SC_SUCCESS; } @@ -516,6 +525,9 @@ static int pcsc_lock(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + rv = priv->gpriv->SCardBeginTransaction(priv->pcsc_card); switch (rv) { @@ -553,6 +565,9 @@ static int pcsc_unlock(sc_reader_t *reader) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + rv = priv->gpriv->SCardEndTransaction(priv->pcsc_card, priv->gpriv->transaction_end_action); priv->locked = 0; @@ -595,12 +610,18 @@ static int pcsc_cancel(sc_context_t *ctx) struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *)ctx->reader_drv_data; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); + + if (ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + #ifndef _WIN32 if (gpriv->pcsc_wait_ctx != -1) { rv = gpriv->SCardCancel(gpriv->pcsc_wait_ctx); - if (rv == SCARD_S_SUCCESS) + if (rv == SCARD_S_SUCCESS) { /* Also close and clear the waiting context */ rv = gpriv->SCardReleaseContext(gpriv->pcsc_wait_ctx); + gpriv->pcsc_wait_ctx = -1; + } } #else rv = gpriv->SCardCancel(gpriv->pcsc_ctx); @@ -618,7 +639,7 @@ static struct sc_reader_driver pcsc_drv = { "PC/SC reader", "pcsc", &pcsc_ops, - 0, 0, NULL + NULL }; static int pcsc_init(sc_context_t *ctx) @@ -745,7 +766,7 @@ static int pcsc_finish(sc_context_t *ctx) SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (gpriv) { - if (gpriv->pcsc_ctx != -1) + if (gpriv->pcsc_ctx != -1 && !(ctx->flags & SC_CTX_FLAG_TERMINATE)) gpriv->SCardReleaseContext(gpriv->pcsc_ctx); if (gpriv->dlhandle != NULL) sc_dlclose(gpriv->dlhandle); @@ -762,15 +783,15 @@ static int pcsc_finish(sc_context_t *ctx) * * @return Bitmask of \c SC_READER_CAP_PACE_GENERIC, \c SC_READER_CAP_PACE_EID and \c * SC_READER_CAP_PACE_ESIGN logically OR'ed if supported */ -static unsigned long part10_detect_pace_capabilities(sc_reader_t *reader) +static unsigned long part10_detect_pace_capabilities(sc_reader_t *reader, SCARDHANDLE card_handle) { u8 pace_capabilities_buf[] = { PACE_FUNCTION_GetReaderPACECapabilities, /* idxFunction */ 0, 0, /* lengthInputData */ }; - u8 rbuf[6]; + u8 rbuf[7]; u8 *p = rbuf; - size_t rcount = sizeof rbuf; + DWORD rcount = sizeof rbuf; struct pcsc_private_data *priv; unsigned long flags = 0; @@ -780,10 +801,15 @@ static unsigned long part10_detect_pace_capabilities(sc_reader_t *reader) if (!priv) goto err; - if (priv->pace_ioctl) { - pcsc_internal_transmit(reader, pace_capabilities_buf, - sizeof pace_capabilities_buf, rbuf, &rcount, - priv->pace_ioctl); + if (priv->pace_ioctl && priv->gpriv) { + if (SCARD_S_SUCCESS != priv->gpriv->SCardControl(card_handle, + priv->pace_ioctl, pace_capabilities_buf, + sizeof pace_capabilities_buf, rbuf, sizeof(rbuf), + &rcount)) { + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, + "PC/SC v2 part 10 amd1: Get PACE properties failed!"); + goto err; + } if (rcount != 7) goto err; @@ -810,6 +836,50 @@ err: return flags; } +static int +part10_find_property_by_tag(unsigned char buffer[], int length, + int tag_searched); +/** + * @brief Detects reader's maximum data size + * + * @param reader reader to probe (\c get_tlv_properties must be initialized) + * + * @return maximum data size + */ +static size_t part10_detect_max_data(sc_reader_t *reader, SCARDHANDLE card_handle) +{ + u8 rbuf[256]; + DWORD rcount = sizeof rbuf; + struct pcsc_private_data *priv; + /* 0 means no limitations */ + size_t max_data = 0; + int r; + + if (!reader) + goto err; + priv = GET_PRIV_DATA(reader); + if (!priv) + goto err; + + if (priv->get_tlv_properties && priv->gpriv) { + if (SCARD_S_SUCCESS != priv->gpriv->SCardControl(card_handle, + priv->get_tlv_properties, NULL, 0, rbuf, sizeof(rbuf), + &rcount)) { + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, + "PC/SC v2 part 10: Get TLV properties failed!"); + goto err; + } + + r = part10_find_property_by_tag(rbuf, rcount, + PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize); + if (r >= 0) + max_data = r; + } + +err: + return max_data; +} + static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) { sc_context_t *ctx = reader->ctx; struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data; @@ -925,7 +995,7 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) if (priv->pace_ioctl) { const char *log_text = "Reader supports PACE"; if (priv->gpriv->enable_pace) { - reader->capabilities |= part10_detect_pace_capabilities(reader); + reader->capabilities |= part10_detect_pace_capabilities(reader, card_handle); if (reader->capabilities & SC_READER_CAP_PACE_GENERIC) sc_log(ctx, log_text); @@ -933,6 +1003,12 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) sc_log(ctx, "%s %s", log_text, log_disabled); } } + + /* Set reader max_send_size and max_recv_size based on detected max_data */ + if (priv->get_tlv_properties) { + reader->max_send_size = part10_detect_max_data(reader, card_handle); + reader->max_recv_size = reader->max_send_size; + } } static int pcsc_detect_readers(sc_context_t *ctx) @@ -944,6 +1020,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) char *reader_buf = NULL, *reader_name; const char *mszGroups = NULL; int ret = SC_ERROR_INTERNAL; + size_t i; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); @@ -953,7 +1030,13 @@ static int pcsc_detect_readers(sc_context_t *ctx) goto out; } - sc_log(ctx, "Probing pcsc readers"); + /* 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 { if (gpriv->pcsc_ctx == -1) { @@ -967,6 +1050,13 @@ static int pcsc_detect_readers(sc_context_t *ctx) else { rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, NULL, NULL, (LPDWORD) &reader_buf_size); + if (rv == SCARD_E_NO_SERVICE) { + gpriv->SCardReleaseContext(gpriv->pcsc_ctx); + gpriv->pcsc_ctx = -1; + gpriv->pcsc_wait_ctx = -1; + /* reconnecting below may may restart PC/SC service */ + rv = SCARD_E_INVALID_HANDLE; + } } if (rv != SCARD_S_SUCCESS) { if (rv != (LONG)SCARD_E_INVALID_HANDLE) { @@ -975,7 +1065,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) goto out; } - sc_log(ctx, "Establish pcsc context"); + sc_log(ctx, "Establish PC/SC context"); rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_ctx); @@ -1002,28 +1092,28 @@ static int pcsc_detect_readers(sc_context_t *ctx) goto out; } for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen(reader_name) + 1) { - sc_reader_t *reader = NULL; + sc_reader_t *reader = NULL, *old_reader; struct pcsc_private_data *priv = NULL; - unsigned int i; int found = 0; for (i=0;i < sc_ctx_get_reader_count(ctx) && !found;i++) { - sc_reader_t *reader2 = sc_ctx_get_reader(ctx, i); - if (reader2 == NULL) { + old_reader = sc_ctx_get_reader(ctx, i); + if (old_reader == NULL) { ret = SC_ERROR_INTERNAL; goto err1; } - if (!strcmp(reader2->name, reader_name)) { + if (!strcmp(old_reader->name, reader_name)) { found = 1; } } /* Reader already available, skip */ if (found) { + old_reader->flags &= ~SC_READER_REMOVED; continue; } - sc_log(ctx, "Found new pcsc reader '%s'", reader_name); + sc_log(ctx, "Found new PC/SC reader '%s'", reader_name); if ((reader = calloc(1, sizeof(sc_reader_t))) == NULL) { ret = SC_ERROR_OUT_OF_MEMORY; @@ -1490,8 +1580,8 @@ static int part10_build_modify_pin_block(struct sc_reader *reader, u8 * buf, siz /* Ignore language and T=1 parameters. */ pin_modify->wLangId = HOST_TO_CCID_16(0x0000); - pin_modify->bMsgIndex1 = 0x00; /* Default message indexes */ - pin_modify->bMsgIndex2 = 0x01; + pin_modify->bMsgIndex1 = (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0x01: 0x00); /* Default message indexes */ + pin_modify->bMsgIndex2 = (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0x02: 0x01); pin_modify->bMsgIndex3 = 0x02; pin_modify->bTeoPrologue[0] = 0x00; pin_modify->bTeoPrologue[1] = 0x00; @@ -1622,6 +1712,9 @@ pcsc_pin_cmd(sc_reader_t *reader, struct sc_pin_cmd_data *data) SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL); + if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) + return SC_ERROR_NOT_ALLOWED; + if (priv->gpriv->SCardControl == NULL) return SC_ERROR_NOT_SUPPORTED; @@ -1797,7 +1890,7 @@ static int transform_pace_output(u8 *rbuf, size_t rbuflen, if (parsed+2 > rbuflen) return SC_ERROR_UNKNOWN_DATA_RECEIVED; pace_output->mse_set_at_sw1 = rbuf[parsed+0]; - pace_output->mse_set_at_sw1 = rbuf[parsed+1]; + pace_output->mse_set_at_sw2 = rbuf[parsed+1]; parsed += 2; /* length_CardAccess */ @@ -1911,8 +2004,8 @@ static int transform_pace_output(u8 *rbuf, size_t rbuflen, static int pcsc_perform_pace(struct sc_reader *reader, void *input_pace, void *output_pace) { - struct establish_pace_channel_input *pace_input = (struct establish_pace_channel_input *) input_pace; - struct establish_pace_channel_output *pace_output = (struct establish_pace_channel_output *) output_pace; + struct establish_pace_channel_input *pace_input = (struct establish_pace_channel_input *) input_pace; + struct establish_pace_channel_output *pace_output = (struct establish_pace_channel_output *) output_pace; struct pcsc_private_data *priv; u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE], sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; size_t rcount = sizeof rbuf, scount = sizeof sbuf; @@ -2000,7 +2093,7 @@ static struct sc_reader_driver cardmod_drv = { "PC/SC cardmod reader", "cardmod", &cardmod_ops, - 0, 0, NULL + NULL }; static int cardmod_init(sc_context_t *ctx) diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 1cc03109..5cddd32e 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -47,7 +49,7 @@ const char *sc_get_version(void) int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen) { - int err = 0; + int err = SC_SUCCESS; size_t left, count = 0; assert(in != NULL && out != NULL && outlen != NULL); @@ -108,7 +110,7 @@ int sc_bin_to_hex(const u8 *in, size_t in_len, char *out, size_t out_len, pos += 2; } *pos = '\0'; - return 0; + return SC_SUCCESS; } /* @@ -116,7 +118,7 @@ int sc_bin_to_hex(const u8 *in, size_t in_len, char *out, size_t out_len, */ size_t sc_right_trim(u8 *buf, size_t len) { - size_t i; + long i; for(i=len-1; i >=0; i--) { if(!isprint(buf[i])) { @@ -274,17 +276,18 @@ void sc_format_path(const char *str, sc_path_t *path) { int type = SC_PATH_TYPE_PATH; - memset(path, 0, sizeof(*path)); - if (*str == 'i' || *str == 'I') { - type = SC_PATH_TYPE_FILE_ID; - str++; + if (path) { + memset(path, 0, sizeof(*path)); + if (*str == 'i' || *str == 'I') { + type = SC_PATH_TYPE_FILE_ID; + str++; + } + path->len = sizeof(path->value); + if (sc_hex_to_bin(str, path->value, &path->len) >= 0) { + path->type = type; + } + path->count = -1; } - path->len = sizeof(path->value); - if (sc_hex_to_bin(str, path->value, &path->len) >= 0) { - path->type = type; - } - path->count = -1; - return; } int sc_append_path(sc_path_t *dest, const sc_path_t *src) @@ -298,7 +301,7 @@ int sc_append_path_id(sc_path_t *dest, const u8 *id, size_t idlen) return SC_ERROR_INVALID_ARGUMENTS; memcpy(dest->value + dest->len, id, idlen); dest->len += idlen; - return 0; + return SC_SUCCESS; } int sc_append_file_id(sc_path_t *dest, unsigned int fid) @@ -416,21 +419,21 @@ int sc_file_add_acl_entry(sc_file_t *file, unsigned int operation, case SC_AC_NEVER: sc_file_clear_acl_entries(file, operation); file->acl[operation] = (sc_acl_entry_t *) 1; - return 0; + return SC_SUCCESS; case SC_AC_NONE: sc_file_clear_acl_entries(file, operation); file->acl[operation] = (sc_acl_entry_t *) 2; - return 0; + return SC_SUCCESS; case SC_AC_UNKNOWN: sc_file_clear_acl_entries(file, operation); file->acl[operation] = (sc_acl_entry_t *) 3; - return 0; + return SC_SUCCESS; default: /* NONE and UNKNOWN get zapped when a new AC is added. * If the ACL is NEVER, additional entries will be * dropped silently. */ if (file->acl[operation] == (sc_acl_entry_t *) 1) - return 0; + return SC_SUCCESS; if (file->acl[operation] == (sc_acl_entry_t *) 2 || file->acl[operation] == (sc_acl_entry_t *) 3) file->acl[operation] = NULL; @@ -440,7 +443,7 @@ int sc_file_add_acl_entry(sc_file_t *file, unsigned int operation, * of the card's AC with OpenSC's), don't add it again. */ for (p = file->acl[operation]; p != NULL; p = p->next) { if ((p->method == method) && (p->key_ref == key_ref)) - return 0; + return SC_SUCCESS; } _new = malloc(sizeof(sc_acl_entry_t)); @@ -453,13 +456,13 @@ int sc_file_add_acl_entry(sc_file_t *file, unsigned int operation, p = file->acl[operation]; if (p == NULL) { file->acl[operation] = _new; - return 0; + return SC_SUCCESS; } while (p->next != NULL) p = p->next; p->next = _new; - return 0; + return SC_SUCCESS; } const sc_acl_entry_t * sc_file_get_acl_entry(const sc_file_t *file, @@ -628,7 +631,7 @@ int sc_file_set_prop_attr(sc_file_t *file, const u8 *prop_attr, free(file->prop_attr); file->prop_attr = NULL; file->prop_attr_len = 0; - return 0; + return SC_SUCCESS; } tmp = (u8 *) realloc(file->prop_attr, prop_attr_len); if (!tmp) { @@ -642,7 +645,7 @@ int sc_file_set_prop_attr(sc_file_t *file, const u8 *prop_attr, memcpy(file->prop_attr, prop_attr, prop_attr_len); file->prop_attr_len = prop_attr_len; - return 0; + return SC_SUCCESS; } int sc_file_set_type_attr(sc_file_t *file, const u8 *type_attr, @@ -656,7 +659,7 @@ int sc_file_set_type_attr(sc_file_t *file, const u8 *type_attr, free(file->type_attr); file->type_attr = NULL; file->type_attr_len = 0; - return 0; + return SC_SUCCESS; } tmp = (u8 *) realloc(file->type_attr, type_attr_len); if (!tmp) { @@ -670,7 +673,7 @@ int sc_file_set_type_attr(sc_file_t *file, const u8 *type_attr, memcpy(file->type_attr, type_attr, type_attr_len); file->type_attr_len = type_attr_len; - return 0; + return SC_SUCCESS; } @@ -780,12 +783,12 @@ int _sc_parse_atr(sc_reader_t *reader) } } if (atr_len <= 0) - return 0; + return SC_SUCCESS; if (n_hist > atr_len) n_hist = atr_len; reader->atr_info.hist_bytes_len = n_hist; reader->atr_info.hist_bytes = p; - return 0; + return SC_SUCCESS; } void *sc_mem_alloc_secure(sc_context_t *ctx, size_t len) @@ -803,7 +806,7 @@ void *sc_mem_alloc_secure(sc_context_t *ctx, size_t len) locked = 1; #endif if (!locked) { - if (ctx->paranoid_memory) { + 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; @@ -839,7 +842,7 @@ int sc_mem_reverse(unsigned char *buf, size_t len) *(buf + len - 1 - ii) = ch; } - return 0; + return SC_SUCCESS; } static int diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c index 1244e857..140c562a 100644 --- a/src/libopensc/sec.c +++ b/src/libopensc/sec.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/src/libopensc/sm.c b/src/libopensc/sm.c index 5f4bd899..44cdfa48 100644 --- a/src/libopensc/sm.c +++ b/src/libopensc/sm.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if HAVE_CONFIG_H #include "config.h" +#endif #include #include @@ -140,6 +142,9 @@ sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) * Send plain APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, apdu); LOG_FUNC_RETURN(ctx, rv); + } else { + if (rv < 0) + sc_sm_stop(card); } LOG_TEST_RET(ctx, rv, "get SM APDU error"); @@ -147,34 +152,66 @@ sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) rv = sc_check_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + sc_sm_stop(card); LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU"); } /* send APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, sm_apdu); - LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); + if (rv < 0) { + card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + sc_sm_stop(card); + LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); + } /* decode SM answer and free temporary SM related data */ rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + if (rv < 0) + sc_sm_stop(card); LOG_FUNC_RETURN(ctx, rv); } + +int +sc_sm_stop(struct sc_card *card) +{ + int r = SC_SUCCESS; + + if (card) { + if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT + && card->sm_ctx.ops.close) + r = card->sm_ctx.ops.close(card); + card->sm_ctx.sm_mode = SM_MODE_NONE; + } + + return r; +} + #else + int sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len, struct sm_card_response *out) { return SC_ERROR_NOT_SUPPORTED; } + int sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len, int ref_rv, struct sc_apdu *apdu) { return SC_ERROR_NOT_SUPPORTED; } + int sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) { return SC_ERROR_NOT_SUPPORTED; } + +int +sc_sm_stop(struct sc_card *card) +{ + return SC_ERROR_NOT_SUPPORTED; +} #endif diff --git a/src/libopensc/sm.h b/src/libopensc/sm.h index 8ff19887..e27725f4 100644 --- a/src/libopensc/sm.h +++ b/src/libopensc/sm.h @@ -353,6 +353,18 @@ int sc_sm_parse_answer(struct sc_card *, unsigned char *, size_t, struct sm_card int sc_sm_update_apdu_response(struct sc_card *, unsigned char *, size_t, int, struct sc_apdu *); int sc_sm_single_transmit(struct sc_card *, struct sc_apdu *); +/** + * @brief Stops SM and frees allocated ressources. + * + * Calls \a card->sm_ctx.ops.close() if available and \c card->sm_ctx.sm_mode + * is \c SM_MODE_TRANSMIT + * + * @param[in] card + * + * @return \c SC_SUCCESS or error code if an error occurred + */ +int sc_sm_stop(struct sc_card *card); + #ifdef __cplusplus } #endif diff --git a/src/libopensc/types.h b/src/libopensc/types.h index 0bf0c29b..38f4c4bf 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -225,7 +225,8 @@ typedef struct sc_file { unsigned int type, ef_structure, status; /* See constant values defined above */ unsigned int shareable; /* true(1), false(0) according to ISO 7816-4:2005 Table 14 */ size_t size; /* Size of file (in bytes) */ - int id; /* Short file id (2 bytes) */ + int id; /* file identifier (2 bytes) */ + int sid; /* short EF identifier (1 byte) */ struct sc_acl_entry *acl[SC_MAX_AC_OPS]; /* Access Control List */ int record_length; /* In case of fixed-length or cyclic EF */ diff --git a/src/libopensc/user-interface.c b/src/libopensc/user-interface.c index f88aee0f..dd3c7c09 100644 --- a/src/libopensc/user-interface.c +++ b/src/libopensc/user-interface.c @@ -29,13 +29,19 @@ #include "config.h" #endif +#ifdef ENABLE_OPENSSL /* empty file without openssl */ + #include #include #include #include #ifdef _WIN32 + +#ifndef UNICODE #define UNICODE +#endif + #include #endif #ifdef __APPLE__ @@ -314,4 +320,6 @@ do_error: LOG_FUNC_RETURN(card->ctx, res); } -#endif +#endif /* ENABLE_DNIE_UI */ + +#endif /* ENABLE_OPENSSL */ diff --git a/src/libsm/sm-common.c b/src/libsm/sm-common.c index cb500b4e..87d5907f 100644 --- a/src/libsm/sm-common.c +++ b/src/libsm/sm-common.c @@ -332,8 +332,10 @@ sm_encrypt_des_cbc3(struct sc_context *ctx, unsigned char *key, *out_len = data_len; *out = malloc(data_len + 8); - if (*out == NULL) + if (*out == NULL) { + free(data); LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "SM encrypt_des_cbc3: failure"); + } memcpy(&kk, key, 8); memcpy(&k2, key + 8, 8); diff --git a/src/minidriver/minidriver-italian-cns.reg b/src/minidriver/minidriver-italian-cns.reg new file mode 100644 index 00000000..3bca8d4a --- /dev/null +++ b/src/minidriver/minidriver-italian-cns.reg @@ -0,0 +1,33 @@ +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 diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c index a7f3dbe7..2d228960 100644 --- a/src/minidriver/minidriver.c +++ b/src/minidriver/minidriver.c @@ -1,7 +1,8 @@ -/* +/* * minidriver.c: OpenSC minidriver * * Copyright (C) 2009,2010 francois.leblanc@cev-sa.com + * Copyright (C) 2015 vincent.letoux@mysmartlogon.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -56,6 +57,9 @@ #include "cardmod-mingw-compat.h" #endif +/* store the instance given at DllMain when attached to access internal resources */ +HINSTANCE g_inst; + #define MD_MINIMUM_VERSION_SUPPORTED 4 #define MD_CURRENT_VERSION_SUPPORTED 7 @@ -100,6 +104,15 @@ #define SCARD_F_UNKNOWN_ERROR 0x80100014L #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 + +/* magic to determine previous pinpad authentication */ +#define MAGIC_SESSION_PIN "opensc-minidriver" + struct md_directory { unsigned char parent[9]; unsigned char name[9]; @@ -129,7 +142,7 @@ struct md_pkcs15_container { struct sc_pkcs15_id id; char guid[MAX_CONTAINER_NAME_LEN + 1]; unsigned flags; - unsigned size_key_exchange, size_sign; + size_t size_key_exchange, size_sign; struct sc_pkcs15_object *cert_obj, *prkey_obj, *pubkey_obj; }; @@ -205,7 +218,7 @@ static DWORD md_get_cardcf(PCARD_DATA pCardData, CARD_CACHE_FILE_FORMAT **out); static DWORD md_pkcs15_delete_object(PCARD_DATA pCardData, struct sc_pkcs15_object *obj); static DWORD md_fs_init(PCARD_DATA pCardData); -static void logprintf(PCARD_DATA pCardData, int level, const char* format, ...) +static void logprintf(PCARD_DATA pCardData, int level, _Printf_format_string_ const char* format, ...) { va_list arg; VENDOR_SPECIFIC *vs; @@ -250,7 +263,7 @@ static void logprintf(PCARD_DATA pCardData, int level, const char* format, ...) va_end(arg); } -static void loghex(PCARD_DATA pCardData, int level, PBYTE data, int len) +static void loghex(PCARD_DATA pCardData, int level, PBYTE data, size_t len) { char line[74]; char *c; @@ -286,14 +299,14 @@ static void loghex(PCARD_DATA pCardData, int level, PBYTE data, int len) logprintf(pCardData, level, " %04X %s\n", a, line); } -static void print_werror(PCARD_DATA pCardData, char *str) +static void print_werror(PCARD_DATA pCardData, PSTR str) { void *buf; - FormatMessage( + FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), 0, (LPTSTR) &buf, 0, NULL); + NULL, GetLastError(), 0, (LPSTR) &buf, 0, NULL); - logprintf(pCardData, 0, "%s%s\n", str, buf); + logprintf(pCardData, 0, "%s%s\n", str, (PSTR) buf); LocalFree(buf); } @@ -306,7 +319,7 @@ static void print_werror(PCARD_DATA pCardData, char *str) static int check_reader_status(PCARD_DATA pCardData) { - int r; + int r = SCARD_S_SUCCESS; VENDOR_SPECIFIC *vs = NULL; logprintf(pCardData, 4, "check_reader_status\n"); @@ -323,12 +336,14 @@ check_reader_status(PCARD_DATA pCardData) if (pCardData->hSCardCtx != vs->hSCardCtx || pCardData->hScard != vs->hScard) { logprintf (pCardData, 1, "HANDLES CHANGED from 0x%08X 0x%08X\n", vs->hSCardCtx, vs->hScard); - // Basically a mini AcquireContext + /* 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 + /* Rebuild 'soft' fs - in case changed */ r = md_fs_init(pCardData); logprintf(pCardData, 1, "md_fs_init r = 0x%08X\n", r); } @@ -338,7 +353,7 @@ check_reader_status(PCARD_DATA pCardData) logprintf(pCardData, 2, "check_reader_status r=%d flags 0x%08X\n", r, vs->reader->flags); } - return SCARD_S_SUCCESS; + return r; } static DWORD @@ -679,6 +694,7 @@ md_fs_free_file(PCARD_DATA pCardData, struct md_file *file) pCardData->pfnCspFree(file->blob); file->blob = NULL; file->size = 0; + pCardData->pfnCspFree(file); } @@ -750,6 +766,40 @@ md_fs_delete_file(PCARD_DATA pCardData, char *parent, char *name) return dwret; } +static DWORD +md_fs_finalize(PCARD_DATA pCardData) +{ + VENDOR_SPECIFIC *vs; + struct md_file *file = NULL, *file_to_rm; + struct md_directory *dir = NULL, *dir_to_rm; + + if (!pCardData) + return SCARD_E_INVALID_PARAMETER; + + vs = pCardData->pvVendorSpecific; + + file = vs->root.files; + while (file != NULL) { + file_to_rm = file; + file = file->next; + md_fs_free_file(pCardData, file_to_rm); + } + + dir = vs->root.subdirs; + while(dir) { + file = dir->files; + while (file != NULL) { + file_to_rm = file; + file = file->next; + md_fs_free_file(pCardData, file_to_rm); + } + dir_to_rm = dir; + dir = dir->next; + pCardData->pfnCspFree(dir_to_rm); + } + return 0; +} + static DWORD md_pkcs15_encode_cardcf(PCARD_DATA pCardData, unsigned char *in, size_t in_size, unsigned char *out, size_t *out_size) @@ -871,7 +921,7 @@ md_pkcs15_update_containers(PCARD_DATA pCardData, unsigned char *blob, size_t si vs = pCardData->pvVendorSpecific; - nn_records = size/sizeof(CONTAINER_MAP_RECORD); + nn_records = (int) size/sizeof(CONTAINER_MAP_RECORD); if (nn_records > MD_MAX_KEY_CONTAINERS) nn_records = MD_MAX_KEY_CONTAINERS; @@ -923,7 +973,7 @@ md_pkcs15_update_container_from_do(PCARD_DATA pCardData, struct sc_pkcs15_object } id.len = *(ddata->data + offs++); memcpy(id.value, ddata->data + offs, id.len); - offs += id.len; + offs += (int) id.len; if (*(ddata->data + offs++) != 0x02) { sc_pkcs15_free_data_object(ddata); @@ -1119,6 +1169,89 @@ md_set_cardid(PCARD_DATA pCardData, struct md_file *file) return SCARD_S_SUCCESS; } +/* fill the msroot file from root certificates */ +static void +md_fs_read_msroot_file(PCARD_DATA pCardData, char *parent, struct md_file *file) +{ + CERT_BLOB dbStore = {0}; + HCERTSTORE hCertStore = NULL; + DWORD dwret = 0; + VENDOR_SPECIFIC *vs; + int rv, ii, cert_num; + struct sc_pkcs15_object *prkey_objs[MD_MAX_KEY_CONTAINERS]; + + hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, (HCRYPTPROV_LEGACY) NULL, 0, NULL); + if (!hCertStore) { + dwret = GetLastError(); + goto Ret; + } + + vs = (VENDOR_SPECIFIC *) pCardData->pvVendorSpecific; + + rv = sc_pkcs15_get_objects(vs->p15card, SC_PKCS15_TYPE_CERT_X509, prkey_objs, MD_MAX_KEY_CONTAINERS); + if (rv < 0) { + logprintf(pCardData, 0, "certificate enumeration failed: %s\n", sc_strerror(rv)); + goto Ret; + } + cert_num = rv; + for(ii = 0; ii < cert_num; ii++) { + struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) prkey_objs[ii]->data; + struct sc_pkcs15_cert *cert = NULL; + PCCERT_CONTEXT wincert = NULL; + if (cert_info->authority) { + rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, &cert); + if(rv) { + logprintf(pCardData, 2, "Cannot read certificate idx:%i: sc-error %d\n", ii, rv); + continue; + } + wincert = CertCreateCertificateContext(X509_ASN_ENCODING, cert->data.value, (DWORD) cert->data.len); + if (wincert) { + CertAddCertificateContextToStore(hCertStore, wincert, CERT_STORE_ADD_REPLACE_EXISTING, NULL); + CertFreeCertificateContext(wincert); + } + else { + logprintf(pCardData, 2, "unable to load the certificate from windows 0x%08X\n", GetLastError()); + } + sc_pkcs15_free_certificate(cert); + } + } + if (FALSE == CertSaveStore( hCertStore, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + CERT_STORE_SAVE_AS_PKCS7, + CERT_STORE_SAVE_TO_MEMORY, + &dbStore, + 0)) { + dwret = GetLastError(); + goto Ret; + } + + dbStore.pbData = (PBYTE) pCardData->pfnCspAlloc(dbStore.cbData); + + if (NULL == dbStore.pbData) { + dwret = ERROR_NOT_ENOUGH_MEMORY; + goto Ret; + } + + if (FALSE == CertSaveStore( hCertStore, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + CERT_STORE_SAVE_AS_PKCS7, + CERT_STORE_SAVE_TO_MEMORY, + &dbStore, + 0)) + { + dwret = GetLastError(); + goto Ret; + } + file->size = dbStore.cbData; + file->blob = dbStore.pbData; + dbStore.pbData = NULL; +Ret: + if (dbStore.pbData) + pCardData->pfnCspFree(dbStore.pbData); + if (hCertStore) + CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG); +} + /* * Return content of the 'soft' file. */ @@ -1143,6 +1276,9 @@ md_fs_read_content(PCARD_DATA pCardData, char *parent, struct md_file *file) logprintf(pCardData, 2, "directory '%s' not found\n", parent ? parent : ""); return; } + if (vs->p15card == NULL) { + return SCARD_F_INTERNAL_ERROR; + } if (!strcmp(dir->name, "mscp")) { int idx, rv; @@ -1172,6 +1308,9 @@ md_fs_read_content(PCARD_DATA pCardData, char *parent, struct md_file *file) CopyMemory(file->blob, cert->data.value, cert->data.len); sc_pkcs15_free_certificate(cert); } + if (!strcmp(file->name, "msroot")) { + md_fs_read_msroot_file(pCardData, parent, file); + } } else { return; @@ -1273,6 +1412,37 @@ md_set_cardapps(PCARD_DATA pCardData, struct md_file *file) return SCARD_S_SUCCESS; } +/* check if the card has root certificates. If yes, notify the base csp by creating the msroot file */ +static DWORD +md_fs_add_msroot(PCARD_DATA pCardData, struct md_file **head) +{ + VENDOR_SPECIFIC *vs; + int rv, ii, cert_num; + DWORD dwret; + struct sc_pkcs15_object *prkey_objs[MD_MAX_KEY_CONTAINERS]; + if (!pCardData || !head) + return SCARD_E_INVALID_PARAMETER; + + vs = (VENDOR_SPECIFIC *) pCardData->pvVendorSpecific; + + rv = sc_pkcs15_get_objects(vs->p15card, SC_PKCS15_TYPE_CERT_X509, prkey_objs, MD_MAX_KEY_CONTAINERS); + if (rv < 0) { + logprintf(pCardData, 0, "certificate enumeration failed: %s\n", sc_strerror(rv)); + return SCARD_S_SUCCESS; + } + cert_num = rv; + for(ii = 0; ii < cert_num; ii++) { + struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) prkey_objs[ii]->data; + if (cert_info->authority) { + dwret = md_fs_add_file(pCardData, head, "msroot", EveryoneReadUserWriteAc, NULL, 0, NULL); + if (dwret != SCARD_S_SUCCESS) + return dwret; + return SCARD_S_SUCCESS; + } + } + return SCARD_S_SUCCESS; +} + /* * Set the content of the 'soft' 'cmapfile': * 1. Initialize internal p15_contaniers with the existing private keys PKCS#15 objects; @@ -1435,8 +1605,8 @@ md_set_cmapfile(PCARD_DATA pCardData, struct md_file *file) mbstowcs((p+ii)->wszGuid, vs->p15_containers[ii].guid, MAX_CONTAINER_NAME_LEN + 1); (p+ii)->bFlags = vs->p15_containers[ii].flags; - (p+ii)->wSigKeySizeBits = vs->p15_containers[ii].size_sign; - (p+ii)->wKeyExchangeKeySizeBits = vs->p15_containers[ii].size_key_exchange; + (p+ii)->wSigKeySizeBits = (WORD) vs->p15_containers[ii].size_sign; + (p+ii)->wKeyExchangeKeySizeBits = (WORD) vs->p15_containers[ii].size_key_exchange; if (vs->p15_containers[ii].cert_obj) { char k_name[6]; @@ -1460,6 +1630,10 @@ md_set_cmapfile(PCARD_DATA pCardData, struct md_file *file) loghex(pCardData, 7, (PBYTE) (p+ii), sizeof(CONTAINER_MAP_RECORD)); } } + + dwret = md_fs_add_msroot(pCardData, &(file->next)); + if (dwret != SCARD_S_SUCCESS) + return dwret; dwret = md_fs_set_content(pCardData, file, cmap_buf, cmap_len); pCardData->pfnCspFree(cmap_buf); @@ -1519,7 +1693,11 @@ md_fs_init(PCARD_DATA pCardData) if (dwret != SCARD_S_SUCCESS) return dwret; +#ifdef OPENSSL_VERSION_NUMBER logprintf(pCardData, 3, "MD virtual file system initialized; OPENSSL_VERSION_NUMBER 0x%Xl\n", OPENSSL_VERSION_NUMBER); +#else + logprintf(pCardData, 3, "MD virtual file system initialized; Without OPENSSL\n"); +#endif return SCARD_S_SUCCESS; } @@ -1551,7 +1729,7 @@ md_create_context(PCARD_DATA pCardData, VENDOR_SPECIFIC *vs) } static DWORD -md_card_capabilities(PCARD_CAPABILITIES pCardCapabilities) +md_card_capabilities(PCARD_DATA pCardData, PCARD_CAPABILITIES pCardCapabilities) { if (!pCardCapabilities) return SCARD_E_INVALID_PARAMETER; @@ -1561,7 +1739,8 @@ md_card_capabilities(PCARD_CAPABILITIES pCardCapabilities) pCardCapabilities->dwVersion = CARD_CAPABILITIES_CURRENT_VERSION; pCardCapabilities->fCertificateCompression = TRUE; - pCardCapabilities->fKeyGen = TRUE; + /* a read only card cannot generate new keys */ + pCardCapabilities->fKeyGen = ! md_is_read_only(pCardData); return SCARD_S_SUCCESS; } @@ -1686,7 +1865,8 @@ md_pkcs15_generate_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, DWORD ke memset(&pub_args, 0, sizeof(pub_args)); memset(&keygen_args, 0, sizeof(keygen_args)); - keygen_args.prkey_args.label = keygen_args.pubkey_label = "TODO: key label"; + keygen_args.prkey_args.label = "TODO: key label"; + keygen_args.pubkey_label = "TODO: key label"; if (key_type == AT_SIGNATURE) { keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA; @@ -1949,6 +2129,7 @@ md_pkcs15_store_certificate(PCARD_DATA pCardData, char *file_name, unsigned char memset(&args, 0, sizeof(args)); args.der_encoded.value = blob; args.der_encoded.len = len; + args.update = 1; /* use container's ID as ID of certificate to store */ idx = -1; @@ -2016,6 +2197,220 @@ md_query_key_sizes(CARD_KEY_SIZES *pKeySizes) 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) +{ + /* unstack the parameters */ + LONG_PTR* parameter = (LONG_PTR*) lpParameter; + int operation = (int) parameter[0]; + struct sc_pkcs15_card *p15card = (struct sc_pkcs15_card *) parameter[1]; + struct sc_pkcs15_object *pin_obj = (struct sc_pkcs15_object *) parameter[2]; + const u8 *pin1 = (const u8 *) parameter[3]; + size_t pin1len = parameter[4]; + const u8 *pin2 = (const u8 *) parameter[5]; + size_t pin2len = parameter[6]; + int rv = 0; + switch (operation) + { + case SC_PIN_CMD_VERIFY: + rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin1, pin1len); + break; + case SC_PIN_CMD_CHANGE: + rv = sc_pkcs15_change_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len); + break; + case SC_PIN_CMD_UNBLOCK: + rv = sc_pkcs15_unblock_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len); + break; + default: + rv = (DWORD) ERROR_INVALID_PARAMETER; + break; + } + if (parameter[9] != 0) { + EndDialog((HWND) parameter[9], rv); + } + return (DWORD) rv; +} + +static INT_PTR CALLBACK md_dialog_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + 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) + { + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + } + /* 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: + { + /* clean resources used */ + LPARAM param = GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (param) { + HANDLE hThread = (HANDLE)((LONG_PTR*)param)[8]; + CloseHandle(hThread); + } + } + break; + } + return FALSE; +} + + + +static int +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) +{ + LONG_PTR parameter[10]; + INT_PTR result = 0; + HWND hWndDlg = 0; + int rv = 0; + VENDOR_SPECIFIC* pv = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + /* stack the parameters */ + parameter[0] = (LONG_PTR)operation; + parameter[1] = (LONG_PTR)p15card; + parameter[2] = (LONG_PTR)pin_obj; + parameter[3] = (LONG_PTR)pin1; + parameter[4] = (LONG_PTR)pin1len; + 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 */ + /* 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); + SecureZeroMemory(parameter, sizeof(parameter)); + return (int) result; +} + +DWORD md_translate_OpenSC_to_Windows_error(int OpenSCerror, DWORD dwDefaulCode) +{ + switch(OpenSCerror) + { + /* Errors related to reader operation */ + case SC_ERROR_READER: + return SCARD_E_PROTO_MISMATCH; + case SC_ERROR_NO_READERS_FOUND: + return SCARD_E_NO_READERS_AVAILABLE; + case SC_ERROR_CARD_NOT_PRESENT: + return SCARD_E_NO_SMARTCARD; + case SC_ERROR_TRANSMIT_FAILED: + return SCARD_E_NOT_TRANSACTED; + case SC_ERROR_CARD_REMOVED: + return SCARD_W_REMOVED_CARD; + case SC_ERROR_CARD_RESET: + return SCARD_W_RESET_CARD; + case SC_ERROR_KEYPAD_CANCELLED: + return SCARD_W_CANCELLED_BY_USER; + case SC_ERROR_KEYPAD_MSG_TOO_LONG: + return SCARD_W_CARD_NOT_AUTHENTICATED; + case SC_ERROR_KEYPAD_PIN_MISMATCH: + return SCARD_E_INVALID_CHV; + case SC_ERROR_KEYPAD_TIMEOUT: + return ERROR_TIMEOUT; + case SC_ERROR_EVENT_TIMEOUT: + return SCARD_E_TIMEOUT; + case SC_ERROR_CARD_UNRESPONSIVE: + return SCARD_W_UNRESPONSIVE_CARD; + case SC_ERROR_READER_LOCKED: + return SCARD_E_SHARING_VIOLATION; + + /* Resulting from a card command or related to the card*/ + case SC_ERROR_INCORRECT_PARAMETERS: + return SCARD_E_INVALID_PARAMETER; + case SC_ERROR_MEMORY_FAILURE: + case SC_ERROR_NOT_ENOUGH_MEMORY: + return SCARD_E_NO_MEMORY; + case SC_ERROR_NOT_ALLOWED: + return SCARD_W_SECURITY_VIOLATION; + case SC_ERROR_AUTH_METHOD_BLOCKED: + return SCARD_W_CHV_BLOCKED; + case SC_ERROR_PIN_CODE_INCORRECT: + return SCARD_W_WRONG_CHV; + + /* Returned by OpenSC library when called with invalid arguments */ + case SC_ERROR_INVALID_ARGUMENTS: + return ERROR_INVALID_PARAMETER; + case SC_ERROR_BUFFER_TOO_SMALL: + return NTE_BUFFER_TOO_SMALL; + + /* Resulting from OpenSC internal operation */ + case SC_ERROR_INTERNAL: + return ERROR_INTERNAL_ERROR; + case SC_ERROR_NOT_SUPPORTED: + return SCARD_E_UNSUPPORTED_FEATURE; + case SC_ERROR_NOT_IMPLEMENTED: + return ERROR_CALL_NOT_IMPLEMENTED; + + default: + return dwDefaulCode; + } +} + DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) { VENDOR_SPECIFIC *vs = NULL; @@ -2044,6 +2439,7 @@ DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) logprintf(pCardData, 1, "**********************************************************************\n"); + md_fs_finalize(pCardData); pCardData->pfnCspFree(pCardData->pvVendorSpecific); pCardData->pvVendorSpecific = NULL; @@ -2051,17 +2447,17 @@ DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) } DWORD WINAPI CardQueryCapabilities(__in PCARD_DATA pCardData, - __in PCARD_CAPABILITIES pCardCapabilities) + __inout PCARD_CAPABILITIES pCardCapabilities) { DWORD dwret; logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); - logprintf(pCardData, 1, "pCardCapabilities=%X\n", pCardCapabilities); + logprintf(pCardData, 1, "pCardCapabilities=%p\n", pCardCapabilities); if (!pCardData || !pCardCapabilities) return SCARD_E_INVALID_PARAMETER; - dwret = md_card_capabilities(pCardCapabilities); + dwret = md_card_capabilities(pCardData, pCardCapabilities); if (dwret != SCARD_S_SUCCESS) return dwret; @@ -2157,7 +2553,7 @@ typedef struct { } PUBKEYSTRUCT_BASE; DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContainerIndex, __in DWORD dwFlags, - __in PCONTAINER_INFO pContainerInfo) + __inout PCONTAINER_INFO pContainerInfo) { VENDOR_SPECIFIC *vs = NULL; DWORD sz = 0; @@ -2194,6 +2590,10 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine return SCARD_E_NO_KEY_CONTAINER; } + if (vs->p15card == NULL) { + return SCARD_F_INTERNAL_ERROR; + } + check_reader_status(pCardData); pubkey_der.value = NULL; pubkey_der.len = 0; @@ -2267,7 +2667,7 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine if (pubkey_der.len && pubkey_der.value) { sz = 0; /* get size */ CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, - pubkey_der.value, pubkey_der.len, 0, NULL, &sz); + pubkey_der.value, (DWORD) pubkey_der.len, 0, NULL, &sz); if (cont->size_sign) { PUBKEYSTRUCT_BASE *oh = (PUBKEYSTRUCT_BASE *)pCardData->pfnCspAlloc(sz); @@ -2275,7 +2675,7 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine return SCARD_E_NO_MEMORY; CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, - pubkey_der.value, pubkey_der.len, 0, oh, &sz); + pubkey_der.value, (DWORD) pubkey_der.len, 0, oh, &sz); oh->publickeystruc.aiKeyAlg = CALG_RSA_SIGN; pContainerInfo->cbSigPublicKey = sz; @@ -2290,7 +2690,7 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine return SCARD_E_NO_MEMORY; CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, - pubkey_der.value, pubkey_der.len, 0, oh, &sz); + pubkey_der.value, (DWORD) pubkey_der.len, 0, oh, &sz); oh->publickeystruc.aiKeyAlg = CALG_RSA_KEYX; pContainerInfo->cbKeyExPublicKey = sz; @@ -2306,82 +2706,27 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData, __in LPWSTR pwszUserId, - __in PBYTE pbPin, + __in_bcount(cbPin) PBYTE pbPin, __in DWORD cbPin, __out_opt PDWORD pcAttemptsRemaining) { - struct sc_pkcs15_object *pin_obj = NULL; - struct sc_pkcs15_auth_info *auth_info = NULL; - char type[256]; - VENDOR_SPECIFIC *vs; - struct md_file *cardcf_file = NULL; - CARD_CACHE_FILE_FORMAT *cardcf = NULL; - DWORD dwret; - int r; - - if(!pCardData) - return SCARD_E_INVALID_PARAMETER; - - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - + PIN_ID PinId = 0; logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardAuthenticatePin '%S':%d\n", NULLWSTR(pwszUserId), cbPin); - check_reader_status(pCardData); - - dwret = md_get_cardcf(pCardData, &cardcf); - if (dwret != SCARD_S_SUCCESS) - return dwret; - - if (NULL == pwszUserId) - return SCARD_E_INVALID_PARAMETER; - if (wcscmp(wszCARD_USER_USER,pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN,pwszUserId) != 0) - return SCARD_E_INVALID_PARAMETER; - if (NULL == pbPin) - return SCARD_E_INVALID_PARAMETER; - - if (cbPin < 4 || cbPin > 12) - return SCARD_W_WRONG_CHV; - - if (wcscmp(wszCARD_USER_ADMIN, pwszUserId) == 0) - return SCARD_W_WRONG_CHV; - - if(pcAttemptsRemaining) - (*pcAttemptsRemaining) = 0; - - wcstombs(type, pwszUserId, 100); - type[10] = 0; - - logprintf(pCardData, 1, "CardAuthenticatePin %.20s, %d, %d\n", NULLSTR(type), - cbPin, (pcAttemptsRemaining==NULL?-2:*pcAttemptsRemaining)); - - r = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj); - if (r != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object"); - return r; + if (wcscmp(pwszUserId, wszCARD_USER_USER) == 0) { + PinId = ROLE_USER; } - - if (!pin_obj) - return SCARD_F_INTERNAL_ERROR; - auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; - - r = sc_pkcs15_verify_pin(vs->p15card, pin_obj, (const u8 *) pbPin, cbPin); - if (r) { - logprintf(pCardData, 1, "PIN code verification failed: %s; tries left %i\n", sc_strerror(r), auth_info->tries_left); - - if (r == SC_ERROR_AUTH_METHOD_BLOCKED) - return SCARD_W_CHV_BLOCKED; - - if(pcAttemptsRemaining) - (*pcAttemptsRemaining) = auth_info->tries_left; - return SCARD_W_WRONG_CHV; + else if (wcscmp(pwszUserId, wszCARD_USER_ADMIN) == 0) { + PinId = ROLE_ADMIN; } + else { + return SCARD_E_INVALID_PARAMETER; + } + if (pbPin == NULL) + return SCARD_E_INVALID_PARAMETER; - logprintf(pCardData, 3, "Pin code correct.\n"); - - SET_PIN(cardcf->bPinsFreshness, ROLE_USER); - logprintf(pCardData, 3, "PinsFreshness = %d\n", cardcf->bPinsFreshness); - return SCARD_S_SUCCESS; + return CardAuthenticateEx(pCardData, PinId, CARD_PIN_SILENT_CONTEXT, pbPin, cbPin, NULL, NULL, pcAttemptsRemaining); } @@ -2390,8 +2735,6 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData, __out PDWORD pcbChallengeData) { VENDOR_SPECIFIC *vs; - unsigned char *random = NULL; - size_t random_len; int rv; logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); @@ -2403,7 +2746,7 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData, return SCARD_E_INVALID_PARAMETER; logprintf(pCardData, 1, "Asked challenge length %i, buffer %p\n", *pcbChallengeData, *ppbChallengeData); - if (pcbChallengeData == 0) { + if (pcbChallengeData == NULL) { *ppbChallengeData = NULL; logprintf(pCardData, 7, "returns zero bytes\n"); @@ -2414,29 +2757,20 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData, check_reader_status(pCardData); - random_len = (size_t)(*pcbChallengeData); - if(random_len < 8) - random_len = 8; - *pcbChallengeData = 0; + *pcbChallengeData = 8; - random = malloc(random_len); - if (!random) + *ppbChallengeData = (PBYTE) pCardData->pfnCspAlloc(8); + if (!*ppbChallengeData) return SCARD_E_NO_MEMORY; - rv = sc_get_challenge(vs->p15card->card, random, random_len); + rv = sc_get_challenge(vs->p15card->card, *ppbChallengeData, 8); if (rv) { logprintf(pCardData, 1, "Get challenge failed: %s\n", sc_strerror(rv)); + pCardData->pfnCspFree(*ppbChallengeData); + *ppbChallengeData = NULL; return SCARD_E_UNEXPECTED; } - *ppbChallengeData = pCardData->pfnCspAlloc(random_len); - if(!*ppbChallengeData) - return SCARD_E_NO_MEMORY; - - memcpy(*ppbChallengeData, random, random_len); - *pcbChallengeData = random_len; - free(random); - logprintf(pCardData, 7, "returns %i bytes:\n", *pcbChallengeData); loghex(pCardData, 7, *ppbChallengeData, *pcbChallengeData); return SCARD_S_SUCCESS; @@ -2463,11 +2797,6 @@ DWORD WINAPI CardUnblockPin(__in PCARD_DATA pCardData, __in DWORD cRetryCount, __in DWORD dwFlags) { - VENDOR_SPECIFIC *vs = NULL; - DWORD dw_rv; - struct sc_pkcs15_object *pin_obj = NULL; - int rv; - if(!pCardData) return SCARD_E_INVALID_PARAMETER; @@ -2476,37 +2805,20 @@ DWORD WINAPI CardUnblockPin(__in PCARD_DATA pCardData, if (pwszUserId == NULL) return SCARD_E_INVALID_PARAMETER; - if (pbAuthenticationData == NULL) - return SCARD_E_INVALID_PARAMETER; if (wcscmp(wszCARD_USER_USER, pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN,pwszUserId) != 0) return SCARD_E_INVALID_PARAMETER; if (wcscmp(wszCARD_USER_ADMIN, pwszUserId) == 0) - return SCARD_W_WRONG_CHV; + return SCARD_E_UNSUPPORTED_FEATURE; + if (dwFlags & CARD_AUTHENTICATE_PIN_CHALLENGE_RESPONSE) + return SCARD_E_UNSUPPORTED_FEATURE; + if (dwFlags) + return SCARD_E_INVALID_PARAMETER; - logprintf(pCardData, 1, "UserID('%s'), AuthData(%p, %li), NewPIN(%p, %li), Retry(%li), dwFlags(0x%lX)\n", + logprintf(pCardData, 1, "UserID('%S'), AuthData(%p, %u), NewPIN(%p, %u), Retry(%u), dwFlags(0x%X)\n", pwszUserId, pbAuthenticationData, cbAuthenticationData, pbNewPinData, cbNewPinData, cRetryCount, dwFlags); - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - - dw_rv = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj); - if (dw_rv != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object"); - return dw_rv; - } - if (!pin_obj) - return SCARD_F_INTERNAL_ERROR; - - rv = sc_pkcs15_unblock_pin(vs->p15card, pin_obj, - pbAuthenticationData, cbAuthenticationData, - pbNewPinData, cbNewPinData); - if (rv) { - logprintf(pCardData, 2, "Failed to unblock User PIN: '%s' (%i)\n", sc_strerror(rv), rv); - return SCARD_F_INTERNAL_ERROR; - } - - logprintf(pCardData, 7, "returns success\n"); - return SCARD_S_SUCCESS; + return CardChangeAuthenticatorEx(pCardData, PIN_CHANGE_FLAG_UNBLOCK | CARD_PIN_SILENT_CONTEXT, ROLE_ADMIN, pbAuthenticationData, cbAuthenticationData, ROLE_USER, pbNewPinData, cbNewPinData, cRetryCount, NULL); } @@ -2520,11 +2832,7 @@ DWORD WINAPI CardChangeAuthenticator(__in PCARD_DATA pCardData, __in DWORD dwFlags, __out_opt PDWORD pcAttemptsRemaining) { - VENDOR_SPECIFIC *vs = NULL; - DWORD dw_rv; - struct sc_pkcs15_object *pin_obj = NULL; - int rv; - + PIN_ID pinid; if(!pCardData) return SCARD_E_INVALID_PARAMETER; @@ -2534,60 +2842,33 @@ DWORD WINAPI CardChangeAuthenticator(__in PCARD_DATA pCardData, if (pwszUserId == NULL) return SCARD_E_INVALID_PARAMETER; - if (pbCurrentAuthenticator == NULL || cbCurrentAuthenticator == 0) { - logprintf(pCardData, 1, "Invalid current PIN data\n"); - return SCARD_E_INVALID_PARAMETER; - } - - if (pbNewAuthenticator == NULL || cbNewAuthenticator == 0) { - logprintf(pCardData, 1, "Invalid new PIN data\n"); - return SCARD_E_INVALID_PARAMETER; - } - - if (dwFlags != CARD_AUTHENTICATE_PIN_PIN) { + if (dwFlags == CARD_AUTHENTICATE_PIN_CHALLENGE_RESPONSE) { logprintf(pCardData, 1, "Other then 'authentication' the PIN are not supported\n"); return SCARD_E_UNSUPPORTED_FEATURE; } + else if (dwFlags != CARD_AUTHENTICATE_PIN_PIN){ + return SCARD_E_INVALID_PARAMETER; + } if (wcscmp(wszCARD_USER_USER, pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN, pwszUserId) != 0) return SCARD_E_INVALID_PARAMETER; - if(pcAttemptsRemaining) - (*pcAttemptsRemaining) = 0; - - logprintf(pCardData, 1, "UserID('%s'), CurrentPIN(%p, %li), NewPIN(%p, %li), Retry(%li), dwFlags(0x%lX)\n", + logprintf(pCardData, 1, "UserID('%S'), CurrentPIN(%p, %u), NewPIN(%p, %u), Retry(%u), dwFlags(0x%X)\n", pwszUserId, pbCurrentAuthenticator, cbCurrentAuthenticator, pbNewAuthenticator, cbNewAuthenticator, cRetryCount, dwFlags); - vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - if (wcscmp(wszCARD_USER_USER, pwszUserId) == 0) - dw_rv = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj); - else if (wcscmp(wszCARD_USER_ADMIN,pwszUserId) == 0) - dw_rv = md_get_pin_by_role(pCardData, ROLE_ADMIN, &pin_obj); + pinid = ROLE_USER; else - return SCARD_F_INTERNAL_ERROR; + pinid = ROLE_ADMIN; - if (dw_rv != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get %s PIN by role", pwszUserId); - return dw_rv; - } - if (!pin_obj) - return SCARD_F_INTERNAL_ERROR; - - rv = sc_pkcs15_change_pin(vs->p15card, pin_obj, - pbCurrentAuthenticator, cbCurrentAuthenticator, - pbNewAuthenticator, cbNewAuthenticator); - if (rv) { - logprintf(pCardData, 2, "Failed to change %s PIN: '%s' (%i)\n", pwszUserId, sc_strerror(rv), rv); - return SCARD_F_INTERNAL_ERROR; - } - - logprintf(pCardData, 7, "returns success\n"); - return SCARD_S_SUCCESS; + return CardChangeAuthenticatorEx(pCardData, PIN_CHANGE_FLAG_CHANGEPIN | CARD_PIN_SILENT_CONTEXT, pinid, pbCurrentAuthenticator, cbCurrentAuthenticator, pinid, pbNewAuthenticator, cbNewAuthenticator, cRetryCount, pcAttemptsRemaining); } - +/* 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*/ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, __in LPWSTR pwszUserId, __in DWORD dwFlags) @@ -2621,7 +2902,9 @@ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, logprintf(pCardData, 5, "PinsFreshness = %d\n", cardcf->bPinsFreshness); /* TODO Reset PKCS#15 PIN object 'validated' flag */ - return SCARD_S_SUCCESS; + + /* 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_E_UNSUPPORTED_FEATURE; } DWORD WINAPI CardCreateDirectory(__in PCARD_DATA pCardData, @@ -2642,7 +2925,7 @@ DWORD WINAPI CardDeleteDirectory(__in PCARD_DATA pCardData, } DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, + __in_opt LPSTR pszDirectoryName, __in LPSTR pszFileName, __in DWORD cbInitialCreationSize, __in CARD_FILE_ACCESS_CONDITION AccessCondition) @@ -2669,10 +2952,10 @@ DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, + __in_opt LPSTR pszDirectoryName, __in LPSTR pszFileName, __in DWORD dwFlags, - __deref_out_bcount(*pcbData) PBYTE *ppbData, + __deref_out_bcount_opt(*pcbData) PBYTE *ppbData, __out PDWORD pcbData) { VENDOR_SPECIFIC *vs; @@ -2689,7 +2972,7 @@ DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - logprintf(pCardData, 2, "pszDirectoryName = %s, pszFileName = %s, dwFlags = %X, pcbData=%d, *ppbData=%X\n", + logprintf(pCardData, 2, "pszDirectoryName = %s, pszFileName = %s, dwFlags = %X, pcbData=%u, *ppbData=%X\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName), dwFlags, *pcbData, *ppbData); if (!pszFileName || !strlen(pszFileName)) @@ -2711,7 +2994,7 @@ DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, *ppbData = pCardData->pfnCspAlloc(file->size); if(!*ppbData) return SCARD_E_NO_MEMORY; - *pcbData = file->size; + *pcbData = (DWORD) file->size; memcpy(*ppbData, file->blob, file->size); logprintf(pCardData, 7, "returns '%s' content:\n", NULLSTR(pszFileName)); @@ -2721,7 +3004,7 @@ DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, DWORD WINAPI CardWriteFile(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, + __in_opt LPSTR pszDirectoryName, __in LPSTR pszFileName, __in DWORD dwFlags, __in_bcount(cbData) PBYTE pbData, @@ -2772,7 +3055,7 @@ DWORD WINAPI CardWriteFile(__in PCARD_DATA pCardData, } DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, + __in_opt LPSTR pszDirectoryName, __in LPSTR pszFileName, __in DWORD dwFlags) { @@ -2798,8 +3081,8 @@ DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, DWORD WINAPI CardEnumFiles(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, - __out_ecount(*pdwcbFileName) LPSTR *pmszFileNames, + __in_opt LPSTR pszDirectoryName, + __deref_out_ecount(*pdwcbFileName) LPSTR *pmszFileNames, __out LPDWORD pdwcbFileName, __in DWORD dwFlags) { @@ -2848,15 +3131,15 @@ DWORD WINAPI CardEnumFiles(__in PCARD_DATA pCardData, return SCARD_E_NO_MEMORY; CopyMemory(*pmszFileNames, mstr, offs); - *pdwcbFileName = offs; + *pdwcbFileName = (DWORD) offs; return SCARD_S_SUCCESS; } DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData, - __in LPSTR pszDirectoryName, + __in_opt LPSTR pszDirectoryName, __in LPSTR pszFileName, - __in PCARD_FILE_INFO pCardFileInfo) + __inout PCARD_FILE_INFO pCardFileInfo) { VENDOR_SPECIFIC *vs = NULL; struct md_directory *dir = NULL; @@ -2874,7 +3157,7 @@ DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData, } pCardFileInfo->dwVersion = CARD_FILE_INFO_CURRENT_VERSION; - pCardFileInfo->cbFileSize = file->size; + pCardFileInfo->cbFileSize = (DWORD) file->size; pCardFileInfo->AccessCondition = file->acl; return SCARD_S_SUCCESS; @@ -2882,7 +3165,7 @@ DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData, DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags, - __in PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo) + __inout PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo) { VENDOR_SPECIFIC *vs; DWORD dwret; @@ -2913,15 +3196,32 @@ DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags, DWORD WINAPI CardQueryKeySizes(__in PCARD_DATA pCardData, __in DWORD dwKeySpec, __in DWORD dwFlags, - __out PCARD_KEY_SIZES pKeySizes) + __inout PCARD_KEY_SIZES pKeySizes) { DWORD dwret; logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); - logprintf(pCardData, 1, "CardQueryKeySizes dwKeySpec=%X, dwFlags=%X, version=%X\n", dwKeySpec, dwFlags, pKeySizes->dwVersion); + logprintf(pCardData, 1, "CardQueryKeySizes dwKeySpec=%X, dwFlags=%X, version=%X\n", dwKeySpec, dwFlags, (pKeySizes?pKeySizes->dwVersion:0)); if (!pCardData) return SCARD_E_INVALID_PARAMETER; + if ( dwFlags != 0 ) + return SCARD_E_INVALID_PARAMETER; + switch(dwKeySpec) + { + case AT_ECDHE_P256 : + case AT_ECDHE_P384 : + case AT_ECDHE_P521 : + case AT_ECDSA_P256 : + case AT_ECDSA_P384 : + case AT_ECDSA_P521 : + return SCARD_E_UNSUPPORTED_FEATURE; + case AT_KEYEXCHANGE: + case AT_SIGNATURE : + break; + default: + return SCARD_E_INVALID_PARAMETER; + } dwret = md_query_key_sizes(pKeySizes); if (dwret != SCARD_S_SUCCESS) @@ -2952,9 +3252,22 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, return SCARD_E_INVALID_PARAMETER; if (!pInfo) return SCARD_E_INVALID_PARAMETER; + if ( pInfo->pbData == NULL ) + return SCARD_E_INVALID_PARAMETER; + if (pInfo->dwVersion > CARD_RSA_KEY_DECRYPT_INFO_CURRENT_VERSION) + return ERROR_REVISION_MISMATCH; + if ( pInfo->dwVersion < CARD_RSA_KEY_DECRYPT_INFO_CURRENT_VERSION + && pCardData->dwVersion == CARD_DATA_CURRENT_VERSION) + return ERROR_REVISION_MISMATCH; + if (pInfo->dwKeySpec != AT_KEYEXCHANGE) + return SCARD_E_INVALID_PARAMETER; vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + /* check if the container exists */ + if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS) + return SCARD_E_NO_KEY_CONTAINER; + check_reader_status(pCardData); logprintf(pCardData, 2, "CardRSADecrypt dwVersion=%u, bContainerIndex=%u,dwKeySpec=%u pbData=%p, cbData=%u\n", @@ -2966,7 +3279,7 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, pkey = vs->p15_containers[pInfo->bContainerIndex].prkey_obj; if (!pkey) { logprintf(pCardData, 2, "CardRSADecrypt prkey not found\n"); - return SCARD_E_INVALID_PARAMETER; + return SCARD_E_NO_KEY_CONTAINER; } /* input and output buffers are always the same size */ @@ -2976,8 +3289,10 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, lg2 = pInfo->cbData; pbuf2 = pCardData->pfnCspAlloc(pInfo->cbData); - if (!pbuf2) + if (!pbuf2) { + pCardData->pfnCspFree(pbuf); return SCARD_E_NO_MEMORY; + } /*inversion donnees*/ for(ui = 0; ui < pInfo->cbData; ui++) @@ -2986,37 +3301,53 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, loghex(pCardData, 7, pbuf, pInfo->cbData); prkey_info = (struct sc_pkcs15_prkey_info *)(pkey->data); - alg_info = sc_card_find_rsa_alg(vs->p15card->card, prkey_info->modulus_length); + alg_info = sc_card_find_rsa_alg(vs->p15card->card, (unsigned int) prkey_info->modulus_length); if (!alg_info) { logprintf(pCardData, 2, "Cannot get appropriate RSA card algorithm for key size %i\n", prkey_info->modulus_length); + pCardData->pfnCspFree(pbuf); + pCardData->pfnCspFree(pbuf2); return SCARD_F_INTERNAL_ERROR; } + /* filter boggus 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; + } + if (alg_info->flags & SC_ALGORITHM_RSA_RAW) { logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA-RAW mechanism\n"); r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags, pbuf, pInfo->cbData, pbuf2, pInfo->cbData); - if (r < 0) { - logprintf(pCardData, 2, "PKCS#15 decipher failed: %i\n", r); - return SCARD_F_INTERNAL_ERROR; - } logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r); - // Need to handle padding - if (pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) { - logprintf(pCardData, 2, "sc_pkcs15_decipher: DECRYPT-INFO dwVersion=%u\n", pInfo->dwVersion); - if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) { - logprintf(pCardData, 2, "sc_pkcs15_decipher: stripping PKCS1 padding\n"); - r = sc_pkcs1_strip_02_padding(vs->ctx, pbuf2, pInfo->cbData, pbuf2, &pInfo->cbData); - if (r < 0) { - logprintf(pCardData, 2, "Cannot strip PKCS1 padding: %i\n", r); + if (r > 0) { + /* Need to handle padding */ + if (pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) { + logprintf(pCardData, 2, "sc_pkcs15_decipher: DECRYPT-INFO dwVersion=%u\n", pInfo->dwVersion); + if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) { + size_t temp = pInfo->cbData; + logprintf(pCardData, 2, "sc_pkcs15_decipher: stripping PKCS1 padding\n"); + r = sc_pkcs1_strip_02_padding(vs->ctx, pbuf2, pInfo->cbData, pbuf2, &temp); + pInfo->cbData = (DWORD) temp; + if (r < 0) { + logprintf(pCardData, 2, "Cannot strip PKCS1 padding: %i\n", r); + pCardData->pfnCspFree(pbuf); + pCardData->pfnCspFree(pbuf2); + return SCARD_F_INTERNAL_ERROR; + } + } + else if (pInfo->dwPaddingType == CARD_PADDING_OAEP) { + /* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */ + logprintf(pCardData, 2, "OAEP padding not implemented\n"); + pCardData->pfnCspFree(pbuf); + pCardData->pfnCspFree(pbuf2); return SCARD_F_INTERNAL_ERROR; } } - else if (pInfo->dwPaddingType == CARD_PADDING_OAEP) { - /* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */ - logprintf(pCardData, 2, "OAEP padding not implemented\n"); - return SCARD_F_INTERNAL_ERROR; - } } } else if (alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1) { @@ -3025,7 +3356,7 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, pbuf, pInfo->cbData, pbuf2, pInfo->cbData); logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r); if (r > 0) { - // No padding info, or padding info none + /* No padding info, or padding info none */ if ((pInfo->dwVersion < CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) || ((pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) && (pInfo->dwPaddingType == CARD_PADDING_NONE))) { @@ -3041,7 +3372,7 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, } } else if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) { - // PKCS1 padding is already handled by the card... + /* PKCS1 padding is already handled by the card... */ pInfo->cbData = r; } /* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */ @@ -3049,12 +3380,16 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, } else { logprintf(pCardData, 2, "CardRSADecrypt: no usable RSA algorithm\n"); + pCardData->pfnCspFree(pbuf); + pCardData->pfnCspFree(pbuf2); return SCARD_E_INVALID_PARAMETER; } if ( r < 0) { logprintf(pCardData, 2, "sc_pkcs15_decipher error(%i): %s\n", r, sc_strerror(r)); - return SCARD_E_INVALID_VALUE; + pCardData->pfnCspFree(pbuf); + pCardData->pfnCspFree(pbuf2); + return md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE); } logprintf(pCardData, 2, "decrypted data(%i):\n", pInfo->cbData); @@ -3070,7 +3405,7 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, } -DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pInfo) +DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __inout PCARD_SIGNING_INFO pInfo) { VENDOR_SPECIFIC *vs; ALG_ID hashAlg; @@ -3085,6 +3420,15 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn if (!pCardData || !pInfo) return SCARD_E_INVALID_PARAMETER; + if ( ( pInfo->dwVersion != CARD_SIGNING_INFO_BASIC_VERSION ) && + ( pInfo->dwVersion != CARD_SIGNING_INFO_CURRENT_VERSION ) ) + return ERROR_REVISION_MISMATCH; + if ( pInfo->pbData == NULL ) + return SCARD_E_INVALID_PARAMETER; + if (pInfo->dwKeySpec != AT_SIGNATURE && pInfo->dwKeySpec != AT_KEYEXCHANGE) + return SCARD_E_INVALID_PARAMETER; + 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; logprintf(pCardData, 2, "CardSignData dwVersion=%u, bContainerIndex=%u, dwKeySpec=%u, dwSigningFlags=0x%08X, aiHashAlg=0x%08X\n", pInfo->dwVersion,pInfo->bContainerIndex ,pInfo->dwKeySpec, pInfo->dwSigningFlags, pInfo->aiHashAlg); @@ -3114,10 +3458,15 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn if (CARD_PADDING_INFO_PRESENT & pInfo->dwSigningFlags) { BCRYPT_PKCS1_PADDING_INFO *pinf = (BCRYPT_PKCS1_PADDING_INFO *)pInfo->pPaddingInfo; - if (CARD_PADDING_PKCS1 != pInfo->dwPaddingType) { - logprintf(pCardData, 0, "unsupported paddingtype\n"); + if (CARD_PADDING_PSS == pInfo->dwPaddingType) { + logprintf(pCardData, 0, "unsupported paddingtype CARD_PADDING_PSS\n"); return SCARD_E_UNSUPPORTED_FEATURE; } + else if (CARD_PADDING_PKCS1 != pInfo->dwPaddingType) { + logprintf(pCardData, 0, "unsupported paddingtype\n"); + return SCARD_E_INVALID_PARAMETER; + } + if (!pinf->pszAlgId) { /* hashAlg = CALG_SSL3_SHAMD5; */ logprintf(pCardData, 3, "Using CALG_SSL3_SHAMD5 hashAlg\n"); @@ -3130,8 +3479,16 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA1; else if (wcscmp(pinf->pszAlgId, L"SHAMD5") == 0) opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5_SHA1; + else if (wcscmp(pinf->pszAlgId, L"SHA224") == 0) + opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA224; else if (wcscmp(pinf->pszAlgId, L"SHA256") == 0) opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA256; + else if (wcscmp(pinf->pszAlgId, L"SHA384") == 0) + opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA384; + else if (wcscmp(pinf->pszAlgId, L"SHA512") == 0) + 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 { logprintf(pCardData, 0,"unknown AlgId %S\n",NULLWSTR(pinf->pszAlgId)); @@ -3155,9 +3512,25 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5_SHA1; else if (hashAlg == CALG_SHA_256) opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA256; + else if (hashAlg == CALG_SHA_384) + opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA384; + else if (hashAlg == CALG_SHA_512) + opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA512; + else if (hashAlg == (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_RIPEMD160)) + opt_hash_flags = SC_ALGORITHM_RSA_HASH_RIPEMD160; else if (hashAlg !=0) return SCARD_E_UNSUPPORTED_FEATURE; } + + if (pInfo->dwSigningFlags & CARD_PADDING_NONE) + { + /* do not add the digest info when called from CryptSignHash(CRYPT_NOHASHOID) + + Note: SC_ALGORITHM_RSA_HASH_MD5_SHA1 aka CALG_SSL3_SHAMD5 do not have a digest info to be added + CryptSignHash(CALG_SSL3_SHAMD5,CRYPT_NOHASHOID) is the same than CryptSignHash(CALG_SSL3_SHAMD5) + */ + opt_hash_flags = 0; + } /* From sc-minidriver_specs_v7.docx pp.76: * 'The Base CSP/KSP performs the hashing operation on the data before passing it @@ -3181,7 +3554,7 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn } opt_crypt_flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; - pInfo->cbSignedData = prkey_info->modulus_length / 8; + pInfo->cbSignedData = (DWORD) prkey_info->modulus_length / 8; logprintf(pCardData, 3, "pInfo->cbSignedData = %d\n", pInfo->cbSignedData); if(!(pInfo->dwSigningFlags&CARD_BUFFER_SIZE_ONLY)) { @@ -3208,7 +3581,8 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn logprintf(pCardData, 2, "sc_pkcs15_compute_signature return %d\n", r); if(r < 0) { logprintf(pCardData, 2, "sc_pkcs15_compute_signature erreur %s\n", sc_strerror(r)); - return SCARD_F_INTERNAL_ERROR; + pCardData->pfnCspFree(pbuf); + return md_translate_OpenSC_to_Windows_error(r, SCARD_F_INTERNAL_ERROR); } pInfo->cbSignedData = r; @@ -3229,7 +3603,7 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pIn } DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, - __in PCARD_DH_AGREEMENT_INFO pAgreementInfo) + __inout PCARD_DH_AGREEMENT_INFO pAgreementInfo) { logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardConstructDHAgreement - unsupported\n"); @@ -3237,7 +3611,7 @@ DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, } DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, - __in PCARD_DERIVE_KEY pAgreementInfo) + __inout PCARD_DERIVE_KEY pAgreementInfo) { logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeriveKey - unsupported\n"); @@ -3277,9 +3651,9 @@ DWORD WINAPI CardGetChallengeEx(__in PCARD_DATA pCardData, DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, __in PIN_ID PinId, __in DWORD dwFlags, - __in PBYTE pbPinData, + __in_bcount(cbPinData) PBYTE pbPinData, __in DWORD cbPinData, - __deref_out_bcount_opt(*pcbSessionPin) PBYTE *ppbSessionPin, + __deref_opt_out_bcount(*pcbSessionPin) PBYTE *ppbSessionPin, __out_opt PDWORD pcbSessionPin, __out_opt PDWORD pcAttemptsRemaining) { @@ -3289,6 +3663,7 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, struct sc_pkcs15_object *pin_obj = NULL; struct sc_pkcs15_auth_info *auth_info = NULL; int r; + BOOL DisplayPinpadUI = FALSE; logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardAuthenticateEx\n"); @@ -3301,24 +3676,33 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - check_reader_status(pCardData); + r = check_reader_status(pCardData); + + if ((vs->p15card) == NULL) + return SCARD_F_INTERNAL_ERROR; if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) { if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) return SCARD_E_UNSUPPORTED_FEATURE; } - if (dwFlags && (dwFlags & CARD_PIN_SILENT_CONTEXT) && NULL == pbPinData) + if (dwFlags & ~(CARD_AUTHENTICATE_GENERATE_SESSION_PIN | CARD_AUTHENTICATE_SESSION_PIN | CARD_PIN_SILENT_CONTEXT)) return SCARD_E_INVALID_PARAMETER; - if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD) && NULL == pbPinData) - return SCARD_E_INVALID_PARAMETER; + /* using a pin pad */ + if (NULL == pbPinData) { + if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) + return SCARD_E_INVALID_PARAMETER; + if (!(dwFlags & CARD_PIN_SILENT_CONTEXT)) { + DisplayPinpadUI = TRUE; + } + } if (PinId != ROLE_USER) return SCARD_E_INVALID_PARAMETER; if(pcAttemptsRemaining) - (*pcAttemptsRemaining) = 0; + (*pcAttemptsRemaining) = (DWORD) -1; r = md_get_pin_by_role(pCardData, PinId, &pin_obj); if (r != SCARD_S_SUCCESS) { @@ -3331,39 +3715,46 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; /* Do we need to display a prompt to enter PIN on pin pad? */ - logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%d\n", + logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%p\n", vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? "yes" : "no", pbPinData, vs->hwndParent); - if ((vs->reader->capabilities & SC_READER_CAP_PIN_PAD) && NULL == pbPinData) { - char buf[200]; - snprintf(buf, sizeof(buf), "Please enter PIN %s", - NULL == vs->wszPinContext ? "on reader pinpad." : vs->wszPinContext); - logprintf(pCardData, 7, "About to display message box for external PIN verification\n"); - /* @TODO: Ideally, this should probably be a non-modal dialog with just a cancel button - * that goes away as soon as a key is pressed on the pinpad. - */ - r = MessageBox(vs->hwndParent, buf, "PIN Entry Required", - MB_OKCANCEL | MB_ICONINFORMATION); - if (IDCANCEL == r) { - logprintf(pCardData, 2, "User canceled PIN verification\n"); - /* @TODO: is this the right code to return? */ - return SCARD_E_INVALID_PARAMETER; - } + + /* check if the pin is the session pin generated by a previous authentication with a pinpad */ + if (pbPinData != NULL && cbPinData == sizeof(MAGIC_SESSION_PIN) && memcmp(MAGIC_SESSION_PIN, pbPinData, sizeof(MAGIC_SESSION_PIN)) == 0) { + pbPinData = NULL; + cbPinData = 0; } - r = sc_pkcs15_verify_pin(vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData); + r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_VERIFY, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, NULL, 0, DisplayPinpadUI); + if (r) { logprintf(pCardData, 1, "PIN code verification failed: %s; tries left %i\n", sc_strerror(r), auth_info->tries_left); - if (r == SC_ERROR_AUTH_METHOD_BLOCKED) + if (r == SC_ERROR_AUTH_METHOD_BLOCKED) { + if(pcAttemptsRemaining) + (*pcAttemptsRemaining) = 0; return SCARD_W_CHV_BLOCKED; + } if(pcAttemptsRemaining) (*pcAttemptsRemaining) = auth_info->tries_left; - return SCARD_W_WRONG_CHV; + return md_translate_OpenSC_to_Windows_error(r, SCARD_W_WRONG_CHV); } logprintf(pCardData, 2, "Pin code correct.\n"); + /* set the session pin according to the minidriver specification */ + if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) { + /* we set it to a special value for pinpad authentication to force a new pinpad authentication */ + if (pcbSessionPin) *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); + if (ppbSessionPin) { + *ppbSessionPin = pCardData->pfnCspAlloc(sizeof(MAGIC_SESSION_PIN)); + if (ppbSessionPin) memcpy(*ppbSessionPin, MAGIC_SESSION_PIN, sizeof(MAGIC_SESSION_PIN)); + } + } else { + if (pcbSessionPin) *pcbSessionPin = 0; + if (ppbSessionPin) *ppbSessionPin = NULL; + } + dwret = md_get_cardcf(pCardData, &cardcf); if (dwret != SCARD_S_SUCCESS) return dwret; @@ -3385,9 +3776,94 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, __in DWORD cRetryCount, __out_opt PDWORD pcAttemptsRemaining) { + 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; + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); - logprintf(pCardData, 1, "CardChangeAuthenticatorEx - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + logprintf(pCardData, 1, "CardChangeAuthenticatorEx\n"); + + if (!pCardData) + 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; + } + if ((dwFlags & PIN_CHANGE_FLAG_UNBLOCK) && (dwFlags & PIN_CHANGE_FLAG_CHANGEPIN)) + 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) + return SCARD_E_INVALID_PARAMETER; + if (dwTargetPinId != ROLE_USER && dwTargetPinId != ROLE_ADMIN) { + logprintf(pCardData, 1, "Only ROLE_USER or ROLE_ADMIN is supported\n"); + return SCARD_E_INVALID_PARAMETER; + } + /* according to the spec: cRetryCount MUST be zero */ + if (cRetryCount) + return SCARD_E_INVALID_PARAMETER; + + logprintf(pCardData, 2, "CardChangeAuthenticatorEx: AuthenticatingPinId=%u, dwFlags=0x%08X, cbAuthenticatingPinData=%u, TargetPinId=%u, cbTargetData=%u, Attempts %s\n", + dwAuthenticatingPinId, dwFlags, cbAuthenticatingPinData, dwTargetPinId, cbTargetData, pcAttemptsRemaining ? "YES" : "NO"); + + + check_reader_status(pCardData); + + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + + if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) { + if (pbAuthenticatingPinData == NULL || cbAuthenticatingPinData == 0) { + logprintf(pCardData, 1, "Invalid current PIN data\n"); + return SCARD_E_INVALID_PARAMETER; + } + + if (pbTargetData == NULL || cbTargetData == 0) { + logprintf(pCardData, 1, "Invalid new PIN data\n"); + return SCARD_E_INVALID_PARAMETER; + } + } + /* using a pin pad */ + if (NULL == pbAuthenticatingPinData) { + if (!(dwFlags & CARD_PIN_SILENT_CONTEXT)) { + DisplayPinpadUI = TRUE; + } + } + + 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; + + 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); + + if (rv) { + logprintf(pCardData, 2, "Failed to %s %s PIN: '%s' (%i)\n", + (dwFlags & PIN_CHANGE_FLAG_CHANGEPIN?"change":"unblock"), + (dwTargetPinId==ROLE_ADMIN?"admin":"user"), sc_strerror(rv), rv); + auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; + if (rv == SC_ERROR_AUTH_METHOD_BLOCKED) { + if(pcAttemptsRemaining) + (*pcAttemptsRemaining) = 0; + return SCARD_W_CHV_BLOCKED; + } + + if(pcAttemptsRemaining) + (*pcAttemptsRemaining) = auth_info->tries_left; + return md_translate_OpenSC_to_Windows_error(rv, SCARD_W_WRONG_CHV); + } + + logprintf(pCardData, 7, "returns success\n"); + return SCARD_S_SUCCESS; } DWORD WINAPI CardDeauthenticateEx(__in PCARD_DATA pCardData, @@ -3415,7 +3891,9 @@ DWORD WINAPI CardDeauthenticateEx(__in PCARD_DATA pCardData, logprintf(pCardData, 1, "CardDeauthenticateEx bPinsFreshness:%d\n", cardcf->bPinsFreshness); /* TODO Reset PKCS#15 PIN object 'validated' flag */ - return SCARD_S_SUCCESS; + + /* force a reset of a card - SCARD_S_SUCCESS does not lead to the reset of the card and leave it still authenticated */ + return SCARD_E_UNSUPPORTED_FEATURE; } DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, @@ -3426,6 +3904,9 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, __out PDWORD pdwDataLen, __in DWORD dwFlags) { + VENDOR_SPECIFIC *vs = NULL; + struct md_pkcs15_container *cont = NULL; + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetContainerProperty\n"); @@ -3440,6 +3921,17 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, return SCARD_E_INVALID_PARAMETER; if (!pbData || !pdwDataLen) return SCARD_E_INVALID_PARAMETER; + 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 */ + vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); + cont = &vs->p15_containers[bContainerIndex]; + + if (!cont->prkey_obj) { + logprintf(pCardData, 7, "Container %i is empty\n", bContainerIndex); + return SCARD_E_NO_KEY_CONTAINER; + } if (wcscmp(CCP_CONTAINER_INFO,wszProperty) == 0) { PCONTAINER_INFO p = (PCONTAINER_INFO) pbData; @@ -3521,7 +4013,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, *pdwDataLen = sizeof(*pCardCapabilities); if (cbData < sizeof(*pCardCapabilities)) return ERROR_INSUFFICIENT_BUFFER; - dwret = md_card_capabilities(pCardCapabilities); + dwret = md_card_capabilities(pCardData, pCardCapabilities); if (dwret != SCARD_S_SUCCESS) return dwret; } @@ -3571,7 +4063,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, } if (pdwDataLen) - *pdwDataLen = cardid->size; + *pdwDataLen = (DWORD) cardid->size; if (cbData < cardid->size) return ERROR_INSUFFICIENT_BUFFER; @@ -3591,7 +4083,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, } if (pdwDataLen) - *pdwDataLen = buf_len; + *pdwDataLen = (DWORD) buf_len; if (cbData < buf_len) return ERROR_INSUFFICIENT_BUFFER; @@ -3664,6 +4156,14 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, return ERROR_INSUFFICIENT_BUFFER; *p = CARD_PIN_STRENGTH_PLAINTEXT; } + else if (wcscmp(CP_KEY_IMPORT_SUPPORT, wszProperty) == 0) { + DWORD *p = (DWORD *)pbData; + if (pdwDataLen) + *pdwDataLen = sizeof(*p); + if (cbData < sizeof(*p)) + return ERROR_INSUFFICIENT_BUFFER; + *p = 0; + } else { logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty); return SCARD_E_INVALID_PARAMETER; @@ -3697,34 +4197,41 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, if (!wszProperty) return SCARD_E_INVALID_PARAMETER; - if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY, wszProperty) == 0 || - wcscmp(CP_CARD_PIN_INFO, wszProperty) == 0) - return SCARD_E_INVALID_PARAMETER; - if (dwFlags) return SCARD_E_INVALID_PARAMETER; - if (wcscmp(CP_PIN_CONTEXT_STRING, wszProperty) == 0) { - vs->wszPinContext = (LPWSTR) pbData; - logprintf(pCardData, 3, "Saved PIN context string: %S\n", pbData); - return SCARD_S_SUCCESS; + if (!cbDataLen) + return SCARD_E_INVALID_PARAMETER; + + /* the following properties cannot be set according to the minidriver specifications */ + if (wcscmp(wszProperty,CP_CARD_FREE_SPACE) == 0 || + wcscmp(wszProperty,CP_CARD_CAPABILITIES) == 0 || + wcscmp(wszProperty,CP_CARD_KEYSIZES) == 0 || + wcscmp(wszProperty,CP_CARD_LIST_PINS) == 0 || + wcscmp(wszProperty,CP_CARD_AUTHENTICATED_STATE) == 0 || + wcscmp(wszProperty,CP_KEY_IMPORT_SUPPORT) == 0 || + wcscmp(wszProperty,CP_ENUM_ALGORITHMS) == 0 || + wcscmp(wszProperty,CP_PADDING_SCHEMES) == 0 || + wcscmp(wszProperty,CP_CHAINING_MODES) == 0 || + wcscmp(wszProperty,CP_SUPPORTS_WIN_X509_ENROLLMENT) == 0 || + wcscmp(wszProperty,CP_CARD_CACHE_MODE) == 0 || + wcscmp(wszProperty,CP_CARD_SERIAL_NO) == 0 + ) { + return SCARD_E_UNSUPPORTED_FEATURE; } - if (wcscmp(CP_CARD_CACHE_MODE, wszProperty) == 0 || - wcscmp(CP_SUPPORTS_WIN_X509_ENROLLMENT, wszProperty) == 0 || - wcscmp(CP_CARD_GUID, wszProperty) == 0 || - wcscmp(CP_CARD_SERIAL_NO, wszProperty) == 0) { - return SCARD_E_INVALID_PARAMETER; + /* the following properties can be set, but are not implemented by the minidriver */ + if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY, wszProperty) == 0 || + wcscmp(CP_CARD_PIN_INFO, wszProperty) == 0 || + wcscmp(CP_CARD_GUID, wszProperty) == 0 ) { + return SCARD_E_UNSUPPORTED_FEATURE; } - if (!pbData || !cbDataLen) - return SCARD_E_INVALID_PARAMETER; - /* This property and CP_PIN_CONTEXT_STRING are set just prior to a call to * CardAuthenticateEx if the PIN required is declared of type ExternalPinType. */ if (wcscmp(CP_PARENT_WINDOW, wszProperty) == 0) { - if (cbDataLen != sizeof(HWND)) { + if (cbDataLen != sizeof(HWND) || !pbData) { return SCARD_E_INVALID_PARAMETER; } else { @@ -3733,15 +4240,278 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, return SCARD_E_INVALID_PARAMETER; vs->hwndParent = cp; } - logprintf(pCardData, 3, "Saved parent window (%u)\n", vs->hwndParent); + logprintf(pCardData, 3, "Saved parent window (%p)\n", vs->hwndParent); + return SCARD_S_SUCCESS; + } + + if (wcscmp(CP_PIN_CONTEXT_STRING, wszProperty) == 0) { + vs->wszPinContext = (PWSTR) pbData; + logprintf(pCardData, 3, "Saved PIN context string: %S\n", (PWSTR) pbData); return SCARD_S_SUCCESS; } - logprintf(pCardData, 3, "INVALID PARAMETER\n"); return SCARD_E_INVALID_PARAMETER; } -DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) + +// 4.8 Secure key injection + + +/** The CardImportSessionKey function imports a temporary session key to the card. +The session key is encrypted with a key exchange key, and the function returns a +handle of the imported session key to the caller.*/ + +DWORD WINAPI CardImportSessionKey( + __in PCARD_DATA pCardData, + __in BYTE bContainerIndex, + __in VOID *pPaddingInfo, + __in LPCWSTR pwszBlobType, + __in LPCWSTR pwszAlgId, + __out CARD_KEY_HANDLE *phKey, + __in_bcount(cbInput) PBYTE pbInput, + __in DWORD cbInput, + __in DWORD dwFlags +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(bContainerIndex); + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(pPaddingInfo); + UNREFERENCED_PARAMETER(pwszBlobType); + UNREFERENCED_PARAMETER(pwszAlgId); + UNREFERENCED_PARAMETER(phKey); + UNREFERENCED_PARAMETER(pbInput); + UNREFERENCED_PARAMETER(cbInput); + UNREFERENCED_PARAMETER(dwFlags); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardImportSessionKey - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** The MDImportSessionKey function imports a temporary session key to the card minidriver +and returns a key handle to the caller.*/ + +DWORD WINAPI MDImportSessionKey( + __in PCARD_DATA pCardData, + __in LPCWSTR pwszBlobType, + __in LPCWSTR pwszAlgId, + __out PCARD_KEY_HANDLE phKey, + __in_bcount(cbInput) PBYTE pbInput, + __in DWORD cbInput +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(pwszBlobType); + UNREFERENCED_PARAMETER(pwszAlgId); + UNREFERENCED_PARAMETER(phKey); + UNREFERENCED_PARAMETER(pbInput); + UNREFERENCED_PARAMETER(cbInput); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "MDImportSessionKey - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** The MDEncryptData function uses a key handle to encrypt data with a symmetric key. +The data is encrypted in a format that the smart card supports.*/ + +DWORD WINAPI MDEncryptData( + __in PCARD_DATA pCardData, + __in CARD_KEY_HANDLE hKey, + __in LPCWSTR pwszSecureFunction, + __in_bcount(cbInput) PBYTE pbInput, + __in DWORD cbInput, + __in DWORD dwFlags, + __deref_out_ecount(*pcEncryptedData) + PCARD_ENCRYPTED_DATA *ppEncryptedData, + __out PDWORD pcEncryptedData +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(hKey); + UNREFERENCED_PARAMETER(pwszSecureFunction); + UNREFERENCED_PARAMETER(pbInput); + UNREFERENCED_PARAMETER(cbInput); + UNREFERENCED_PARAMETER(dwFlags); + UNREFERENCED_PARAMETER(ppEncryptedData); + UNREFERENCED_PARAMETER(pcEncryptedData); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "MDEncryptData - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + + +/** The CardGetSharedKeyHandle function returns a session key handle to the caller. +Note: The manner in which this session key has been established is outside the +scope of this specification. For example, the session key could be established +by either a permanent shared key or a key derivation algorithm that has occurred +before the call to CardGetSharedKeyHandle.*/ + +DWORD WINAPI CardGetSharedKeyHandle( + __in PCARD_DATA pCardData, + __in_bcount(cbInput) PBYTE pbInput, + __in DWORD cbInput, + __deref_opt_out_bcount(*pcbOutput) + PBYTE *ppbOutput, + __out_opt PDWORD pcbOutput, + __out PCARD_KEY_HANDLE phKey +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(pbInput); + UNREFERENCED_PARAMETER(cbInput); + UNREFERENCED_PARAMETER(ppbOutput); + UNREFERENCED_PARAMETER(pcbOutput); + UNREFERENCED_PARAMETER(phKey); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardGetSharedKeyHandle - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** The CardDestroyKey function releases a temporary key on the card. The card +should delete all of the key material that is associated with that key handle.*/ + +DWORD WINAPI CardDestroyKey( + __in PCARD_DATA pCardData, + __in CARD_KEY_HANDLE hKey +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(hKey); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardDestroyKey - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** This function can be used to get properties for a cryptographic algorithm.*/ +DWORD WINAPI CardGetAlgorithmProperty ( + __in PCARD_DATA pCardData, + __in LPCWSTR pwszAlgId, + __in LPCWSTR pwszProperty, + __out_bcount_part_opt(cbData, *pdwDataLen) + PBYTE pbData, + __in DWORD cbData, + __out PDWORD pdwDataLen, + __in DWORD dwFlags +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(pwszAlgId); + UNREFERENCED_PARAMETER(pwszProperty); + UNREFERENCED_PARAMETER(pbData); + UNREFERENCED_PARAMETER(cbData); + UNREFERENCED_PARAMETER(pdwDataLen); + UNREFERENCED_PARAMETER(dwFlags); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardGetAlgorithmProperty - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** This function is used to get the properties of a key.*/ +DWORD WINAPI CardGetKeyProperty( + __in PCARD_DATA pCardData, + __in CARD_KEY_HANDLE hKey, + __in LPCWSTR pwszProperty, + __out_bcount_part_opt(cbData, *pdwDataLen) PBYTE pbData, + __in DWORD cbData, + __out PDWORD pdwDataLen, + __in DWORD dwFlags + ) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(hKey); + UNREFERENCED_PARAMETER(pwszProperty); + UNREFERENCED_PARAMETER(pbData); + UNREFERENCED_PARAMETER(cbData); + UNREFERENCED_PARAMETER(pdwDataLen); + UNREFERENCED_PARAMETER(dwFlags); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardGetKeyProperty - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** This function is used to set the properties of a key.*/ +DWORD WINAPI CardSetKeyProperty( + __in PCARD_DATA pCardData, + __in CARD_KEY_HANDLE hKey, + __in LPCWSTR pwszProperty, + __in_bcount(cbInput) PBYTE pbInput, + __in DWORD cbInput, + __in DWORD dwFlags +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(dwFlags); + UNREFERENCED_PARAMETER(hKey); + UNREFERENCED_PARAMETER(pwszProperty); + UNREFERENCED_PARAMETER(pbInput); + UNREFERENCED_PARAMETER(cbInput); + UNREFERENCED_PARAMETER(dwFlags); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardSetKeyProperty - unsupported\n"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +/** CardProcessEncryptedData processes a set of encrypted data BLOBs by +sending them to the card where the data BLOBs are decrypted.*/ + +DWORD WINAPI CardProcessEncryptedData( + __in PCARD_DATA pCardData, + __in CARD_KEY_HANDLE hKey, + __in LPCWSTR pwszSecureFunction, + __in_ecount(cEncryptedData) + PCARD_ENCRYPTED_DATA pEncryptedData, + __in DWORD cEncryptedData, + __out_bcount_part_opt(cbOutput, *pdwOutputLen) + PBYTE pbOutput, + __in DWORD cbOutput, + __out_opt PDWORD pdwOutputLen, + __in DWORD dwFlags +) +{ + UNREFERENCED_PARAMETER(pCardData); + UNREFERENCED_PARAMETER(hKey); + UNREFERENCED_PARAMETER(pwszSecureFunction); + UNREFERENCED_PARAMETER(pEncryptedData); + UNREFERENCED_PARAMETER(cEncryptedData); + UNREFERENCED_PARAMETER(pbOutput); + UNREFERENCED_PARAMETER(cbOutput); + UNREFERENCED_PARAMETER(pdwOutputLen); + UNREFERENCED_PARAMETER(dwFlags); + logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData); + logprintf(pCardData, 1, "CardProcessEncryptedData - unsupported\n"); + 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; @@ -3750,9 +4520,44 @@ DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) return SCARD_E_INVALID_PARAMETER; if (dwFlags) return SCARD_E_INVALID_PARAMETER; + if (!(dwFlags & CARD_SECURE_KEY_INJECTION_NO_CARD_MODE)) { + if( pCardData->hSCardCtx == 0) { + logprintf(pCardData, 0, "Invalide handle.\n"); + return SCARD_E_INVALID_HANDLE; + } + if( pCardData->hScard == 0) { + logprintf(pCardData, 0, "Invalide handle.\n"); + return SCARD_E_INVALID_HANDLE; + } + } + else + { + /* secure key injection not supported */ + return SCARD_E_UNSUPPORTED_FEATURE; + } + + if (pCardData->pbAtr == NULL) + return SCARD_E_INVALID_PARAMETER; + if ( pCardData->pwszCardName == NULL ) + return SCARD_E_INVALID_PARAMETER; + /* <2 lenght 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 */ + if (pCardData->pbAtr[0] == 0xFF || pCardData->pbAtr[0] == 0x00) + return SCARD_E_UNKNOWN_CARD; + /* Memory management functions */ + if ( ( pCardData->pfnCspAlloc == NULL ) || + ( pCardData->pfnCspReAlloc == NULL ) || + ( pCardData->pfnCspFree == NULL ) ) + return SCARD_E_INVALID_PARAMETER; + + /* The lowest supported version is 4 - maximum is 7. */ + if (pCardData->dwVersion < MD_MINIMUM_VERSION_SUPPORTED) + return (DWORD) ERROR_REVISION_MISMATCH; suppliedVersion = pCardData->dwVersion; - + /* VENDOR SPECIFIC */ vs = pCardData->pvVendorSpecific = pCardData->pfnCspAlloc(sizeof(VENDOR_SPECIFIC)); memset(vs, 0, sizeof(VENDOR_SPECIFIC)); @@ -3765,22 +4570,16 @@ DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) vs->hScard = pCardData->hScard; vs->hSCardCtx = pCardData->hSCardCtx; - /* The lowest supported version is 4. */ - if (pCardData->dwVersion < MD_MINIMUM_VERSION_SUPPORTED) - return (DWORD) ERROR_REVISION_MISMATCH; - - if( pCardData->hScard == 0) { - logprintf(pCardData, 0, "Invalide handle.\n"); - return SCARD_E_INVALID_HANDLE; - } - logprintf(pCardData, 2, "request version pCardData->dwVersion = %d\n", pCardData->dwVersion); pCardData->dwVersion = min(pCardData->dwVersion, MD_CURRENT_VERSION_SUPPORTED); logprintf(pCardData, 2, "pCardData->dwVersion = %d\n", pCardData->dwVersion); dwret = md_create_context(pCardData, vs); - if (dwret != SCARD_S_SUCCESS) + if (dwret != SCARD_S_SUCCESS) { + pCardData->pfnCspFree(pCardData->pvVendorSpecific); + pCardData->pvVendorSpecific = NULL; return dwret; + } md_static_data.flags &= ~MD_STATIC_FLAG_CONTEXT_DELETED; pCardData->pfnCardDeleteContext = CardDeleteContext; @@ -3793,7 +4592,8 @@ DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) pCardData->pfnCardAuthenticateChallenge = CardAuthenticateChallenge; pCardData->pfnCardUnblockPin = CardUnblockPin; pCardData->pfnCardChangeAuthenticator = CardChangeAuthenticator; - pCardData->pfnCardDeauthenticate = CardDeauthenticate; /* NULL */ + /* the minidriver does not perform a deauthentication - set it to NULL according to the specification */ + pCardData->pfnCardDeauthenticate = NULL; pCardData->pfnCardCreateDirectory = CardCreateDirectory; pCardData->pfnCardDeleteDirectory = CardDeleteDirectory; pCardData->pvUnused3 = NULL; @@ -3811,22 +4611,28 @@ DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) pCardData->pfnCardConstructDHAgreement = CardConstructDHAgreement; dwret = associate_card(pCardData); - if (dwret != SCARD_S_SUCCESS) + if (dwret != SCARD_S_SUCCESS) { + pCardData->pfnCspFree(pCardData->pvVendorSpecific); + pCardData->pvVendorSpecific = NULL; return dwret; + } dwret = md_fs_init(pCardData); - if (dwret != SCARD_S_SUCCESS) + if (dwret != SCARD_S_SUCCESS) { + pCardData->pfnCspFree(pCardData->pvVendorSpecific); + pCardData->pvVendorSpecific = NULL; return dwret; + } logprintf(pCardData, 1, "OpenSC init done.\n"); + logprintf(pCardData, 1, "Supplied version %u - version used %u.\n", suppliedVersion, pCardData->dwVersion); - if (suppliedVersion > 4) { + if (pCardData->dwVersion >= CARD_DATA_VERSION_FIVE) { pCardData->pfnCardDeriveKey = CardDeriveKey; pCardData->pfnCardDestroyDHAgreement = CardDestroyDHAgreement; pCardData->pfnCspGetDHAgreement = CspGetDHAgreement; - if (suppliedVersion > 5 ) { - logprintf(pCardData, 1, "Supplied version %i.\n", suppliedVersion); + if (pCardData->dwVersion >= CARD_DATA_VERSION_SIX) { pCardData->pfnCardGetChallengeEx = CardGetChallengeEx; pCardData->pfnCardAuthenticateEx = CardAuthenticateEx; @@ -3836,6 +4642,19 @@ DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags) pCardData->pfnCardSetContainerProperty = CardSetContainerProperty; pCardData->pfnCardGetProperty = CardGetProperty; pCardData->pfnCardSetProperty = CardSetProperty; + if (pCardData->dwVersion >= CARD_DATA_VERSION_SEVEN) { + + pCardData->pfnMDImportSessionKey = MDImportSessionKey; + pCardData->pfnMDEncryptData = MDEncryptData; + pCardData->pfnCardImportSessionKey = CardImportSessionKey; + pCardData->pfnCardGetSharedKeyHandle = CardGetSharedKeyHandle; + pCardData->pfnCardGetAlgorithmProperty = CardGetAlgorithmProperty; + pCardData->pfnCardGetKeyProperty = CardGetKeyProperty; + pCardData->pfnCardSetKeyProperty = CardSetKeyProperty; + pCardData->pfnCardProcessEncryptedData = CardProcessEncryptedData; + pCardData->pfnCardDestroyKey = CardDestroyKey; + pCardData->pfnCardCreateContainerEx = CardCreateContainerEx; + } } } @@ -3952,7 +4771,7 @@ static int disassociate_card(PCARD_DATA pCardData) } -BOOL APIENTRY DllMain( HMODULE hModule, +BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved ) @@ -3961,7 +4780,7 @@ BOOL APIENTRY DllMain( HMODULE hModule, CHAR name[MAX_PATH + 1] = "\0"; char *reason = ""; - GetModuleFileName(GetModuleHandle(NULL),name,MAX_PATH); + GetModuleFileNameA(GetModuleHandle(NULL),name,MAX_PATH); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: @@ -3978,12 +4797,13 @@ BOOL APIENTRY DllMain( HMODULE hModule, break; } - logprintf(NULL,8,"\n********** DllMain Module(handle:0x%X) '%s'; reason='%s'; Reserved=%p; P:%d; T:%d\n", - hModule, name, reason, lpReserved, GetCurrentProcessId(), GetCurrentThreadId()); + logprintf(NULL,8,"\n********** DllMain Module(handle:0x%p) '%s'; reason='%s'; Reserved=%p; P:%d; T:%d\n", + hinstDLL, name, reason, lpReserved, GetCurrentProcessId(), GetCurrentThreadId()); #endif switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: + g_inst = hinstDLL; md_static_data.attach_check = MD_STATIC_PROCESS_ATTACHED; break; case DLL_PROCESS_DETACH: diff --git a/src/minidriver/versioninfo-minidriver.rc.in b/src/minidriver/versioninfo-minidriver.rc.in index cc02a9a0..f80f165f 100644 --- a/src/minidriver/versioninfo-minidriver.rc.in +++ b/src/minidriver/versioninfo-minidriver.rc.in @@ -1,5 +1,12 @@ #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 + 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@ @@ -36,3 +43,14 @@ BEGIN 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 + +IDI_LOGO ICON "..\\..\\win32\\OpenSC.ico" diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index a4ef46f0..52f5a082 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -498,7 +498,7 @@ CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) data.pin_type = SC_AC_CHV; data.pin_reference = pin_info->attrs.pin.reference; - r = sc_pin_cmd(slot->card->card, &data, NULL); + r = sc_pin_cmd(slot->p11card->card, &data, NULL); if (r == SC_SUCCESS) { if (data.pin1.max_tries > 0) pin_info->max_tries = data.pin1.max_tries; @@ -867,7 +867,7 @@ check_cert_data_read(struct pkcs15_fw_data *fw_data, struct pkcs15_cert_object * /* now that we have the cert and pub key, lets see if we can bind anything else */ pkcs15_bind_related_objects(fw_data); - return 0; + return rv; } @@ -906,7 +906,7 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot, struct pkcs15_any_object *obj, case SC_PKCS15_TYPE_PRKEY_GOSTR3410: case SC_PKCS15_TYPE_PRKEY_EC: pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); - card_fw_data = (struct pkcs15_fw_data *) slot->card->fws_data[slot->fw_data_idx]; + card_fw_data = (struct pkcs15_fw_data *) slot->p11card->fws_data[slot->fw_data_idx]; for (i = 0; i < card_fw_data->num_objects; i++) { struct pkcs15_any_object *obj2 = card_fw_data->objects[i]; struct pkcs15_cert_object *cert; @@ -1224,7 +1224,7 @@ _add_public_objects(struct sc_pkcs11_slot *slot, struct pkcs15_fw_data *fw_data, * even if there is an auth_id to allow writting for example. * See bug issue #291 * treat pubkey and cert as readable.a - */ + */ if (obj->p15_object->auth_id.len && !(is_pubkey(obj) || is_cert(obj))) continue; @@ -1394,7 +1394,7 @@ static CK_RV pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15_card *p15card = NULL; struct sc_pkcs15_object *auth_object = NULL; @@ -1568,7 +1568,7 @@ pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType, static CK_RV pkcs15_logout(struct sc_pkcs11_slot *slot) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; CK_RV ret = CKR_OK; int rc; @@ -1608,7 +1608,7 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct sc_pkcs15_card *p15card = NULL; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15_auth_info *auth_info = NULL; @@ -1685,7 +1685,7 @@ pkcs15_initialize(struct sc_pkcs11_slot *slot, void *ptr, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct sc_cardctl_pkcs11_init_token args; scconf_block *atrblock = NULL; int rc, enable_InitToken = 0; @@ -1811,7 +1811,7 @@ pkcs15_initialize(struct sc_pkcs11_slot *slot, void *ptr, static CK_RV pkcs15_init_pin(struct sc_pkcs11_slot *slot, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_pinargs args; struct sc_profile *profile = NULL; @@ -1911,7 +1911,7 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_prkeyargs args; struct pkcs15_any_object *key_any_obj = NULL; @@ -2031,7 +2031,7 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil } /* CKA_VALUE arrives in little endian form. pkcs15init framework expects it in a big endian one. */ rc = sc_mem_reverse(gost->d.data, gost->d.len); - if (rv) { + if (rc != SC_SUCCESS) { rv = sc_to_cryptoki_error(rc, "C_CreateObject"); goto out; } @@ -2065,7 +2065,7 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_skeyargs args; struct pkcs15_any_object *key_any_obj = NULL; @@ -2087,7 +2087,9 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile return rv; /* CKA_TOKEN defaults to false */ - attr_find(pTemplate, ulCount, CKA_TOKEN, &_token, NULL); + rv = attr_find(pTemplate, ulCount, CKA_TOKEN, &_token, NULL); + if (rv != CKR_OK) + return rv; switch (key_type) { /* Only support GENERIC_SECRET for now */ @@ -2213,7 +2215,7 @@ static CK_RV pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_pubkeyargs args; struct pkcs15_any_object *key_any_obj = NULL; @@ -2274,6 +2276,18 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile bn = &rsa->modulus; break; case CKA_PUBLIC_EXPONENT: bn = &rsa->exponent; break; + case CKA_VERIFY: + args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_VERIFY); + break; + case CKA_VERIFY_RECOVER: + args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER); + break; + case CKA_ENCRYPT: + args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_ENCRYPT); + break; + case CKA_WRAP: + args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_WRAP); + break; default: /* ignore unknown attrs, or flag error? */ continue; @@ -2308,7 +2322,7 @@ pkcs15_create_certificate(struct sc_pkcs11_slot *slot, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_certargs args; struct pkcs15_any_object *cert_any_obj = NULL; @@ -2390,7 +2404,7 @@ pkcs15_create_data(struct sc_pkcs11_slot *slot, struct sc_profile *profile, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_pkcs15init_dataargs args; struct pkcs15_any_object *data_any_obj = NULL; @@ -2478,7 +2492,7 @@ static CK_RV pkcs15_create_object(struct sc_pkcs11_slot *slot, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_profile *profile = NULL; CK_OBJECT_CLASS _class; @@ -2665,7 +2679,7 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE_PTR phPubKey, CK_OBJECT_HANDLE_PTR phPrivKey) /* gets priv. key handle */ { struct sc_profile *profile = NULL; - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct sc_pkcs15_auth_info *pin = NULL; struct sc_aid *aid = NULL; struct pkcs15_fw_data *fw_data = NULL; @@ -2749,10 +2763,10 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism, /* TODO: check allowed values of keybits */ } else if (keytype == CKK_EC) { - struct sc_pkcs15_der *der = &keygen_args.prkey_args.params.ec.der; + struct sc_lv_data *der = &keygen_args.prkey_args.key.u.ec.params.der; der->len = sizeof(struct sc_object_id); - rv = attr_find_ptr(pPubTpl, ulPubCnt, CKA_EC_PARAMS, (void **)&der->value, &der->len); + rv = attr_find_and_allocate_ptr(pPubTpl, ulPubCnt, CKA_EC_PARAMS, (void **)&der->value, &der->len); if (rv != CKR_OK) { sc_unlock(p11card->card); return sc_to_cryptoki_error(rc, "C_GenerateKeyPair"); @@ -2850,7 +2864,7 @@ pkcs15_skey_destroy(struct sc_pkcs11_session *session, void *object) return CKR_FUNCTION_NOT_SUPPORTED; #else struct pkcs15_any_object *any_obj = (struct pkcs15_any_object*) object; - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; int rv; @@ -2886,7 +2900,7 @@ pkcs15_any_destroy(struct sc_pkcs11_session *session, void *object) struct pkcs15_data_object *obj = (struct pkcs15_data_object*) object; struct pkcs15_any_object *any_obj = (struct pkcs15_any_object*) object; struct sc_pkcs11_slot *slot = session->slot; - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_aid *aid = NULL; struct sc_profile *profile = NULL; @@ -2967,7 +2981,7 @@ pkcs15_any_destroy(struct sc_pkcs11_session *session, void *object) static CK_RV pkcs15_get_random(struct sc_pkcs11_slot *slot, CK_BYTE_PTR p, CK_ULONG len) { - struct sc_pkcs11_card *p11card = slot->card; + struct sc_pkcs11_card *p11card = slot->p11card; struct pkcs15_fw_data *fw_data = NULL; int rc; @@ -3012,7 +3026,7 @@ pkcs15_set_attrib(struct sc_pkcs11_session *session, struct sc_pkcs15_object *p1 #else struct sc_profile *profile = NULL; struct sc_pkcs11_slot *slot = session->slot; - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct sc_aid *aid = NULL; struct sc_pkcs15_id id; @@ -3109,7 +3123,7 @@ pkcs15_cert_get_attribute(struct sc_pkcs11_session *session, void *object, CK_AT size_t len; sc_log(context, "pkcs15_cert_get_attribute() called"); - p11card = session->slot->card; + p11card = session->slot->p11card; fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx]; if (!fw_data) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); @@ -3201,7 +3215,7 @@ pkcs15_cert_cmp_attribute(struct sc_pkcs11_session *session, void *object, CK_ATTRIBUTE_PTR attr) { struct pkcs15_cert_object *cert = (struct pkcs15_cert_object*) object; - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; const unsigned char *data = NULL, *_data = NULL; size_t len, _len; @@ -3304,7 +3318,7 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session, size_t len; sc_log(context, "pkcs15_prkey_get_attribute() called"); - p11card = session->slot->card; + p11card = session->slot->p11card; fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx]; if (!fw_data) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); @@ -3368,14 +3382,26 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session, *(CK_OBJECT_CLASS*)attr->pValue = CKO_PRIVATE_KEY; break; case CKA_TOKEN: - case CKA_LOCAL: - case CKA_SENSITIVE: - case CKA_ALWAYS_SENSITIVE: - case CKA_NEVER_EXTRACTABLE: check_attribute_buffer(attr, sizeof(CK_BBOOL)); *(CK_BBOOL*)attr->pValue = TRUE; break; - case CKA_ALWAYS_AUTHENTICATE: + case CKA_ALWAYS_SENSITIVE: + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + *(CK_BBOOL*)attr->pValue = (prkey->prv_info->access_flags & SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE) != 0; + break; + case CKA_NEVER_EXTRACTABLE: + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + *(CK_BBOOL*)attr->pValue = (prkey->prv_info->access_flags & SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE) != 0; + break; + case CKA_SENSITIVE: + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + *(CK_BBOOL*)attr->pValue = (prkey->prv_info->access_flags & SC_PKCS15_PRKEY_ACCESS_SENSITIVE) != 0; + break; + case CKA_LOCAL: + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + *(CK_BBOOL*)attr->pValue = (prkey->prv_info->access_flags & SC_PKCS15_PRKEY_ACCESS_LOCAL) != 0; + break; + case CKA_ALWAYS_AUTHENTICATE: check_attribute_buffer(attr, sizeof(CK_BBOOL)); *(CK_BBOOL*)attr->pValue = prkey->prv_p15obj->user_consent; break; @@ -3417,14 +3443,10 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session, check_attribute_buffer(attr, sizeof(CK_MECHANISM_TYPE)); *(CK_MECHANISM_TYPE*)attr->pValue = CK_UNAVAILABLE_INFORMATION; break; - case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN: case CKA_SIGN_RECOVER: - case CKA_WRAP: case CKA_UNWRAP: - case CKA_VERIFY: - case CKA_VERIFY_RECOVER: case CKA_DERIVE: case CKA_OPENSC_NON_REPUDIATION: /* TODO seems to be obsolete */ @@ -3438,10 +3460,12 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session, check_attribute_buffer(attr, sizeof(CK_ULONG)); switch (prkey->prv_p15obj->type) { case SC_PKCS15_TYPE_PRKEY_EC: - if (key && key->u.ec.params.field_length > 0) - *(CK_ULONG *) attr->pValue = key->u.ec.params.field_length; - else - *(CK_ULONG *) attr->pValue = (key->u.ec.ecpointQ.len - 1) / 2 *8; + if (key) { + if (key->u.ec.params.field_length > 0) + *(CK_ULONG *) attr->pValue = key->u.ec.params.field_length; + else + *(CK_ULONG *) attr->pValue = (key->u.ec.ecpointQ.len - 1) / 2 *8; + } return CKR_OK; default: *(CK_ULONG *) attr->pValue = prkey->prv_info->modulus_length; @@ -3484,7 +3508,7 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, CK_ULONG_PTR pulDataLen) { struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj; - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; int rv, flags = 0, prkey_has_path = 0; unsigned sign_flags = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER @@ -3585,7 +3609,7 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct pkcs15_prkey_object *prkey; unsigned char decrypted[256]; /* FIXME: Will not work for keys above 2048 bits */ @@ -3656,7 +3680,7 @@ pkcs15_prkey_derive(struct sc_pkcs11_session *session, void *obj, CK_BYTE_PTR pParameters, CK_ULONG ulParametersLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj; int need_unlock = 0, prkey_has_path = 0; @@ -3728,7 +3752,7 @@ static CK_RV pkcs15_prkey_can_do(struct sc_pkcs11_session *session, void *obj, CK_MECHANISM_TYPE mech_type, unsigned int flags) { - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj; struct sc_pkcs15_prkey_info *pkinfo = NULL; @@ -3822,7 +3846,7 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ sc_log(context, "pkcs15_pubkey_get_attribute() called"); - p11card = session->slot->card; + p11card = session->slot->p11card; cert = pubkey->pub_genfrom; fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx]; @@ -3837,8 +3861,8 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ case CKA_EC_PARAMS: case CKA_EC_POINT: if (pubkey->pub_data == NULL) - /* FIXME: check the return value? */ - check_cert_data_read(fw_data, cert); + if (SC_SUCCESS != check_cert_data_read(fw_data, cert)) + return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "check_cert_data_read"); break; } @@ -3848,13 +3872,17 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ *(CK_OBJECT_CLASS*)attr->pValue = CKO_PUBLIC_KEY; break; case CKA_TOKEN: - case CKA_LOCAL: case CKA_SENSITIVE: - case CKA_ALWAYS_SENSITIVE: - case CKA_NEVER_EXTRACTABLE: check_attribute_buffer(attr, sizeof(CK_BBOOL)); *(CK_BBOOL*)attr->pValue = TRUE; break; + case CKA_LOCAL: + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + if (pubkey->pub_info) + *(CK_BBOOL*)attr->pValue = (pubkey->pub_info->access_flags & SC_PKCS15_PRKEY_ACCESS_LOCAL) != 0; + else /* no pub_info structure, falling back to TRUE */ + *(CK_BBOOL*)attr->pValue = TRUE; + break; case CKA_PRIVATE: check_attribute_buffer(attr, sizeof(CK_BBOOL)); if (pubkey->pub_p15obj) @@ -3913,11 +3941,7 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ *(CK_MECHANISM_TYPE*)attr->pValue = CK_UNAVAILABLE_INFORMATION; break; case CKA_ENCRYPT: - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_SIGN_RECOVER: case CKA_WRAP: - case CKA_UNWRAP: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_DERIVE: @@ -3948,7 +3972,17 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ if (sc_pkcs15_encode_pubkey(context, pubkey->pub_data, &value, &len)) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); - check_attribute_buffer(attr, len); + if (attr->pValue == NULL_PTR) { + attr->ulValueLen = len; + free(value); + return CKR_OK; + } + if (attr->ulValueLen < len) { + attr->ulValueLen = len; + free(value); + return CKR_BUFFER_TOO_SMALL; + } + attr->ulValueLen = len; memcpy(attr->pValue, value, len); free(value); @@ -4020,9 +4054,9 @@ pkcs15_dobj_get_value(struct sc_pkcs11_session *session, struct pkcs15_data_object *dobj, struct sc_pkcs15_data **out_data) { - struct sc_pkcs11_card *p11card = session->slot->card; + struct sc_pkcs11_card *p11card = session->slot->p11card; struct pkcs15_fw_data *fw_data = NULL; - struct sc_card *card = session->slot->card->card; + struct sc_card *card = session->slot->p11card->card; int rv; if (!out_data) @@ -4355,7 +4389,7 @@ get_public_exponent(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr) static CK_RV get_ec_pubkey_params(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr) { - struct sc_ec_params * ecp; + struct sc_ec_parameters *ecp; if (key == NULL) return CKR_ATTRIBUTE_TYPE_INVALID; @@ -4372,10 +4406,10 @@ get_ec_pubkey_params(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr) return CKR_OK; } - ecp = (struct sc_ec_params *) key->alg_id->params; - if (ecp && ecp->der && ecp->der_len) { - check_attribute_buffer(attr, ecp->der_len); - memcpy(attr->pValue, ecp->der, ecp->der_len); + ecp = (struct sc_ec_parameters *) key->alg_id->params; + if (ecp && ecp->der.value && ecp->der.len) { + check_attribute_buffer(attr, ecp->der.len); + memcpy(attr->pValue, ecp->der.value, ecp->der.len); return CKR_OK; } } @@ -4485,7 +4519,7 @@ register_gost_mechanisms(struct sc_pkcs11_card *p11card, int flags) if (flags & SC_ALGORITHM_GOSTR3410_HASH_NONE) { mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410, - &mech_info, CKK_GOSTR3410, NULL); + &mech_info, CKK_GOSTR3410, NULL, NULL); if (!mt) return CKR_HOST_MEMORY; rc = sc_pkcs11_register_mechanism(p11card, mt); @@ -4494,7 +4528,7 @@ register_gost_mechanisms(struct sc_pkcs11_card *p11card, int flags) } if (flags & SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411) { mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410_WITH_GOSTR3411, - &mech_info, CKK_GOSTR3410, NULL); + &mech_info, CKK_GOSTR3410, NULL, NULL); if (!mt) return CKR_HOST_MEMORY; rc = sc_pkcs11_register_mechanism(p11card, mt); @@ -4504,14 +4538,14 @@ register_gost_mechanisms(struct sc_pkcs11_card *p11card, int flags) if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) { mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR; mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410_KEY_PAIR_GEN, - &mech_info, CKK_GOSTR3410, NULL); + &mech_info, CKK_GOSTR3410, NULL, NULL); if (!mt) return CKR_HOST_MEMORY; rc = sc_pkcs11_register_mechanism(p11card, mt); if (rc != CKR_OK) return rc; } - + return CKR_OK; } @@ -4533,7 +4567,7 @@ static int register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags, if (ext_flags & SC_ALGORITHM_EXT_EC_NAMEDCURVE) ec_flags |= CKF_EC_NAMEDCURVE; if (ext_flags & SC_ALGORITHM_EXT_EC_UNCOMPRESES) - ec_flags |= CKF_EC_UNCOMPRESES; + ec_flags |= CKF_EC_UNCOMPRESS; if (ext_flags & SC_ALGORITHM_EXT_EC_COMPRESS) ec_flags |= CKF_EC_COMPRESS; @@ -4542,46 +4576,51 @@ static int register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags, mech_info.ulMinKeySize = min_key_size; mech_info.ulMaxKeySize = max_key_size; - mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL); - if (!mt) - return CKR_HOST_MEMORY; - rc = sc_pkcs11_register_mechanism(p11card, mt); - if (rc != CKR_OK) - return rc; + if(flags & SC_ALGORITHM_ECDSA_HASH_NONE) { + mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } -#if ENABLE_OPENSSL - mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, - &mech_info, CKK_EC, NULL); - if (!mt) - return CKR_HOST_MEMORY; - rc = sc_pkcs11_register_mechanism(p11card, mt); - if (rc != CKR_OK) - return rc; +#ifdef ENABLE_OPENSSL + if(flags & SC_ALGORITHM_ECDSA_HASH_SHA1) { + mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, &mech_info, CKK_EC, NULL, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } #endif /* ADD ECDH mechanisms */ /* The PIV uses curves where CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE produce the same results */ - mech_info.flags &= ~CKF_SIGN; - mech_info.flags |= CKF_DERIVE; + if(flags & SC_ALGORITHM_ECDH_CDH_RAW) { + mech_info.flags &= ~CKF_SIGN; + mech_info.flags |= CKF_DERIVE; - mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE, &mech_info, CKK_EC, NULL); - if (!mt) - return CKR_HOST_MEMORY; - rc = sc_pkcs11_register_mechanism(p11card, mt); - if (rc != CKR_OK) - return rc; + mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE, &mech_info, CKK_EC, NULL, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; - mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC, NULL); - if (!mt) - return CKR_HOST_MEMORY; - rc = sc_pkcs11_register_mechanism(p11card, mt); - if (rc != CKR_OK) - return rc; + mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC, NULL, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) { mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR; mech_info.flags |= ec_flags; - mt = sc_pkcs11_new_fw_mechanism(CKM_EC_KEY_PAIR_GEN, &mech_info, CKK_EC, NULL); + mt = sc_pkcs11_new_fw_mechanism(CKM_EC_KEY_PAIR_GEN, &mech_info, CKK_EC, NULL, NULL); if (!mt) return CKR_HOST_MEMORY; rc = sc_pkcs11_register_mechanism(p11card, mt); @@ -4607,7 +4646,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) unsigned long ec_ext_flags; sc_pkcs11_mechanism_type_t *mt; unsigned int num; - int rc, flags = 0; + int rc, rsa_flags = 0, ec_flags = 0, gostr_flags = 0; /* Register generic mechanisms */ sc_pkcs11_register_generic_mechanisms(p11card); @@ -4625,14 +4664,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) /* For now, we just OR all the algorithm specific * flags, based on the assumption that cards don't - * support different modes for different key sizes - * But we need to do this by type of key as - * each has different min/max and different flags. - * - * TODO: -DEE This code assumed RSA, but the GOST - * and EC code was forced in. There should be a - * routine for each key type. - */ + * support different modes for different key *sizes*. */ num = card->algorithm_count; alg_info = card->algorithms; while (num--) { @@ -4642,67 +4674,69 @@ register_mechanisms(struct sc_pkcs11_card *p11card) mech_info.ulMinKeySize = alg_info->key_length; if (alg_info->key_length > mech_info.ulMaxKeySize) mech_info.ulMaxKeySize = alg_info->key_length; - flags |= alg_info->flags; + rsa_flags |= alg_info->flags; break; case SC_ALGORITHM_EC: if (alg_info->key_length < ec_min_key_size) ec_min_key_size = alg_info->key_length; if (alg_info->key_length > ec_max_key_size) ec_max_key_size = alg_info->key_length; - flags |= alg_info->flags; + ec_flags |= alg_info->flags; ec_ext_flags |= alg_info->u._ec.ext_flags; break; case SC_ALGORITHM_GOSTR3410: - flags |= alg_info->flags; + gostr_flags |= alg_info->flags; break; } alg_info++; } - if (flags & SC_ALGORITHM_ECDSA_RAW) - rc = register_ec_mechanisms(p11card, flags, ec_ext_flags, ec_min_key_size, ec_max_key_size); + if (ec_flags & SC_ALGORITHM_ECDSA_RAW) { + rc = register_ec_mechanisms(p11card, ec_flags, ec_ext_flags, ec_min_key_size, ec_max_key_size); + if (rc != CKR_OK) + return rc; + } - if (flags & (SC_ALGORITHM_GOSTR3410_RAW + if (gostr_flags & (SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_GOSTR3410_HASH_NONE | SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411)) { - if (flags & SC_ALGORITHM_GOSTR3410_RAW) - flags |= SC_ALGORITHM_GOSTR3410_HASH_NONE; - rc = register_gost_mechanisms(p11card, flags); + if (gostr_flags & SC_ALGORITHM_GOSTR3410_RAW) + gostr_flags |= SC_ALGORITHM_GOSTR3410_HASH_NONE; + rc = register_gost_mechanisms(p11card, gostr_flags); if (rc != CKR_OK) return rc; } /* Check if we support raw RSA */ - if (flags & SC_ALGORITHM_RSA_RAW) { - mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, &mech_info, CKK_RSA, NULL); + if (rsa_flags & SC_ALGORITHM_RSA_RAW) { + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, &mech_info, CKK_RSA, NULL, NULL); rc = sc_pkcs11_register_mechanism(p11card, mt); if (rc != CKR_OK) return rc; + /* We support PKCS1 padding in software */ + /* either the card supports it or OpenSC does */ + rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; } - /* We support PKCS1 padding in software */ - /* either the card supports it or OpenSC does */ - flags |= SC_ALGORITHM_RSA_PAD_PKCS1; - #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 lists the hashs, will we * help it a little, by adding all the OpenSSL hashes * that have PKCS#11 mechanisms. - */ - if (!(flags & SC_ALGORITHM_RSA_HASHES)) { - flags |= SC_ALGORITHM_RSA_HASHES; + */ + if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { + rsa_flags |= SC_ALGORITHM_RSA_HASHES; #if OPENSSL_VERSION_NUMBER < 0x00908000L /* turn off hashes not in openssl 0.9.8 */ - flags &= ~(SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512 | SC_ALGORITHM_RSA_HASH_SHA224); + rsa_flags &= ~(SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512 | SC_ALGORITHM_RSA_HASH_SHA224); #endif } #endif /* No need to Check for PKCS1 We support it in software and turned it on above so always added it */ - if (flags & SC_ALGORITHM_RSA_PAD_PKCS1) { - mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS, &mech_info, CKK_RSA, NULL); + if (rsa_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS, &mech_info, CKK_RSA, NULL, NULL); rc = sc_pkcs11_register_mechanism(p11card, mt); if (rc != CKR_OK) return rc; @@ -4712,32 +4746,32 @@ register_mechanisms(struct sc_pkcs11_card *p11card) /* All hashes are in OpenSSL * Either the card set the hashes or we helped it above */ - if (flags & SC_ALGORITHM_RSA_HASH_SHA1) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt); if (rc != CKR_OK) return rc; } - if (flags & SC_ALGORITHM_RSA_HASH_SHA256) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS, CKM_SHA256, mt); if (rc != CKR_OK) return rc; } - if (flags & SC_ALGORITHM_RSA_HASH_SHA384) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA384_RSA_PKCS, CKM_SHA384, mt); if (rc != CKR_OK) return rc; } - if (flags & SC_ALGORITHM_RSA_HASH_SHA512) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA512_RSA_PKCS, CKM_SHA512, mt); if (rc != CKR_OK) return rc; } - if (flags & SC_ALGORITHM_RSA_HASH_MD5) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_MD5) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_MD5_RSA_PKCS, CKM_MD5, mt); if (rc != CKR_OK) return rc; } - if (flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) { + if (rsa_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) { rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt); if (rc != CKR_OK) return rc; @@ -4747,15 +4781,15 @@ register_mechanisms(struct sc_pkcs11_card *p11card) /* TODO support other padding mechanisms */ - if (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); - if (!mt) - return CKR_HOST_MEMORY; - rc = sc_pkcs11_register_mechanism(p11card, 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); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } return CKR_OK; } diff --git a/src/pkcs11/framework-pkcs15init.c b/src/pkcs11/framework-pkcs15init.c index ad7ab415..582be36f 100644 --- a/src/pkcs11/framework-pkcs15init.c +++ b/src/pkcs11/framework-pkcs15init.c @@ -127,7 +127,7 @@ pkcs15init_initialize(struct sc_pkcs11_slot *pslot, void *ptr, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { - struct sc_pkcs11_card *p11card = pslot->card; + struct sc_pkcs11_card *p11card = pslot->p11card; struct sc_profile *profile = (struct sc_profile *) p11card->fws_data[0]; struct sc_pkcs15init_initargs args; struct sc_pkcs11_slot *slot; @@ -159,9 +159,9 @@ pkcs15init_initialize(struct sc_pkcs11_slot *pslot, void *ptr, * the flags. */ for (id = 0; slot_get_slot(id, &slot) == CKR_OK; id++) { - if (slot->card == p11card) + if (slot->p11card == p11card) slot->token_info.flags |= CKF_TOKEN_INITIALIZED; - if (slot->card->card->caps & SC_CARD_CAP_RNG) + if (slot->p11card->card->caps & SC_CARD_CAP_RNG) slot->token_info.flags |= CKF_RNG; } diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 0dbcf394..40d07401 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -83,6 +83,9 @@ sc_pkcs11_get_mechanism_list(struct sc_pkcs11_card *p11card, unsigned int n, count = 0; int rv; + if (!p11card) + return CKR_TOKEN_NOT_PRESENT; + for (n = 0; n < p11card->nmechanisms; n++) { if (!(mt = p11card->mechanisms[n])) continue; @@ -152,7 +155,7 @@ sc_pkcs11_md_init(struct sc_pkcs11_session *session, int rv; LOG_FUNC_CALLED(context); - if (!session || !session->slot || !(p11card = session->slot->card)) + if (!session || !session->slot || !(p11card = session->slot->p11card)) LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); /* See if we support this mechanism type */ @@ -231,7 +234,7 @@ sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechani int rv; LOG_FUNC_CALLED(context); - if (!session || !session->slot || !(p11card = session->slot->card)) + if (!session || !session->slot || !(p11card = session->slot->p11card)) LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); /* See if we support this mechanism type */ @@ -515,7 +518,7 @@ sc_pkcs11_verif_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechan int rv; if (!session || !session->slot - || !(p11card = session->slot->card)) + || !(p11card = session->slot->p11card)) return CKR_ARGUMENTS_BAD; /* See if we support this mechanism type */ @@ -590,7 +593,7 @@ done: } /* - * Initialize a signature operation + * Initialize a verify operation */ static CK_RV sc_pkcs11_verify_init(sc_pkcs11_operation_t *operation, @@ -606,6 +609,18 @@ sc_pkcs11_verify_init(sc_pkcs11_operation_t *operation, data->info = NULL; data->key = key; + if (key->ops->can_do) { + rv = key->ops->can_do(operation->session, key, operation->type->mech, CKF_SIGN); + if ((rv == CKR_OK) || (rv == CKR_FUNCTION_NOT_SUPPORTED)) { + /* Mechanism recognized and can be performed by pkcs#15 card or algorithm references not supported */ + } + else { + /* Mechanism cannot be performed by pkcs#15 card, or some general error. */ + free(data); + LOG_FUNC_RETURN(context, rv); + } + } + /* If this is a verify with hash operation, set up the * hash operation */ info = (struct hash_signature_info *) operation->type->mech_data; @@ -714,7 +729,7 @@ sc_pkcs11_decr_init(struct sc_pkcs11_session *session, CK_RV rv; if (!session || !session->slot - || !(p11card = session->slot->card)) + || !(p11card = session->slot->p11card)) return CKR_ARGUMENTS_BAD; /* See if we support this mechanism type */ @@ -784,7 +799,7 @@ sc_pkcs11_deri(struct sc_pkcs11_session *session, if (!session || !session->slot - || !(p11card = session->slot->card)) + || !(p11card = session->slot->p11card)) return CKR_ARGUMENTS_BAD; /* See if we support this mechanism type */ @@ -859,19 +874,32 @@ out: /* - * Initialize a signature operation + * Initialize a decrypt operation */ static CK_RV sc_pkcs11_decrypt_init(sc_pkcs11_operation_t *operation, struct sc_pkcs11_object *key) { struct signature_data *data; + CK_RV rv; if (!(data = calloc(1, sizeof(*data)))) return CKR_HOST_MEMORY; data->key = key; + if (key->ops->can_do) { + rv = key->ops->can_do(operation->session, key, operation->type->mech, CKF_DECRYPT); + if ((rv == CKR_OK) || (rv == CKR_FUNCTION_NOT_SUPPORTED)) { + /* Mechanism recognized and can be performed by pkcs#15 card or algorithm references not supported */ + } + else { + /* Mechanism cannot be performed by pkcs#15 card, or some general error. */ + free(data); + LOG_FUNC_RETURN(context, rv); + } + } + operation->priv_data = data; return CKR_OK; } @@ -906,6 +934,7 @@ sc_pkcs11_derive(sc_pkcs11_operation_t *operation, pmechParam, ulmechParamLen, pData, pulDataLen); } + /* * Create new mechanism type for a mechanism supported by * the card @@ -914,7 +943,8 @@ sc_pkcs11_mechanism_type_t * sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR pInfo, CK_KEY_TYPE key_type, - void *priv_data) + const void *priv_data, + void (*free_priv_data)(const void *priv_data)) { sc_pkcs11_mechanism_type_t *mt; @@ -925,6 +955,7 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech, mt->mech_info = *pInfo; mt->key_type = key_type; mt->mech_data = priv_data; + mt->free_mech_data = free_priv_data; mt->obj_size = sizeof(sc_pkcs11_operation_t); mt->release = sc_pkcs11_signature_release; @@ -966,6 +997,11 @@ sc_pkcs11_register_generic_mechanisms(struct sc_pkcs11_card *p11card) return CKR_OK; } +void free_info(const void *info) +{ + free((void *) info); +} + /* * Register a sign+hash algorithm derived from an algorithm supported * by the token + a software hash mechanism @@ -987,13 +1023,16 @@ sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *p11card, mech_info.flags &= (CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER); info = calloc(1, sizeof(*info)); + if (!info) + LOG_FUNC_RETURN(p11card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + info->mech = mech; info->sign_type = sign_type; info->hash_type = hash_type; info->sign_mech = sign_type->mech; info->hash_mech = hash_mech; - new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info); + new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info, free_info); if (!new_type) return CKR_HOST_MEMORY; diff --git a/src/pkcs11/misc.c b/src/pkcs11/misc.c index 8aab05cc..a2422db4 100644 --- a/src/pkcs11/misc.c +++ b/src/pkcs11/misc.c @@ -251,6 +251,30 @@ CK_RV attr_find2(CK_ATTRIBUTE_PTR pTemp1, CK_ULONG ulCount1, return rv; } +CK_RV attr_find_and_allocate_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void **out, size_t *out_len) +{ + void *ptr; + size_t len; + CK_RV rv; + + if (!out || !out_len) + return CKR_ARGUMENTS_BAD; + len = *out_len; + + rv = attr_find_ptr(pTemplate, ulCount, type, &ptr, &len); + if (rv != CKR_OK) + return rv; + + *out = calloc(1, len); + if (*out == NULL) + return CKR_HOST_MEMORY; + + memcpy(*out, ptr, len); + *out_len = len; + + return CKR_OK; +} + CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void **ptr, size_t * sizep) { unsigned int n; diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c index 88023d76..77d974bd 100644 --- a/src/pkcs11/openssl.c +++ b/src/pkcs11/openssl.c @@ -48,7 +48,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha1_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; #if OPENSSL_VERSION_NUMBER >= 0x00908000L @@ -65,7 +66,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha256_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; static sc_pkcs11_mechanism_type_t openssl_sha384_mech = { @@ -81,7 +83,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha384_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; static sc_pkcs11_mechanism_type_t openssl_sha512_mech = { @@ -97,7 +100,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha512_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; #endif @@ -115,7 +119,8 @@ static sc_pkcs11_mechanism_type_t openssl_gostr3411_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; #endif @@ -132,7 +137,8 @@ static sc_pkcs11_mechanism_type_t openssl_md5_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; static sc_pkcs11_mechanism_type_t openssl_ripemd160_mech = { @@ -148,11 +154,20 @@ static sc_pkcs11_mechanism_type_t openssl_ripemd160_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; +static void * dup_mem(void *in, size_t in_len) +{ + void *out = malloc(in_len); + if (out) + memcpy(out, in, in_len); + return out; +} + void -sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *card) +sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *p11card) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_ENGINE) void (*locking_cb)(int, int, const char *, int); @@ -192,22 +207,22 @@ sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *card) #endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_ENGINE) */ openssl_sha1_mech.mech_data = EVP_sha1(); - sc_pkcs11_register_mechanism(card, &openssl_sha1_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha1_mech, sizeof openssl_sha1_mech)); #if OPENSSL_VERSION_NUMBER >= 0x00908000L openssl_sha256_mech.mech_data = EVP_sha256(); - sc_pkcs11_register_mechanism(card, &openssl_sha256_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech)); openssl_sha384_mech.mech_data = EVP_sha384(); - sc_pkcs11_register_mechanism(card, &openssl_sha384_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha384_mech, sizeof openssl_sha384_mech)); openssl_sha512_mech.mech_data = EVP_sha512(); - sc_pkcs11_register_mechanism(card, &openssl_sha512_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha512_mech, sizeof openssl_sha512_mech)); #endif openssl_md5_mech.mech_data = EVP_md5(); - sc_pkcs11_register_mechanism(card, &openssl_md5_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_md5_mech, sizeof openssl_md5_mech)); openssl_ripemd160_mech.mech_data = EVP_ripemd160(); - sc_pkcs11_register_mechanism(card, &openssl_ripemd160_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_ripemd160_mech, sizeof openssl_ripemd160_mech)); #if OPENSSL_VERSION_NUMBER >= 0x10000000L openssl_gostr3411_mech.mech_data = EVP_get_digestbynid(NID_id_GostR3411_94); - sc_pkcs11_register_mechanism(card, &openssl_gostr3411_mech); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_gostr3411_mech, sizeof openssl_gostr3411_mech)); #endif } @@ -227,7 +242,7 @@ static CK_RV sc_pkcs11_openssl_md_init(sc_pkcs11_operation_t *op) if (!op || !(mt = op->type) || !(md = (EVP_MD *) mt->mech_data)) return CKR_ARGUMENTS_BAD; - if (!(md_ctx = calloc(1, sizeof(*md_ctx)))) + if (!(md_ctx = EVP_MD_CTX_create())) return CKR_HOST_MEMORY; EVP_DigestInit(md_ctx, md); op->priv_data = md_ctx; @@ -263,7 +278,7 @@ static void sc_pkcs11_openssl_md_release(sc_pkcs11_operation_t *op) EVP_MD_CTX *md_ctx = DIGEST_CTX(op); if (md_ctx) - free(md_ctx); + EVP_MD_CTX_destroy(md_ctx); op->priv_data = NULL; } diff --git a/src/pkcs11/pkcs11-display.c b/src/pkcs11/pkcs11-display.c index 10403bdf..652c6f63 100644 --- a/src/pkcs11/pkcs11-display.c +++ b/src/pkcs11/pkcs11-display.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Mathias Brossard + * Copyright (C) 2015 Mathias Brossard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -275,7 +275,12 @@ static enum_specs ck_key_s[] = { { CKK_BATON , "CKK_BATON " }, { CKK_JUNIPER , "CKK_JUNIPER " }, { CKK_CDMF , "CKK_CDMF " }, - { CKK_AES , "CKK_AES " } + { CKK_AES , "CKK_AES " }, + { CKK_BLOWFISH , "CKK_BLOWFISH " }, + { CKK_TWOFISH , "CKK_TWOFISH " }, + { CKK_GOSTR3410 , "CKK_GOSTR3410 " }, + { CKK_GOSTR3411 , "CKK_GOSTR3411 " }, + { CKK_GOST28147 , "CKK_GOST28147 " } }; static enum_specs ck_mec_s[] = { @@ -479,6 +484,26 @@ static enum_specs ck_mec_s[] = { { CKM_AES_MAC , "CKM_AES_MAC " }, { CKM_AES_MAC_GENERAL , "CKM_AES_MAC_GENERAL " }, { CKM_AES_CBC_PAD , "CKM_AES_CBC_PAD " }, + { CKM_AES_CTR , "CKM_AES_CTR " }, + { CKM_AES_GCM , "CKM_AES_GCM " }, + { CKM_AES_CCM , "CKM_AES_CCM " }, + { CKM_AES_CTS , "CKM_AES_CTS " }, + { CKM_BLOWFISH_KEY_GEN , "CKM_BLOWFISH_KEY_GEN " }, + { CKM_BLOWFISH_CBC , "CKM_BLOWFISH_CBC " }, + { CKM_TWOFISH_KEY_GEN , "CKM_TWOFISH_KEY_GEN " }, + { CKM_TWOFISH_CBC , "CKM_TWOFISH_CBC " }, + { CKM_GOSTR3410_KEY_PAIR_GEN , "CKM_GOSTR3410_KEY_PAIR_GEN " }, + { CKM_GOSTR3410 , "CKM_GOSTR3410 " }, + { CKM_GOSTR3410_WITH_GOSTR3411 , "CKM_GOSTR3410_WITH_GOSTR3411 " }, + { CKM_GOSTR3410_KEY_WRAP , "CKM_GOSTR3410_KEY_WRAP " }, + { CKM_GOSTR3410_DERIVE , "CKM_GOSTR3410_DERIVE " }, + { CKM_GOSTR3411 , "CKM_GOSTR3411 " }, + { CKM_GOSTR3411_HMAC , "CKM_GOSTR3411_HMAC " }, + { CKM_GOST28147_KEY_GEN , "CKM_GOST28147_KEY_GEN " }, + { CKM_GOST28147_ECB , "CKM_GOST28147_ECB " }, + { CKM_GOST28147 , "CKM_GOST28147 " }, + { CKM_GOST28147_MAC , "CKM_GOST28147_MAC " }, + { CKM_GOST28147_KEY_WRAP , "CKM_GOST28147_KEY_WRAP " }, { CKM_DSA_PARAMETER_GEN , "CKM_DSA_PARAMETER_GEN " }, { CKM_DH_PKCS_PARAMETER_GEN , "CKM_DH_PKCS_PARAMETER_GEN " }, { CKM_X9_42_DH_PARAMETER_GEN , "CKM_X9_42_DH_PARAMETER_GEN " }, @@ -682,6 +707,9 @@ type_spec ck_attribute_specs[] = { { CKA_WRAP_WITH_TRUSTED , "CKA_WRAP_WITH_TRUSTED ", print_generic, NULL }, { CKA_WRAP_TEMPLATE , "CKA_WRAP_TEMPLATE ", print_generic, NULL }, { CKA_UNWRAP_TEMPLATE , "CKA_UNWRAP_TEMPLATE ", print_generic, NULL }, + { CKA_GOSTR3410_PARAMS , "CKA_GOSTR3410_PARAMS ", print_generic, NULL }, + { CKA_GOSTR3411_PARAMS , "CKA_GOSTR3411_PARAMS ", print_generic, NULL }, + { CKA_GOST28147_PARAMS , "CKA_GOST28147_PARAMS ", print_generic, NULL }, { CKA_HW_FEATURE_TYPE , "CKA_HW_FEATURE_TYPE ", print_generic, NULL }, { CKA_RESET_ON_INIT , "CKA_RESET_ON_INIT ", print_generic, NULL }, { CKA_HAS_RESET , "CKA_HAS_RESET ", print_generic, NULL }, @@ -891,7 +919,9 @@ print_mech_info(FILE *f, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR minfo) const char *name = lookup_enum(MEC_T, type); CK_ULONG known_flags = CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_DIGEST | CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER | - CKF_GENERATE | CKF_GENERATE_KEY_PAIR | CKF_WRAP | CKF_UNWRAP | CKF_DERIVE; + CKF_GENERATE | CKF_GENERATE_KEY_PAIR | CKF_WRAP | CKF_UNWRAP | + CKF_DERIVE | CKF_EC_F_P | CKF_EC_F_2M |CKF_EC_ECPARAMETERS | + CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS; if (name) fprintf(f, "%s : ", name); @@ -901,7 +931,7 @@ print_mech_info(FILE *f, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR minfo) fprintf(f, "min:%lu max:%lu flags:0x%lX ", (unsigned long) minfo->ulMinKeySize, (unsigned long) minfo->ulMaxKeySize, minfo->flags); - fprintf(f, "( %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", + fprintf(f, "( %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", (minfo->flags & CKF_HW) ? "Hardware " : "", (minfo->flags & CKF_ENCRYPT) ? "Encrypt " : "", (minfo->flags & CKF_DECRYPT) ? "Decrypt " : "", @@ -915,6 +945,12 @@ print_mech_info(FILE *f, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR minfo) (minfo->flags & CKF_WRAP) ? "Wrap " : "", (minfo->flags & CKF_UNWRAP) ? "Unwrap " : "", (minfo->flags & CKF_DERIVE) ? "Derive " : "", + (minfo->flags & CKF_EC_F_P) ? "F(P) " : "", + (minfo->flags & CKF_EC_F_2M) ? "F(2^M) " : "", + (minfo->flags & CKF_EC_ECPARAMETERS) ? "EcParams " : "", + (minfo->flags & CKF_EC_NAMEDCURVE) ? "NamedCurve " : "", + (minfo->flags & CKF_EC_UNCOMPRESS) ? "Uncompress " : "", + (minfo->flags & CKF_EC_COMPRESS) ? "Compress " : "", (minfo->flags & ~known_flags) ? "Unknown " : ""); } diff --git a/src/pkcs11/pkcs11-display.h b/src/pkcs11/pkcs11-display.h index 7e1ae8e9..0f7bc5fb 100644 --- a/src/pkcs11/pkcs11-display.h +++ b/src/pkcs11/pkcs11-display.h @@ -2,7 +2,7 @@ #define PKCS11_DISPLAY_H /* - * Copyright (C) 2003 Mathias Brossard + * Copyright (C) 2015 Mathias Brossard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 64abd1a7..349ee296 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -202,9 +202,11 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) unsigned int i; sc_context_param_t ctx_opts; - /* Handle fork() exception */ #if !defined(_WIN32) + /* Handle fork() exception */ if (current_pid != initialized_pid) { + if (context) + context->flags |= SC_CTX_FLAG_TERMINATE; C_Finalize(NULL_PTR); } initialized_pid = current_pid; @@ -533,7 +535,7 @@ CK_RV C_GetMechanismList(CK_SLOT_ID slotID, rv = slot_get_token(slotID, &slot); if (rv == CKR_OK) - rv = sc_pkcs11_get_mechanism_list(slot->card, pMechanismList, pulCount); + rv = sc_pkcs11_get_mechanism_list(slot->p11card, pMechanismList, pulCount); sc_pkcs11_unlock(); return rv; @@ -555,7 +557,7 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, rv = slot_get_token(slotID, &slot); if (rv == CKR_OK) - rv = sc_pkcs11_get_mechanism_info(slot->card, type, pInfo); + rv = sc_pkcs11_get_mechanism_info(slot->p11card, type, pInfo); sc_pkcs11_unlock(); return rv; @@ -582,7 +584,8 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, goto out; } - if (slot->card->framework->init_token == NULL) { + if (!slot->p11card || !slot->p11card->framework + || !slot->p11card->framework->init_token) { sc_log(context, "C_InitToken() not supported by framework"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto out; @@ -597,7 +600,7 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, } } - rv = slot->card->framework->init_token(slot,slot->fw_data, pPin, ulPinLen, pLabel); + rv = slot->p11card->framework->init_token(slot,slot->fw_data, pPin, ulPinLen, pLabel); if (rv == CKR_OK) { /* Now we should re-bind all tokens so they get the * corresponding function vector and flags */ @@ -688,7 +691,7 @@ out: sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states); } - sc_log(context, "C_WaitForSlotEvent() = %s, event in 0x%lx", lookup_enum (RV_T, rv), *pSlot); + sc_log(context, "C_WaitForSlotEvent() = %s", lookup_enum (RV_T, rv)); sc_pkcs11_unlock(); return rv; } diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index 90b5e1d5..41bfe5c0 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -47,7 +47,8 @@ static sc_pkcs11_mechanism_type_t find_mechanism = { NULL, /* decrypt_init */ NULL, /* decrypt */ NULL, /* derive */ - NULL /* mech_data */ + NULL, /* mech_data */ + NULL, /* free_mech_data */ }; static void @@ -113,7 +114,7 @@ CK_RV sc_create_object_int(CK_SESSION_HANDLE hSession, /* the session's handle * goto out; } - card = session->slot->card; + card = session->slot->p11card; if (card->framework->create_object == NULL) rv = CKR_FUNCTION_NOT_SUPPORTED; else @@ -394,7 +395,7 @@ C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */ sizeof(CK_OBJECT_HANDLE) * operation->allocated_handles); if (operation->handles == NULL) { rv = CKR_HOST_MEMORY; - break; + goto out; } } operation->handles[operation->num_handles++] = object->handle; @@ -760,57 +761,7 @@ C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ CK_OBJECT_HANDLE hKey) /* handle of the signature key */ { - CK_RV rv; - CK_BBOOL can_sign; - CK_KEY_TYPE key_type; - CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) }; - CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; - struct sc_pkcs11_session *session; - struct sc_pkcs11_object *object; - - /* FIXME #47: C_SignRecover is not implemented */ return CKR_FUNCTION_NOT_SUPPORTED; - - if (pMechanism == NULL_PTR) - return CKR_ARGUMENTS_BAD; - - rv = sc_pkcs11_lock(); - if (rv != CKR_OK) - return rv; - - rv = get_object_from_session(hSession, hKey, &session, &object); - if (rv != CKR_OK) { - if (rv == CKR_OBJECT_HANDLE_INVALID) - rv = CKR_KEY_HANDLE_INVALID; - goto out; - } - - if (object->ops->sign == NULL_PTR) { - rv = CKR_KEY_TYPE_INCONSISTENT; - goto out; - } - - rv = object->ops->get_attribute(session, object, &sign_attribute); - if (rv != CKR_OK || !can_sign) { - rv = CKR_KEY_TYPE_INCONSISTENT; - goto out; - } - rv = object->ops->get_attribute(session, object, &key_type_attr); - if (rv != CKR_OK) { - rv = CKR_KEY_TYPE_INCONSISTENT; - goto out; - } - - /* XXX: need to tell the signature algorithm that we want - * to recover the signature */ - sc_log(context, "SignRecover operation initialized\n"); - - rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type); - -out: - sc_log(context, "C_SignRecoverInit() = %sn", lookup_enum ( RV_T, rv )); - sc_pkcs11_unlock(); - return rv; } @@ -1032,10 +983,10 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, /* the session's handle */ } slot = session->slot; - if (slot->card->framework->gen_keypair == NULL) + if (slot->p11card->framework->gen_keypair == NULL) rv = CKR_FUNCTION_NOT_SUPPORTED; else - rv = slot->card->framework->gen_keypair(slot, pMechanism, + rv = slot->p11card->framework->gen_keypair(slot, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); @@ -1128,8 +1079,8 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = get_object_from_session(hSession, *phKey, &session, &key_object); if (rv != CKR_OK) { - if (rv == CKR_OBJECT_HANDLE_INVALID) - rv = CKR_KEY_HANDLE_INVALID; + if (rv == CKR_OBJECT_HANDLE_INVALID) + rv = CKR_KEY_HANDLE_INVALID; goto out; } @@ -1169,10 +1120,10 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = get_session(hSession, &session); if (rv == CKR_OK) { slot = session->slot; - if (slot->card->framework->get_random == NULL) + if (slot->p11card->framework->get_random == NULL) rv = CKR_RANDOM_NO_RNG; else - rv = slot->card->framework->get_random(slot, RandomData, ulRandomLen); + rv = slot->p11card->framework->get_random(slot, RandomData, ulRandomLen); } sc_pkcs11_unlock(); diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index e6edf25c..c4ab857f 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -107,7 +107,7 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession) slot->nsessions--; if (slot->nsessions == 0 && slot->login_user >= 0) { slot->login_user = -1; - slot->card->framework->logout(slot); + slot->p11card->framework->logout(slot); } if (list_delete(&sessions, session) != 0) @@ -120,17 +120,17 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession) * the global lock held */ CK_RV sc_pkcs11_close_all_sessions(CK_SLOT_ID slotID) { - CK_RV rv = CKR_OK; + CK_RV rv = CKR_OK, error; struct sc_pkcs11_session *session; unsigned int i; sc_log(context, "real C_CloseAllSessions(0x%lx) %d", slotID, list_size(&sessions)); for (i = 0; i < list_size(&sessions); i++) { session = list_get_at(&sessions, i); if (session->slot->id == slotID) - if ((rv = sc_pkcs11_close_session(session->handle)) != CKR_OK) - return rv; + if ((error = sc_pkcs11_close_session(session->handle)) != CKR_OK) + rv = error; } - return CKR_OK; + return rv; } CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) @@ -272,7 +272,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ goto out; } else { - rv = slot->card->framework->login(slot, userType, pPin, ulPinLen); + rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); } } else { @@ -286,7 +286,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ } sc_log(context, "C_Login() userType %li", userType); - rv = slot->card->framework->login(slot, userType, pPin, ulPinLen); + rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); sc_log(context, "fLogin() rv %li", rv); if (rv == CKR_OK) slot->login_user = userType; @@ -319,7 +319,7 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) if (slot->login_user >= 0) { slot->login_user = -1; - rv = slot->card->framework->logout(slot); + rv = slot->p11card->framework->logout(slot); } else rv = CKR_USER_NOT_LOGGED_IN; @@ -355,10 +355,10 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) slot = session->slot; if (slot->login_user != CKU_SO) { rv = CKR_USER_NOT_LOGGED_IN; - } else if (slot->card->framework->init_pin == NULL) { + } else if (slot->p11card->framework->init_pin == NULL) { rv = CKR_FUNCTION_NOT_SUPPORTED; } else { - rv = slot->card->framework->init_pin(slot, pPin, ulPinLen); + rv = slot->p11card->framework->init_pin(slot, pPin, ulPinLen); sc_log(context, "C_InitPIN() init-pin result %li", rv); } @@ -395,7 +395,7 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, goto out; } - rv = slot->card->framework->change_pin(slot, pOldPin, ulOldLen, pNewPin, ulNewLen); + rv = slot->p11card->framework->change_pin(slot, pOldPin, ulOldLen, pNewPin, ulNewLen); out: sc_pkcs11_unlock(); return rv; diff --git a/src/pkcs11/pkcs11-spy.c b/src/pkcs11/pkcs11-spy.c index 52318e48..49a6116c 100644 --- a/src/pkcs11/pkcs11-spy.c +++ b/src/pkcs11/pkcs11-spy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Mathias Brossard + * Copyright (C) 2015 Mathias Brossard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -68,7 +68,7 @@ init_spy(void) if (pkcs11_spy) { /* with our own pkcs11.h we need to maintain this ourself */ pkcs11_spy->version.major = 2; - pkcs11_spy->version.major = 11; + pkcs11_spy->version.minor = 11; pkcs11_spy->C_Initialize = C_Initialize; pkcs11_spy->C_Finalize = C_Finalize; pkcs11_spy->C_GetInfo = C_GetInfo; diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h index 1a51a31e..9967025b 100644 --- a/src/pkcs11/pkcs11.h +++ b/src/pkcs11/pkcs11.h @@ -355,6 +355,8 @@ typedef unsigned long ck_key_type_t; #define CKK_BLOWFISH (0x20UL) #define CKK_TWOFISH (0x21UL) #define CKK_GOSTR3410 (0x30UL) +#define CKK_GOSTR3411 (0x31UL) +#define CKK_GOST28147 (0x32UL) #define CKK_VENDOR_DEFINED (1UL << 31) @@ -671,10 +673,27 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_AES_MAC (0x1083UL) #define CKM_AES_MAC_GENERAL (0x1084UL) #define CKM_AES_CBC_PAD (0x1085UL) +#define CKM_AES_CTR (0x1086UL) +#define CKM_AES_GCM (0x1087UL) +#define CKM_AES_CCM (0x1088UL) +#define CKM_AES_CTS (0x1089UL) +#define CKM_BLOWFISH_KEY_GEN (0x1090UL) +#define CKM_BLOWFISH_CBC (0x1091UL) +#define CKM_TWOFISH_KEY_GEN (0x1092UL) +#define CKM_TWOFISH_CBC (0x1093UL) #define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) #define CKM_GOSTR3410 (0x1201UL) #define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) +#define CKM_GOSTR3410_KEY_WRAP (0x1203UL) +#define CKM_GOSTR3410_DERIVE (0x1204UL) #define CKM_GOSTR3411 (0x1210UL) +#define CKM_GOSTR3411_HMAC (0x1211UL) +#define CKM_GOST28147_KEY_GEN (0x1220UL) +#define CKM_GOST28147_ECB (0x1221UL) +#define CKM_GOST28147 (0x1222UL) +#define CKM_GOST28147_MAC (0x1223UL) +#define CKM_GOST28147_KEY_WRAP (0x1224UL) + #define CKM_DSA_PARAMETER_GEN (0x2000UL) #define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) #define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) @@ -715,7 +734,7 @@ struct ck_mechanism_info #define CKF_EC_F_2M (1UL << 21) #define CKF_EC_ECPARAMETERS (1UL << 22) #define CKF_EC_NAMEDCURVE (1UL << 23) -#define CKF_EC_UNCOMPRESES (1UL << 24) +#define CKF_EC_UNCOMPRESS (1UL << 24) #define CKF_EC_COMPRESS (1UL << 25) /* Flags for C_WaitForSlotEvent. */ diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 3783fde8..b89185ce 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -208,7 +208,7 @@ struct sc_pkcs11_slot { CK_SLOT_INFO slot_info; /* Slot specific information (information about reader) */ CK_TOKEN_INFO token_info; /* Token specific information (information about card) */ sc_reader_t *reader; /* same as card->reader if there's a card present */ - struct sc_pkcs11_card *card; /* The card associated with this slot */ + struct sc_pkcs11_card *p11card; /* The card associated with this slot */ unsigned int events; /* Card events SC_EVENT_CARD_{INSERTED,REMOVED} */ void *fw_data; /* Framework specific data */ /* TODO: get know how it used */ list_t objects; /* Objects in this slot */ @@ -275,7 +275,9 @@ struct sc_pkcs11_mechanism_type { CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); /* mechanism specific data */ - const void * mech_data; + const void * mech_data; + /* free mechanism specific data */ + void (*free_mech_data)(const void *mech_data); }; typedef struct sc_pkcs11_mechanism_type sc_pkcs11_mechanism_type_t; @@ -369,6 +371,7 @@ CK_RV attr_find(CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, void *, size_t *); CK_RV attr_find2(CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, void *, size_t *); CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, void **, size_t *); +CK_RV attr_find_and_allocate_ptr(CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, void **, size_t *); CK_RV attr_find_var(CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, void *, size_t *); CK_RV attr_extract(CK_ATTRIBUTE_PTR, void *, size_t *); @@ -402,7 +405,7 @@ sc_pkcs11_mechanism_type_t *sc_pkcs11_find_mechanism(struct sc_pkcs11_card *, CK_MECHANISM_TYPE, unsigned int); sc_pkcs11_mechanism_type_t *sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE, CK_MECHANISM_INFO_PTR, CK_KEY_TYPE, - void *); + const void *, void (*)(const void *)); sc_pkcs11_operation_t *sc_pkcs11_new_operation(sc_pkcs11_session_t *, sc_pkcs11_mechanism_type_t *); void sc_pkcs11_release_operation(sc_pkcs11_operation_t **); diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index 87b1e3dd..857252c3 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -20,6 +20,7 @@ */ #include "config.h" +#include "libopensc/opensc.h" #include #include @@ -100,6 +101,15 @@ CK_RV create_slot(sc_reader_t *reader) return CKR_OK; } +void delete_slot(struct sc_pkcs11_slot *slot) +{ + if (slot) { + list_destroy(&slot->objects); + list_delete(&virtual_slots, slot); + free(slot); + } +} + /* create slots associated with a reader, called whenever a reader is seen. */ CK_RV initialize_reader(sc_reader_t *reader) @@ -142,7 +152,7 @@ CK_RV initialize_reader(sc_reader_t *reader) CK_RV card_removed(sc_reader_t * reader) { unsigned int i; - struct sc_pkcs11_card *card = NULL; + struct sc_pkcs11_card *p11card = NULL; /* Mark all slots as "token not present" */ sc_log(context, "%s: card removed", reader->name); @@ -151,29 +161,23 @@ CK_RV card_removed(sc_reader_t * reader) sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) { /* Save the "card" object */ - if (slot->card) - card = slot->card; + if (slot->p11card) + p11card = slot->p11card; slot_token_removed(slot->id); } } - if (card) { - card->framework->unbind(card); - sc_disconnect_card(card->card); - /* FIXME: free mechanisms - * spaces allocated by the - * sc_pkcs11_register_sign_and_hash_mechanism - * and sc_pkcs11_new_fw_mechanism. - * but see sc_pkcs11_register_generic_mechanisms - for (i=0; i < card->nmechanisms; ++i) { - // if 'mech_data' is a pointer earlier returned by the ?alloc - free(card->mechanisms[i]->mech_data); - // if 'mechanisms[i]' is a pointer earlier returned by the ?alloc - free(card->mechanisms[i]); + if (p11card) { + p11card->framework->unbind(p11card); + sc_disconnect_card(p11card->card); + for (i=0; i < p11card->nmechanisms; ++i) { + if (p11card->mechanisms[i]->free_mech_data) { + p11card->mechanisms[i]->free_mech_data(p11card->mechanisms[i]->mech_data); + } + free(p11card->mechanisms[i]); } - */ - free(card->mechanisms); - free(card); + free(p11card->mechanisms); + free(p11card); } return CKR_OK; @@ -220,7 +224,7 @@ again: for (i=0; ireader == reader) { - p11card = slot->card; + p11card = slot->p11card; break; } } @@ -330,16 +334,27 @@ card_detect_all(void) /* Detect cards in all initialized readers */ for (i=0; i< sc_ctx_get_reader_count(context); i++) { sc_reader_t *reader = sc_ctx_get_reader(context, i); - if (!reader_get_slot(reader)) - initialize_reader(reader); - card_detect(sc_ctx_get_reader(context, i)); + if (reader->flags & SC_READER_REMOVED) { + struct sc_pkcs11_slot *slot; + card_removed(reader); + while ((slot = reader_get_slot(reader))) { + delete_slot(slot); + } + _sc_delete_reader(context, reader); + i--; + } else { + if (!reader_get_slot(reader)) + initialize_reader(reader); + else + card_detect(sc_ctx_get_reader(context, i)); + } } sc_log(context, "All cards detected"); return CKR_OK; } /* Allocates an existing slot to a card */ -CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * card) +CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * p11card) { unsigned int i; struct sc_pkcs11_slot *tmp_slot = NULL; @@ -347,13 +362,13 @@ CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * card) /* Locate a free slot for this reader */ for (i=0; i< list_size(&virtual_slots); i++) { tmp_slot = (struct sc_pkcs11_slot *)list_get_at(&virtual_slots, i); - if (tmp_slot->reader == card->reader && tmp_slot->card == NULL) + if (tmp_slot->reader == p11card->reader && tmp_slot->p11card == NULL) break; } if (!tmp_slot || (i == list_size(&virtual_slots))) return CKR_FUNCTION_FAILED; - sc_log(context, "Allocated slot 0x%lx for card in reader %s", tmp_slot->id, card->reader->name); - tmp_slot->card = card; + sc_log(context, "Allocated slot 0x%lx for card in reader %s", tmp_slot->id, p11card->reader->name); + tmp_slot->p11card = p11card; tmp_slot->events = SC_EVENT_CARD_INSERTED; *slot = tmp_slot; return CKR_OK; @@ -418,16 +433,16 @@ CK_RV slot_token_removed(CK_SLOT_ID id) } /* Release framework stuff */ - if (slot->card != NULL) { + if (slot->p11card != NULL) { if (slot->fw_data != NULL && - slot->card->framework != NULL && slot->card->framework->release_token != NULL) - slot->card->framework->release_token(slot->card, slot->fw_data); + slot->p11card->framework != NULL && slot->p11card->framework->release_token != NULL) + slot->p11card->framework->release_token(slot->p11card, slot->fw_data); } /* Reset relevant slot properties */ slot->slot_info.flags &= ~CKF_TOKEN_PRESENT; slot->login_user = -1; - slot->card = NULL; + slot->p11card = NULL; if (token_was_present) slot->events = SC_EVENT_CARD_REMOVED; @@ -446,7 +461,7 @@ CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask) sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); sc_log(context, "slot 0x%lx token: %d events: 0x%02X",slot->id, (slot->slot_info.flags & CKF_TOKEN_PRESENT), slot->events); if ((slot->events & SC_EVENT_CARD_INSERTED) - && !(slot->slot_info.flags & CKF_TOKEN_PRESENT)) { + && !(slot->slot_info.flags & CKF_TOKEN_PRESENT)) { /* If a token has not been initialized, clear the inserted event */ slot->events &= ~SC_EVENT_CARD_INSERTED; } diff --git a/src/pkcs15init/Makefile.am b/src/pkcs15init/Makefile.am index 1bffba0f..bf267df8 100644 --- a/src/pkcs15init/Makefile.am +++ b/src/pkcs15init/Makefile.am @@ -29,7 +29,8 @@ dist_pkgdata_DATA = \ iasecc.profile \ ias_adele_admin1.profile ias_adele_admin2.profile ias_adele_common.profile \ iasecc_generic_pki.profile iasecc_admin_eid.profile iasecc_generic_oberthur.profile \ - openpgp.profile sc-hsm.profile + openpgp.profile sc-hsm.profile \ + isoApplet.profile AM_CPPFLAGS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\" \ -I$(top_srcdir)/src @@ -46,4 +47,5 @@ libpkcs15init_la_SOURCES = \ pkcs15-rtecp.c pkcs15-myeid.c \ pkcs15-oberthur.c pkcs15-oberthur-awp.c \ pkcs15-authentic.c pkcs15-iasecc.c pkcs15-openpgp.c \ - pkcs15-sc-hsm.c + pkcs15-sc-hsm.c \ + pkcs15-isoApplet.c diff --git a/src/pkcs15init/Makefile.mak b/src/pkcs15init/Makefile.mak index 348534ee..fb4b28fb 100644 --- a/src/pkcs15init/Makefile.mak +++ b/src/pkcs15init/Makefile.mak @@ -9,7 +9,8 @@ OBJECTS = pkcs15-lib.obj profile.obj \ pkcs15-muscle.obj pkcs15-asepcos.obj pkcs15-rutoken.obj \ pkcs15-entersafe.obj pkcs15-rtecp.obj pkcs15-westcos.obj \ pkcs15-myeid.obj pkcs15-authentic.obj pkcs15-iasecc.obj \ - pkcs15-epass2003.obj pkcs15-openpgp.obj pkcs15-sc-hsm.obj + pkcs15-epass2003.obj pkcs15-openpgp.obj pkcs15-sc-hsm.obj \ + pkcs15-isoApplet.obj all: $(TARGET) diff --git a/src/pkcs15init/isoApplet.profile b/src/pkcs15init/isoApplet.profile new file mode 100644 index 00000000..2f7df105 --- /dev/null +++ b/src/pkcs15init/isoApplet.profile @@ -0,0 +1,158 @@ +# +# PKCS15 profile for the isoApplet JavaCard Applet. +# - init driver: pkcs15-isoApplet.c +# - card driver: card-isoApplet.c +# + +cardinfo { + label ="JavaCard isoApplet"; + manufacturer = "unknown"; + min-pin-length = 4; + max-pin-length = 16; + pin-pad-char = 0x00; +} + +pkcs15 { + # Method to calculate ID of the crypto objects + # mozilla: SHA1(modulus) for RSA, SHA1(pub) for DSA + # rfc2459: SHA1(SequenceASN1 of public key components as ASN1 integers) + # native: 'E' + number_of_present_objects_of_the_same_type + # default value: 'native' + pkcs15-id-style = native; +} + +option default { + macros { + unusedspace-size = 128; + odf-size = 256; + aodf-size = 256; + cdf-size = 512; + prkdf-size = 512; + pukdf-size = 512; + dodf-size = 256; + } +} + +PIN so-pin { + attempts = 3; + max-length = 16; + min-length = 4; + reference = 1; + flags = case-sensitive, needs-padding; +} + +PIN so-puk { + attempts = 3; + max-length = 16; + min-length = 16; + reference = 2; + flags = unblockingPin, unblock-disabled, case-sensitive, change-disabled; +} + +filesystem { + DF MF { + path = 3F00; + type = DF; + + # This is the DIR file + EF DIR { + type = EF; + file-id = 2F00; + size = 128; + acl = *=NONE; + } + + # Here comes the application DF + DF PKCS15-AppDF { + type = DF; + file-id = 5015; + aid = A0:00:00:00:63:50:4B:43:53:2D:31:35; + acl = *=NONE, DELETE=$PIN; + size = 5000; + + EF PKCS15-ODF { + file-id = 5031; + size = $odf-size; + ACL = *=NONE; + } + + EF PKCS15-TokenInfo { + file-id = 5032; + ACL = *=NONE; + } + + EF PKCS15-UnusedSpace { + file-id = 5033; + size = $unusedspace-size; + ACL = *=NONE; + } + + EF PKCS15-AODF { + file-id = 4401; + size = $aodf-size; + ACL = *=$PIN, READ=NONE; + } + + EF PKCS15-PrKDF { + file-id = 4402; + size = $prkdf-size; + acl = *=$PIN, READ=NONE; + } + + EF PKCS15-PuKDF { + file-id = 4403; + size = $pukdf-size; + acl = *=$PIN, READ=NONE; + } + + EF PKCS15-CDF { + file-id = 4404; + size = $cdf-size; + acl = *=$PIN, READ=NONE; + } + + EF PKCS15-DODF { + file-id = 4405; + size = $dodf-size; + ACL = *=$PIN, READ=NONE; + } + + template key-domain { + + BSO private-key { + ACL = *=$PIN, READ=NEVER; + } + + # EF extractable-key { + # file-id = 3100; + # acl = *=NEVER, READ=$PIN, UPDATE=$PIN, + # ERASE=$PIN; + # } + + EF data { + file-id = 3200; + acl = *=NEVER, UPDATE=$PIN, READ=NONE, + DELETE-SELF=$PIN, ERASE=$PIN; + } + + EF privdata { + file-id = 3500; + acl = *=NEVER, UPDATE=$PIN, READ=$PIN, + DELETE-SELF=$PIN, ERASE=$PIN; + } + + EF public-key { + file-id = 3300; + acl = *=NEVER, UPDATE=$PIN, READ=NONE, + DELETE-SELF=$PIN, ERASE=$PIN; + } + + EF certificate { + file-id = 3400; + acl = *=NEVER, UPDATE=$PIN, READ=NONE, + DELETE-SELF=$PIN, ERASE=$PIN; + } + } + } + } +} diff --git a/src/pkcs15init/pkcs15-asepcos.c b/src/pkcs15init/pkcs15-asepcos.c index 310c6f92..7904fb5a 100644 --- a/src/pkcs15init/pkcs15-asepcos.c +++ b/src/pkcs15init/pkcs15-asepcos.c @@ -510,9 +510,9 @@ static int asepcos_do_create_key(sc_card_t *card, size_t ksize, int fileid, int r; size_t len; sc_file_t *nfile = NULL; - u8 buf[512], *p = buf; + u8 buf[1024], *p = buf; - if (sizeof(buf) < kdlen + 11) + if (sizeof(buf) < kdlen + 12) return SC_ERROR_BUFFER_TOO_SMALL; *p++ = 0x85; diff --git a/src/pkcs15init/pkcs15-authentic.c b/src/pkcs15init/pkcs15-authentic.c index cdead033..1f41747f 100644 --- a/src/pkcs15init/pkcs15-authentic.c +++ b/src/pkcs15init/pkcs15-authentic.c @@ -258,6 +258,8 @@ authentic_pkcs15_new_file(struct sc_profile *profile, struct sc_card *card, file->path.type, sc_print_path(&file->path)); if (out) *out = file; + else + sc_file_free(file); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -350,6 +352,7 @@ authentic_sdo_allocate_prvkey(struct sc_profile *profile, struct sc_card *card, sdo = calloc(1, sizeof(struct sc_authentic_sdo)); if (!sdo) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate 'sc_authentic_sdo'"); + *out = sdo; sdo->magic = AUTHENTIC_SDO_MAGIC; sdo->docp.id = key_info->key_reference & ~AUTHENTIC_OBJECT_REF_FLAG_LOCAL; @@ -357,16 +360,11 @@ authentic_sdo_allocate_prvkey(struct sc_profile *profile, struct sc_card *card, rv = authentic_docp_set_acls(card, file, authentic_v3_rsa_ac_ops, sizeof(authentic_v3_rsa_ac_ops)/sizeof(authentic_v3_rsa_ac_ops[0]), &sdo->docp); - LOG_TEST_RET(ctx, rv, "Cannot set key ACLs from file"); - sc_file_free(file); + LOG_TEST_RET(ctx, rv, "Cannot set key ACLs from file"); sc_log(ctx, "sdo(mech:%X,id:%X,acls:%s)", sdo->docp.mech, sdo->docp.id, sc_dump_hex(sdo->docp.acl_data, sdo->docp.acl_data_len)); - if (out) - *out = sdo; - else - free(sdo); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -720,12 +718,12 @@ authentic_pkcs15_delete_rsa_sdo (struct sc_profile *profile, struct sc_pkcs15_ca sc_log(ctx, "delete SDO RSA key (ref:%i,size:%i)", key_info->key_reference, key_info->modulus_length); rv = authentic_pkcs15_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file); - LOG_TEST_RET(ctx, rv, "PRKEY_RSA instantiation file error"); + LOG_TEST_GOTO_ERR(ctx, rv, "PRKEY_RSA instantiation file error"); p15card->card->caps &= ~SC_CARD_CAP_USE_FCI_AC; rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_DELETE); p15card->card->caps = caps; - LOG_TEST_RET(ctx, rv, "'DELETE' authentication failed for parent RSA key"); + LOG_TEST_GOTO_ERR(ctx, rv, "'DELETE' authentication failed for parent RSA key"); sdo.magic = AUTHENTIC_SDO_MAGIC; sdo.docp.id = key_info->key_reference & ~AUTHENTIC_OBJECT_REF_FLAG_LOCAL; @@ -734,8 +732,11 @@ authentic_pkcs15_delete_rsa_sdo (struct sc_profile *profile, struct sc_pkcs15_ca rv = sc_card_ctl(p15card->card, SC_CARDCTL_AUTHENTIC_SDO_DELETE, &sdo); if (rv == SC_ERROR_DATA_OBJECT_NOT_FOUND) rv = SC_SUCCESS; - 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"); +err: + if (file) + sc_file_free(file); LOG_FUNC_RETURN(ctx, rv); } diff --git a/src/pkcs15init/pkcs15-cardos.c b/src/pkcs15init/pkcs15-cardos.c index 160b975b..63f32a85 100644 --- a/src/pkcs15init/pkcs15-cardos.c +++ b/src/pkcs15init/pkcs15-cardos.c @@ -402,6 +402,62 @@ out: return r; } +/* + * Object deletion. + */ +static int +cardos_delete_object(sc_profile_t *profile, struct sc_pkcs15_card *p15card, + struct sc_pkcs15_object *obj, const struct sc_path *path) +{ + int r, stored_in_ef = 0, algorithm = 0; + size_t keybits; + sc_file_t *file = NULL; + struct sc_pkcs15_prkey_info *key_info; + struct sc_pkcs15_prkey_rsa key_obj; + struct sc_context *ctx = p15card->card->ctx; + uint8_t abignum[256]; + + LOG_FUNC_CALLED(ctx); + /* + * If we are deleting a private key, overwrite it so it can't be used. + */ + if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) { + key_info = obj->data; + keybits = key_info->modulus_length & ~7UL; + init_key_object(&key_obj, abignum, keybits >> 3); + r = cardos_key_algorithm(key_info->usage, keybits, &algorithm); + LOG_TEST_RET(ctx, r, "cardos_key_algorithm failed"); + + r = sc_select_file(p15card->card, &key_info->path, &file); + LOG_TEST_RET(ctx, r, "Failed to store key: cannot select parent DF"); + + r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); + sc_file_free(file); + LOG_TEST_RET(ctx, r, "Failed to store key: UPDATE authentication failed"); + + r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj); + LOG_TEST_RET(ctx, r, "cardos_put_key failed"); + } + + /* Delete object from the PKCS15 file system. */ + if (path->len || path->aid.len) { + r = sc_select_file(p15card->card, path, &file); + if (r != SC_ERROR_FILE_NOT_FOUND) + LOG_TEST_RET(ctx, r, "select object path failed"); + + stored_in_ef = (file->type != SC_FILE_TYPE_DF); + sc_file_free(file); + } + + /* If the object is stored in a normal EF, try to delete the EF. */ + if (r == SC_SUCCESS && stored_in_ef) { + r = sc_pkcs15init_delete_by_path(profile, p15card, path); + LOG_TEST_RET(ctx, r, "Failed to delete object by path"); + } + + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + /* * Store a PIN or PUK */ @@ -851,7 +907,7 @@ static struct sc_pkcs15init_operations sc_pkcs15init_cardos_operations = { cardos_generate_key, NULL, NULL, /* encode private/public key */ NULL, /* finalize_card */ - NULL, /* delete_object */ + cardos_delete_object, NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ NULL /* sanity_check */ }; diff --git a/src/pkcs15init/pkcs15-cflex.c b/src/pkcs15init/pkcs15-cflex.c index 30cb3d49..1b85b880 100644 --- a/src/pkcs15init/pkcs15-cflex.c +++ b/src/pkcs15init/pkcs15-cflex.c @@ -224,7 +224,7 @@ cflex_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin; sc_file_t *dummies[2]; int ndummies, pin_type, puk_type, r; - sc_file_t *file; + sc_file_t *file = NULL; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); @@ -250,6 +250,7 @@ cflex_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND, "profile does not define pin file ACLs"); ndummies = cflex_create_dummy_chvs(profile, p15card, file, SC_AC_OP_CREATE, dummies); + sc_file_free(file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, ndummies, "Unable to create dummy CHV file"); r = cflex_create_pin_file(profile, p15card, &df->path, pin_attrs->reference, diff --git a/src/pkcs15init/pkcs15-entersafe.c b/src/pkcs15init/pkcs15-entersafe.c index 80c66698..12611179 100644 --- a/src/pkcs15init/pkcs15-entersafe.c +++ b/src/pkcs15init/pkcs15-entersafe.c @@ -292,10 +292,9 @@ static int entersafe_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card data.key_data.symmetric.key_len=16; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); - if (pin_obj) { - /* Cache new PIN value. */ - sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); - } + + /* Cache new PIN value. */ + sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); } {/*puk*/ diff --git a/src/pkcs15init/pkcs15-epass2003.c b/src/pkcs15init/pkcs15-epass2003.c index a457ec93..47ed5d1a 100644 --- a/src/pkcs15init/pkcs15-epass2003.c +++ b/src/pkcs15init/pkcs15-epass2003.c @@ -470,8 +470,7 @@ static int epass2003_pkcs15_store_key(struct sc_profile *profile, SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "store key: cannot update private key"); - if (file) - sc_file_free(file); + sc_file_free(file); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } @@ -488,7 +487,7 @@ static int epass2003_pkcs15_generate_key(struct sc_profile *profile, (struct sc_pkcs15_prkey_info *)obj->data; size_t idx = key_info->key_reference; size_t keybits = key_info->modulus_length; - struct sc_file *tfile = NULL, *prkf = NULL, *pukf = NULL; + struct sc_file *tfile = NULL, *pukf = NULL; struct sc_path path; struct sc_file *file = NULL; int fidl = 0; @@ -628,8 +627,6 @@ static int epass2003_pkcs15_generate_key(struct sc_profile *profile, failed: if (pukf) sc_file_free(pukf); - if (prkf) - sc_file_free(prkf); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } diff --git a/src/pkcs15init/pkcs15-gpk.c b/src/pkcs15init/pkcs15-gpk.c index fdcf1871..c6cb63d9 100644 --- a/src/pkcs15init/pkcs15-gpk.c +++ b/src/pkcs15init/pkcs15-gpk.c @@ -458,8 +458,7 @@ gpk_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_objec #endif done: - if (keyfile) - sc_file_free(keyfile); + sc_file_free(keyfile); return r; } @@ -718,7 +717,8 @@ gpk_pkfile_init_public(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file if (r >= 0) { if (r != 7 || buffer[0] != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "first record of public key file is not Lsys0"); - return SC_ERROR_OBJECT_NOT_VALID; + r = SC_ERROR_OBJECT_NOT_VALID; + goto out; } r = sc_update_record(p15card->card, 1, sysrec, sizeof(sysrec), diff --git a/src/pkcs15init/pkcs15-iasecc.c b/src/pkcs15init/pkcs15-iasecc.c index 7df8103e..a7571123 100644 --- a/src/pkcs15init/pkcs15-iasecc.c +++ b/src/pkcs15init/pkcs15-iasecc.c @@ -246,6 +246,8 @@ iasecc_pkcs15_new_file(struct sc_profile *profile, struct sc_card *card, if (out) *out = file; + else + sc_file_free(file); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -396,8 +398,11 @@ iasecc_sdo_set_key_acls_from_profile(struct sc_profile *profile, struct sc_card scb[cntr++] = 0x00; } else if (acl->method == SC_AC_SEN || acl->method == SC_AC_PRO || acl->method == SC_AC_AUT) { - if ((acl->key_ref & 0xF) == 0 || (acl->key_ref & 0xF) == 0xF) + if ((acl->key_ref & 0xF) == 0 || (acl->key_ref & 0xF) == 0xF) { + if (file) + sc_file_free(file); LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Invalid SE reference"); + } amb |= mask; @@ -409,10 +414,15 @@ iasecc_sdo_set_key_acls_from_profile(struct sc_profile *profile, struct sc_card scb[cntr++] = acl->key_ref | IASECC_SCB_METHOD_EXT_AUTH; } else { + if (file) + sc_file_free(file); LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Unknown SCB method"); } } + if (file) + sc_file_free(file); + /* Copy ACLs into the DOCP*/ sdo->docp.acls_contact.tag = IASECC_DOCP_TAG_ACLS_CONTACT; sdo->docp.acls_contact.size = cntr + 1; @@ -503,6 +513,8 @@ iasecc_sdo_allocate_prvkey(struct sc_profile *profile, struct sc_card *card, if (out) *out = sdo; + else + free(sdo); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -565,6 +577,8 @@ iasecc_sdo_allocate_pubkey(struct sc_profile *profile, struct sc_card *card, str if (out) *out = sdo; + else + free(sdo); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -573,16 +587,20 @@ iasecc_sdo_allocate_pubkey(struct sc_profile *profile, struct sc_card *card, str static int iasecc_sdo_convert_to_file(struct sc_card *card, struct iasecc_sdo *sdo, struct sc_file **out) { - struct sc_context *ctx = card->ctx; - struct sc_file *file = sc_file_new(); + struct sc_context *ctx; + struct sc_file *file; unsigned ii; int rv; + if (!card || !sdo) + return SC_ERROR_INVALID_ARGUMENTS; + + ctx = card->ctx; LOG_FUNC_CALLED(ctx); - if (file == NULL) + + file = sc_file_new(); + if (!file) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - else if (!card || !sdo) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SDO class 0x%X", sdo->sdo_class); @@ -596,15 +614,21 @@ iasecc_sdo_convert_to_file(struct sc_card *card, struct iasecc_sdo *sdo, struct unsigned op_method, op_ref; rv = iasecc_sdo_convert_acl(card, sdo, ops[ii], &op_method, &op_ref); - LOG_TEST_RET(ctx, rv, "IasEcc: cannot convert ACL"); - sc_log(ctx, "ii:%i, method:%X, ref:%X", ii, op_method, op_ref); + if (rv < 0) { + sc_file_free(file); + LOG_TEST_RET(ctx, rv, "IasEcc: cannot convert ACL"); + } + sc_log(ctx, "ii:%i, method:%X, ref:%X", ii, op_method, op_ref); sc_file_add_acl_entry(file, ops[ii], op_method, op_ref); } } if (out) *out = file; + else + sc_file_free(file); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -820,17 +844,18 @@ iasecc_sdo_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, if (!sdo_prvkey && !sdo_pubkey) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "At least one SDO has to be supplied"); + rv = iasecc_sdo_convert_to_file(card, sdo_prvkey ? sdo_prvkey : sdo_pubkey, &dummy_file); LOG_TEST_RET(ctx, rv, "Cannot convert SDO PRIVATE KEY to file"); card->caps &= ~SC_CARD_CAP_USE_FCI_AC; rv = sc_pkcs15init_authenticate(profile, p15card, dummy_file, SC_AC_OP_UPDATE); card->caps = caps; - LOG_TEST_RET(ctx, rv, "SDO PRIVATE KEY UPDATE authentication failed"); - if (dummy_file) sc_file_free(dummy_file); + LOG_TEST_RET(ctx, rv, "SDO PRIVATE KEY UPDATE authentication failed"); + memset(&update, 0, sizeof(update)); update.sdo_prv_key = sdo_prvkey; @@ -889,8 +914,6 @@ iasecc_pkcs15_fix_private_key_attributes(struct sc_profile *profile, struct sc_p LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported object type"); key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_SENSITIVE; - key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE; - key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE; sc_log(ctx, "SDO(class:%X,ref:%X,usage:%X)", sdo_prvkey->sdo_class, sdo_prvkey->sdo_ref, sdo_prvkey->usage); @@ -939,9 +962,7 @@ iasecc_pkcs15_fix_private_key_attributes(struct sc_profile *profile, struct sc_p IASECC_ALGORITHM_RSA_PKCS | IASECC_ALGORITHM_SHA2); LOG_TEST_RET(ctx, rv, "Cannot add RSA_PKCS SHA2 supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_SIGN; if (sdo_prvkey->docp.non_repudiation.value && sdo_prvkey->docp.non_repudiation.value[0]) { - key_info->usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; object->user_consent = 1; } } @@ -949,14 +970,12 @@ iasecc_pkcs15_fix_private_key_attributes(struct sc_profile *profile, struct sc_p rv = iasecc_pkcs15_add_algorithm_reference(p15card, key_info, IASECC_ALGORITHM_RSA_PKCS); LOG_TEST_RET(ctx, rv, "Cannot add RSA_PKCS supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; } else if (ii == IASECC_ACLS_RSAKEY_PSO_DECIPHER) { rv = iasecc_pkcs15_add_algorithm_reference(p15card, key_info, IASECC_ALGORITHM_RSA_PKCS_DECRYPT | IASECC_ALGORITHM_SHA1); LOG_TEST_RET(ctx, rv, "Cannot add decipher RSA_PKCS supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP; } } @@ -1129,6 +1148,8 @@ iasecc_pkcs15_generate_key(struct sc_profile *profile, sc_pkcs15_card_t *p15card LOG_TEST_RET(ctx, rv, "SC_AC_OP_GENERATE authentication failed"); key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_LOCAL; + key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE; + key_info->access_flags |= SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE; rv = sc_card_ctl(card, SC_CARDCTL_IASECC_SDO_GENERATE, sdo_prvkey); LOG_TEST_RET(ctx, rv, "generate key failed"); @@ -1267,16 +1288,23 @@ iasecc_pkcs15_delete_sdo (struct sc_profile *profile, struct sc_pkcs15_card *p15 sc_log(ctx, "iasecc_pkcs15_delete_sdo() SDO class 0x%X, ref 0x%X", sdo->sdo_class, sdo->sdo_ref); rv = iasecc_sdo_convert_to_file(card, sdo, &dummy_file); - LOG_TEST_RET(ctx, rv, "iasecc_pkcs15_delete_sdo() Cannot convert SDO to file"); + if (rv < 0) { + iasecc_sdo_free(card, sdo); + LOG_TEST_RET(ctx, rv, "iasecc_pkcs15_delete_sdo() Cannot convert SDO to file"); + } card->caps &= ~SC_CARD_CAP_USE_FCI_AC; rv = sc_pkcs15init_authenticate(profile, p15card, dummy_file, SC_AC_OP_UPDATE); card->caps = save_card_caps; - LOG_TEST_RET(ctx, rv, "iasecc_pkcs15_delete_sdo() UPDATE authentication failed for SDO"); if (dummy_file) sc_file_free(dummy_file); + if (rv < 0) { + iasecc_sdo_free(card, sdo); + LOG_TEST_RET(ctx, rv, "iasecc_pkcs15_delete_sdo() UPDATE authentication failed for SDO"); + } + if (card->type == SC_CARD_TYPE_IASECC_OBERTHUR) { /* Oberthur's card supports creation/deletion of the key slots ... */ rv = sc_card_ctl(card, SC_CARDCTL_IASECC_SDO_DELETE, sdo); @@ -1300,7 +1328,6 @@ iasecc_pkcs15_delete_sdo (struct sc_profile *profile, struct sc_pkcs15_card *p15 /* Don't know why, but, clean public key do not working with Gemalto card */ rv = iasecc_sdo_store_key(profile, p15card, sdo, NULL, &rsa); - LOG_TEST_RET(ctx, rv, "iasecc_pkcs15_delete_sdo() store empty private key failed"); } iasecc_sdo_free(card, sdo); @@ -1313,7 +1340,7 @@ iasecc_pkcs15_delete_object (struct sc_profile *profile, struct sc_pkcs15_card * struct sc_pkcs15_object *object, const struct sc_path *path) { struct sc_context *ctx = p15card->card->ctx; - struct sc_file *file = sc_file_new(); + struct sc_file *file = NULL; int rv, key_ref; LOG_FUNC_CALLED(ctx); @@ -1355,6 +1382,7 @@ iasecc_pkcs15_delete_object (struct sc_profile *profile, struct sc_pkcs15_card * LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } + file = sc_file_new(); file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->id = path->value[path->len-2] * 0x100 + path->value[path->len-1]; @@ -1761,8 +1789,7 @@ iasecc_store_data_object(struct sc_pkcs15_card *p15card, struct sc_profile *prof if (parent) sc_file_free(parent); - if (file) - sc_file_free(file); + sc_file_free(file); if (cfile) sc_file_free(cfile); diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index a301b200..e4240096 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -216,7 +216,6 @@ struct sc_pkcs15init_prkeyargs { union { struct sc_pkcs15init_keyarg_gost_params gost; - struct sc_pkcs15_ec_parameters ec; } params; struct sc_pkcs15_prkey key; @@ -236,7 +235,6 @@ struct sc_pkcs15init_pubkeyargs { union { struct sc_pkcs15init_keyarg_gost_params gost; - struct sc_pkcs15_ec_parameters ec; } params; struct sc_pkcs15_pubkey key; @@ -267,6 +265,7 @@ struct sc_pkcs15init_skeyargs { struct sc_pkcs15init_certargs { struct sc_pkcs15_id id; const char * label; + int update; unsigned long x509_usage; unsigned char authority; @@ -422,6 +421,7 @@ extern struct sc_pkcs15init_operations *sc_pkcs15init_get_iasecc_ops(void); extern struct sc_pkcs15init_operations *sc_pkcs15init_get_piv_ops(void); extern struct sc_pkcs15init_operations *sc_pkcs15init_get_openpgp_ops(void); extern struct sc_pkcs15init_operations *sc_pkcs15init_get_sc_hsm_ops(void); +extern struct sc_pkcs15init_operations *sc_pkcs15init_get_isoApplet_ops(void); #ifdef __cplusplus } diff --git a/src/pkcs15init/pkcs15-isoApplet.c b/src/pkcs15init/pkcs15-isoApplet.c new file mode 100644 index 00000000..99db23a7 --- /dev/null +++ b/src/pkcs15init/pkcs15-isoApplet.c @@ -0,0 +1,796 @@ +/* + * pkcs15-init driver for JavaCards with IsoApplet installed. + * + * Copyright (C) 2014 Philip Wendland + * + * 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 "config.h" + +#include +#include +#include +#include +#include + +#include "../libopensc/log.h" +#include "../libopensc/internal.h" +#include "../libopensc/opensc.h" +#include "../libopensc/cardctl.h" +#include "../libopensc/asn1.h" +#include "pkcs15-init.h" +#include "profile.h" + +#define ISOAPPLET_KEY_ID_MIN 0 +#define ISOAPPLET_KEY_ID_MAX 15 + +/* Curve parameters of a curve specified by the OID. */ +struct ec_curve +{ + const struct sc_lv_data oid; /* Object ID in hex, including structural information */ + const struct sc_lv_data prime; + const struct sc_lv_data coefficientA; + const struct sc_lv_data coefficientB; + const struct sc_lv_data basePointG; + const struct sc_lv_data order; + const struct sc_lv_data coFactor; +}; + +/* OpenSC only works with named curves, but we need the + * explicit parameters for ECC key generation or import. */ +static const struct ec_curve curves[] = +{ + { + /* brainpoolP192r1 */ + { (unsigned char *) "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x03", 11}, + { (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}, + { (unsigned char *) "\x46\x9A\x28\xEF\x7C\x28\xCC\xA3\xDC\x72\x1D\x04\x4F\x44\x96\xBC\xCA\x7E\xF4\x14\x6F\xBF\x25\xC9", 24}, + { (unsigned char *) "\x04\xC0\xA0\x64\x7E\xAA\xB6\xA4\x87\x53\xB0\x33\xC5\x6C\xB0\xF0\x90\x0A\x2F\x5C\x48\x53\x37\x5F\xD6\x14\xB6\x90\x86\x6A\xBD\x5B\xB8\x8B\x5F\x48\x28\xC1\x49\x00\x02\xE6\x77\x3F\xA2\xFA\x29\x9B\x8F", 49}, + { (unsigned char *) "\xC3\x02\xF4\x1D\x93\x2A\x36\xCD\xA7\xA3\x46\x2F\x9E\x9E\x91\x6B\x5B\xE8\xF1\x02\x9A\xC4\xAC\xC1", 24}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* brainpoolP224r1 */ + { (unsigned char *) "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x05", 11}, + { (unsigned char *) "\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD1\xD7\x87\xB0\x9F\x07\x57\x97\xDA\x89\xF5\x7E\xC8\xC0\xFF", 28}, + { (unsigned char *) "\x68\xA5\xE6\x2C\xA9\xCE\x6C\x1C\x29\x98\x03\xA6\xC1\x53\x0B\x51\x4E\x18\x2A\xD8\xB0\x04\x2A\x59\xCA\xD2\x9F\x43", 28}, + { (unsigned char *) "\x25\x80\xF6\x3C\xCF\xE4\x41\x38\x87\x07\x13\xB1\xA9\x23\x69\xE3\x3E\x21\x35\xD2\x66\xDB\xB3\x72\x38\x6C\x40\x0B", 28}, + { (unsigned char *) "\x04\x0D\x90\x29\xAD\x2C\x7E\x5C\xF4\x34\x08\x23\xB2\xA8\x7D\xC6\x8C\x9E\x4C\xE3\x17\x4C\x1E\x6E\xFD\xEE\x12\xC0\x7D\x58\xAA\x56\xF7\x72\xC0\x72\x6F\x24\xC6\xB8\x9E\x4E\xCD\xAC\x24\x35\x4B\x9E\x99\xCA\xA3\xF6\xD3\x76\x14\x02\xCD", 57}, + { (unsigned char *) "\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD0\xFB\x98\xD1\x16\xBC\x4B\x6D\xDE\xBC\xA3\xA5\xA7\x93\x9F", 28}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* brainpoolP256r1 */ + { (unsigned char *) "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x07", 11}, + { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, + { (unsigned char *) "\x7D\x5A\x09\x75\xFC\x2C\x30\x57\xEE\xF6\x75\x30\x41\x7A\xFF\xE7\xFB\x80\x55\xC1\x26\xDC\x5C\x6C\xE9\x4A\x4B\x44\xF3\x30\xB5\xD9", 32}, + { (unsigned char *) "\x26\xDC\x5C\x6C\xE9\x4A\x4B\x44\xF3\x30\xB5\xD9\xBB\xD7\x7C\xBF\x95\x84\x16\x29\x5C\xF7\xE1\xCE\x6B\xCC\xDC\x18\xFF\x8C\x07\xB6", 32}, + { (unsigned char *) "\x04\x8B\xD2\xAE\xB9\xCB\x7E\x57\xCB\x2C\x4B\x48\x2F\xFC\x81\xB7\xAF\xB9\xDE\x27\xE1\xE3\xBD\x23\xC2\x3A\x44\x53\xBD\x9A\xCE\x32\x62\x54\x7E\xF8\x35\xC3\xDA\xC4\xFD\x97\xF8\x46\x1A\x14\x61\x1D\xC9\xC2\x77\x45\x13\x2D\xED\x8E\x54\x5C\x1D\x54\xC7\x2F\x04\x69\x97", 65}, + { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x71\x8C\x39\x7A\xA3\xB5\x61\xA6\xF7\x90\x1E\x0E\x82\x97\x48\x56\xA7", 32}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* brainpoolP320r1 */ + { (unsigned char *) "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x09", 11}, + { (unsigned char *) "\xD3\x5E\x47\x20\x36\xBC\x4F\xB7\xE1\x3C\x78\x5E\xD2\x01\xE0\x65\xF9\x8F\xCF\xA6\xF6\xF4\x0D\xEF\x4F\x92\xB9\xEC\x78\x93\xEC\x28\xFC\xD4\x12\xB1\xF1\xB3\x2E\x27", 40}, + { (unsigned char *) "\x3E\xE3\x0B\x56\x8F\xBA\xB0\xF8\x83\xCC\xEB\xD4\x6D\x3F\x3B\xB8\xA2\xA7\x35\x13\xF5\xEB\x79\xDA\x66\x19\x0E\xB0\x85\xFF\xA9\xF4\x92\xF3\x75\xA9\x7D\x86\x0E\xB4", 40}, + { (unsigned char *) "\x52\x08\x83\x94\x9D\xFD\xBC\x42\xD3\xAD\x19\x86\x40\x68\x8A\x6F\xE1\x3F\x41\x34\x95\x54\xB4\x9A\xCC\x31\xDC\xCD\x88\x45\x39\x81\x6F\x5E\xB4\xAC\x8F\xB1\xF1\xA6", 40}, + { (unsigned char *) "\x04\x43\xBD\x7E\x9A\xFB\x53\xD8\xB8\x52\x89\xBC\xC4\x8E\xE5\xBF\xE6\xF2\x01\x37\xD1\x0A\x08\x7E\xB6\xE7\x87\x1E\x2A\x10\xA5\x99\xC7\x10\xAF\x8D\x0D\x39\xE2\x06\x11\x14\xFD\xD0\x55\x45\xEC\x1C\xC8\xAB\x40\x93\x24\x7F\x77\x27\x5E\x07\x43\xFF\xED\x11\x71\x82\xEA\xA9\xC7\x78\x77\xAA\xAC\x6A\xC7\xD3\x52\x45\xD1\x69\x2E\x8E\xE1", 81}, + { (unsigned char *) "\xD3\x5E\x47\x20\x36\xBC\x4F\xB7\xE1\x3C\x78\x5E\xD2\x01\xE0\x65\xF9\x8F\xCF\xA5\xB6\x8F\x12\xA3\x2D\x48\x2E\xC7\xEE\x86\x58\xE9\x86\x91\x55\x5B\x44\xC5\x93\x11", 40}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* prime192v1, secp192r1, ansiX9p192r1 */ + { (unsigned char *) "\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x01", 10}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC", 24}, + { (unsigned char *) "\x64\x21\x05\x19\xE5\x9C\x80\xE7\x0F\xA7\xE9\xAB\x72\x24\x30\x49\xFE\xB8\xDE\xEC\xC1\x46\xB9\xB1", 24}, + { (unsigned char *) "\x04\x18\x8D\xA8\x0E\xB0\x30\x90\xF6\x7C\xBF\x20\xEB\x43\xA1\x88\x00\xF4\xFF\x0A\xFD\x82\xFF\x10\x12\x07\x19\x2B\x95\xFF\xC8\xDA\x78\x63\x10\x11\xED\x6B\x24\xCD\xD5\x73\xF9\x77\xA1\x1E\x79\x48\x11", 49}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x99\xDE\xF8\x36\x14\x6B\xC9\xB1\xB4\xD2\x28\x31", 24}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* prime224v1, nistp224 */ + { (unsigned char *) "\x06\x05\x2b\x81\x04\x00\x21", 7}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 28}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 28}, + { (unsigned char *) "\xB4\x05\x0A\x85\x0C\x04\xB3\xAB\xF5\x41\x32\x56\x50\x44\xB0\xB7\xD7\xBF\xD8\xBA\x27\x0B\x39\x43\x23\x55\xFF\xB4", 28}, + { (unsigned char *) "\x04\xB7\x0E\x0C\xBD\x6B\xB4\xBF\x7F\x32\x13\x90\xB9\x4A\x03\xC1\xD3\x56\xC2\x11\x22\x34\x32\x80\xD6\x11\x5C\x1D\x21\xBD\x37\x63\x88\xB5\xF7\x23\xFB\x4C\x22\xDF\xE6\xCD\x43\x75\xA0\x5A\x07\x47\x64\x44\xD5\x81\x99\x85\x00\x7E\x34", 57}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\xA2\xE0\xB8\xF0\x3E\x13\xDD\x29\x45\x5C\x5C\x2A\x3D", 28}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* prime256v1, secp256r1, ansiX9p256r1 */ + { (unsigned char *) "\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", 10}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC", 32}, + { (unsigned char *) "\x5A\xC6\x35\xD8\xAA\x3A\x93\xE7\xB3\xEB\xBD\x55\x76\x98\x86\xBC\x65\x1D\x06\xB0\xCC\x53\xB0\xF6\x3B\xCE\x3C\x3E\x27\xD2\x60\x4B", 32}, + { (unsigned char *) "\x04\x6B\x17\xD1\xF2\xE1\x2C\x42\x47\xF8\xBC\xE6\xE5\x63\xA4\x40\xF2\x77\x03\x7D\x81\x2D\xEB\x33\xA0\xF4\xA1\x39\x45\xD8\x98\xC2\x96\x4F\xE3\x42\xE2\xFE\x1A\x7F\x9B\x8E\xE7\xEB\x4A\x7C\x0F\x9E\x16\x2B\xCE\x33\x57\x6B\x31\x5E\xCE\xCB\xB6\x40\x68\x37\xBF\x51\xF5", 65}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51", 32}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* prime384v1, secp384r1, ansiX9p384r1 */ + { (unsigned char *) "\x06\x05\x2B\x81\x04\x00\x22", 7}, + { (unsigned char *) "\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\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, + { (unsigned char *) "\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\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFC", 48}, + { (unsigned char *) "\xB3\x31\x2F\xA7\xE2\x3E\xE7\xE4\x98\x8E\x05\x6B\xE3\xF8\x2D\x19\x18\x1D\x9C\x6E\xFE\x81\x41\x12\x03\x14\x08\x8F\x50\x13\x87\x5A\xC6\x56\x39\x8D\x8A\x2E\xD1\x9D\x2A\x85\xC8\xED\xD3\xEC\x2A\xEF", 48}, + { (unsigned char *) "\x04\xAA\x87\xCA\x22\xBE\x8B\x05\x37\x8E\xB1\xC7\x1E\xF3\x20\xAD\x74\x6E\x1D\x3B\x62\x8B\xA7\x9B\x98\x59\xF7\x41\xE0\x82\x54\x2A\x38\x55\x02\xF2\x5D\xBF\x55\x29\x6C\x3A\x54\x5E\x38\x72\x76\x0A\xB7\x36\x17\xDE\x4A\x96\x26\x2C\x6F\x5D\x9E\x98\xBF\x92\x92\xDC\x29\xF8\xF4\x1D\xBD\x28\x9A\x14\x7C\xE9\xDA\x31\x13\xB5\xF0\xB8\xC0\x0A\x60\xB1\xCE\x1D\x7E\x81\x9D\x7A\x43\x1D\x7C\x90\xEA\x0E\x5F", 97}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC7\x63\x4D\x81\xF4\x37\x2D\xDF\x58\x1A\x0D\xB2\x48\xB0\xA7\x7A\xEC\xEC\x19\x6A\xCC\xC5\x29\x73", 48}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* secp192k1 */ + { (unsigned char *) "\x06\x05\x2B\x81\x04\x00\x1F", 7}, + { (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}, + { (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\x03", 24}, + { (unsigned char *) "\x04\xDB\x4F\xF1\x0E\xC0\x57\xE9\xAE\x26\xB0\x7D\x02\x80\xB7\xF4\x34\x1D\xA5\xD1\xB1\xEA\xE0\x6C\x7D\x9B\x2F\x2F\x6D\x9C\x56\x28\xA7\x84\x41\x63\xD0\x15\xBE\x86\x34\x40\x82\xAA\x88\xD9\x5E\x2F\x9D", 49}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x26\xF2\xFC\x17\x0F\x69\x46\x6A\x74\xDE\xFD\x8D", 24}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + /* secp256k1 */ + { (unsigned char *) "\x06\x05\x2B\x81\x04\x00\x0A", 7}, + { (unsigned char *) "\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\xFE\xFF\xFF\xFC\x2F", 32}, + { (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\x00\x00\x00\x00\x00\x00\x00\x00", 32}, + { (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\x00\x00\x00\x00\x00\x00\x00\x07", 32}, + { (unsigned char *) "\x04\x79\xBE\x66\x7E\xF9\xDC\xBB\xAC\x55\xA0\x62\x95\xCE\x87\x0B\x07\x02\x9B\xFC\xDB\x2D\xCE\x28\xD9\x59\xF2\x81\x5B\x16\xF8\x17\x98\x48\x3A\xDA\x77\x26\xA3\xC4\x65\x5D\xA4\xFB\xFC\x0E\x11\x08\xA8\xFD\x17\xB4\x48\xA6\x85\x54\x19\x9C\x47\xD0\x8F\xFB\x10\xD4\xB8", 65}, + { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xBA\xAE\xDC\xE6\xAF\x48\xA0\x3B\xBF\xD2\x5E\x8C\xD0\x36\x41\x41", 32}, + { (unsigned char *) "\x00\x01", 2} + }, + + { + { NULL, 0}, + { NULL, 0}, + { NULL, 0}, + { NULL, 0}, + { NULL, 0}, + { NULL, 0}, + { NULL, 0} + } +}; + + +/* + * Create DF, using default pkcs15init functions. + */ +static int +isoApplet_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) +{ + sc_card_t *card = p15card->card; + int r = SC_SUCCESS; + + LOG_FUNC_CALLED(card->ctx); + + if(!profile || !p15card || !df || !p15card->card || !p15card->card->ctx) + { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } + r = sc_pkcs15init_create_file(profile, p15card, df); + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * Select a PIN reference. + * + * Basically (as I understand it) the caller passes an auth_info object and the + * auth_info->attrs.pin.reference is supposed to be set accordingly and return. + * + * The IsoApplet only supports a PIN and a PUK at the moment. + * The reference for the PIN is 1, for the PUK 2. + */ +static int +isoApplet_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, + sc_pkcs15_auth_info_t *auth_info) +{ + sc_card_t *card = p15card->card; + int preferred; + int current; + + LOG_FUNC_CALLED(card->ctx); + + if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) + { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); + } + + current = auth_info->attrs.pin.reference; + if (current < 0) + { + current = 0; + } + + if(current > 2) + { + /* Only two PINs supported: User PIN and PUK. */ + LOG_FUNC_RETURN(card->ctx, SC_ERROR_TOO_MANY_OBJECTS); + } + else + { + if(auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) + { + /* PUK */ + preferred = 2; + } + else + { + /* PIN */ + preferred = 1; + } + } + + auth_info->attrs.pin.reference = preferred; + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +/* + * Create a PIN and store it on the card using CHANGE REFERENCE DATA for PIN transmission. + * First, the PUK is transmitted, then the PIN. Now, the IsoApplet is in the + * "STATE_OPERATIONAL_ACTIVATED" lifecycle state. + */ +static int +isoApplet_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, + sc_pkcs15_object_t *pin_obj, + const u8 *pin, size_t pin_len, + const u8 *puk, size_t puk_len) +{ + sc_card_t *card = p15card->card; + sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; + struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin; + int r; + + LOG_FUNC_CALLED(card->ctx); + + if(!pin || !pin_len || !p15card || !p15card->card || !df || !&df->path) + { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } + + if(pin_attrs->reference != 1 && pin_attrs->reference != 2) + { + /* Reject PIN reference. */ + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_PIN_REFERENCE); + } + + /* If we have a PUK, set it first. */ + if(puk && puk_len) + { + /* The PUK has a incremented reference, i.e. pins are odd, puks are equal (+1). */ + r = sc_change_reference_data(p15card->card, SC_AC_CHV, + pin_attrs->reference+1, + NULL, 0, + puk, puk_len, NULL); + if(r < 0) + { + LOG_FUNC_RETURN(card->ctx, r); + } + } + + /* Store PIN: (use CHANGE REFERENCE DATA). */ + r = sc_change_reference_data(p15card->card, SC_AC_CHV, + pin_attrs->reference, + NULL, 0, + pin, pin_len, NULL); + + LOG_FUNC_RETURN(card->ctx, r); +} + +/* + * @brief Get the curve parameters associated with the curve specified by an OID. + * + * @param[in] oid The DER encoded OID of the curve. + * @param[in] oid_len The length of oid. + * @param[out] curve_out The ec_curve containing the set of parameters. + * + * @returns SC_SUCCESS: If the curve was found. + * SC_ERROR_INVALID_ARGUMENTS: If named_curve was null or the curve + * was not found + */ +static int +isoApplet_get_curve(u8 *oid, size_t oid_len, const struct ec_curve **curve_out) +{ + int i; + + if(!oid) + return SC_ERROR_INVALID_ARGUMENTS; + + /* Search the curve parameters. */ + for (i = 0; curves[i].oid.value; i++) + { + if (oid_len == curves[i].oid.len && memcmp(oid, curves[i].oid.value, curves[i].oid.len) == 0) + { + *curve_out = &curves[i]; + return SC_SUCCESS; + } + } + + return SC_ERROR_INVALID_ARGUMENTS; +} + + +/* + * @brief Generate a RSA private key on the card. + * + * A MANAGE SECURITY ENVIRONMENT apdu must have been sent before. + * This function uses card_ctl to access the card-isoApplet driver. + * + * @param[in] key_info + * @param[in] card + * @param[in] pubkey The public key of the generated key pair + * returned by the card. + * + * @return SC_ERROR_INVALID_ARGURMENTS: Invalid key length. + * SC_ERROR_OUT_OF_MEMORY + */ +static int +isoApplet_generate_key_rsa(sc_pkcs15_prkey_info_t *key_info, sc_card_t *card, + sc_pkcs15_pubkey_t *pubkey) +{ + int rv; + size_t keybits; + struct sc_cardctl_isoApplet_genkey args; + + LOG_FUNC_CALLED(card->ctx); + + /* Check key size: */ + keybits = key_info->modulus_length; + if (keybits != 2048) + { + rv = SC_ERROR_INVALID_ARGUMENTS; + sc_log(card->ctx, "%s: RSA private key length is unsupported, correct length is 2048", sc_strerror(rv)); + goto err; + } + + /* Generate the key. + * Note: key size is not explicitly passed to the card. + * It assumes 2048 along with the algorithm reference. */ + memset(&args, 0, sizeof(args)); + args.algorithm_ref = SC_ISOAPPLET_ALG_REF_RSA_GEN_2048; + args.priv_key_ref = key_info->key_reference; + + args.pubkey.rsa.modulus.len = keybits / 8; + args.pubkey.rsa.modulus.value = malloc(args.pubkey.rsa.modulus.len); + if (!args.pubkey.rsa.modulus.value) + { + rv = SC_ERROR_OUT_OF_MEMORY; + sc_log(card->ctx, "%s: Unable to allocate public key buffer.", sc_strerror(rv)); + goto err; + } + + args.pubkey.rsa.exponent.len = 3; + args.pubkey.rsa.exponent.value = malloc(args.pubkey.rsa.exponent.len); + if(!args.pubkey.rsa.exponent.value) + { + rv = SC_ERROR_OUT_OF_MEMORY; + sc_log(card->ctx, "%s: Unable to allocate public key exponent buffer.", sc_strerror(rv)); + goto err; + } + + rv = sc_card_ctl(card, SC_CARDCTL_ISOAPPLET_GENERATE_KEY, &args); + if (rv < 0) + { + sc_log(card->ctx, "%s: Error in card_ctl", sc_strerror(rv)); + goto err; + } + + /* extract the public key */ + pubkey->algorithm = SC_ALGORITHM_RSA; + pubkey->u.rsa.modulus.len = args.pubkey.rsa.modulus.len; + pubkey->u.rsa.modulus.data = args.pubkey.rsa.modulus.value; + pubkey->u.rsa.exponent.len = args.pubkey.rsa.exponent.len; + pubkey->u.rsa.exponent.data = args.pubkey.rsa.exponent.value; + rv = SC_SUCCESS; + LOG_FUNC_RETURN(card->ctx, rv); +err: + if (args.pubkey.rsa.modulus.value) + { + free(args.pubkey.rsa.modulus.value); + pubkey->u.rsa.modulus.data = NULL; + pubkey->u.rsa.modulus.len = 0; + } + if (args.pubkey.rsa.exponent.value) + { + free(args.pubkey.rsa.exponent.value); + pubkey->u.rsa.exponent.data = NULL; + pubkey->u.rsa.exponent.len = 0; + } + LOG_FUNC_RETURN(card->ctx, rv); +} + +/* + * @brief Generate a EC private key on the card. + * + * A MANAGE SECURITY ENVIRONMENT apdu must have been sent before. + * This function uses card_ctl to access the card-isoApplet driver. + * + * @param[in] key_info + * @param[in] card + * @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. + * SC_ERROR_OUT_OF_MEMORY + * SC_ERROR_INCOMPATIBLE_KEY: The data returned by the card + * was unexpected and can not be + * handled. + */ +static int +isoApplet_generate_key_ec(const sc_pkcs15_prkey_info_t *key_info, sc_card_t *card, + sc_pkcs15_pubkey_t *pubkey) +{ + int r; + const struct ec_curve *curve = NULL; + struct sc_ec_parameters *alg_id_params = NULL; + sc_cardctl_isoApplet_genkey_t args; + const struct sc_ec_parameters *info_ecp = + (struct sc_ec_parameters *) key_info->params.data; + + LOG_FUNC_CALLED(card->ctx); + + /* Check key size: */ + if(key_info->field_length == 0) + { + sc_log(card->ctx, "Unknown field length."); + r = SC_ERROR_INVALID_ARGUMENTS; + goto out; + } + + r = isoApplet_get_curve(info_ecp->der.value, info_ecp->der.len, &curve); + if(r < 0) + { + sc_log(card->ctx, "EC key generation failed: Unsupported curve: [%s].", info_ecp->named_curve); + goto out; + } + + /* Generate the key. + * Note: The field size is not explicitly passed to the card. + * As we only support FP curves, the field length can be calculated from any parameter. */ + memset(&args, 0, sizeof(args)); + + args.pubkey.ec.params.prime.value = curve->prime.value; + args.pubkey.ec.params.prime.len = curve->prime.len; + args.pubkey.ec.params.coefficientA.value = curve->coefficientA.value; + args.pubkey.ec.params.coefficientA.len = curve->coefficientA.len; + args.pubkey.ec.params.coefficientB.value = curve->coefficientB.value; + args.pubkey.ec.params.coefficientB.len = curve->coefficientB.len; + args.pubkey.ec.params.basePointG.value = curve->basePointG.value; + args.pubkey.ec.params.basePointG.len = curve->basePointG.len; + args.pubkey.ec.params.order.value = curve->order.value; + args.pubkey.ec.params.order.len = curve->order.len; + args.pubkey.ec.params.coFactor.value = curve->coFactor.value; + args.pubkey.ec.params.coFactor.len = curve->coFactor.len; + /* The length of the public key point will be: + * Uncompressed tag + 2 * field length in bytes. */ + args.pubkey.ec.ecPointQ.len = 1 + (key_info->field_length + 7) / 8 * 2; + args.pubkey.ec.ecPointQ.value = malloc(args.pubkey.ec.ecPointQ.len); + if(!args.pubkey.ec.ecPointQ.value) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + + args.algorithm_ref = SC_ISOAPPLET_ALG_REF_EC_GEN; + args.priv_key_ref = key_info->key_reference; + + /* On-card key generation */ + r = sc_card_ctl(card, SC_CARDCTL_ISOAPPLET_GENERATE_KEY, &args); + if (r < 0) + { + sc_log(card->ctx, "%s: Error in card_ctl.", sc_strerror(r)); + goto out; + } + + /* Extract and compose the public key. */ + pubkey->algorithm = SC_ALGORITHM_EC; + + /* der-encoded parameters */ + alg_id_params = calloc(1, sizeof(*alg_id_params)); + if(!alg_id_params) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + alg_id_params->der.len = curve->oid.len; + alg_id_params->der.value = malloc(alg_id_params->der.len); + if(!alg_id_params->der.value) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + memcpy(alg_id_params->der.value, curve->oid.value, curve->oid.len); + alg_id_params->type = 1; /* named curve */ + + pubkey->alg_id = malloc(sizeof(*pubkey->alg_id)); + if(!pubkey->alg_id) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + pubkey->alg_id->algorithm = SC_ALGORITHM_EC; + pubkey->alg_id->params = alg_id_params; + + /* Extract ecpointQ */ + pubkey->u.ec.ecpointQ.len = args.pubkey.ec.ecPointQ.len; + pubkey->u.ec.ecpointQ.value = malloc(pubkey->u.ec.ecpointQ.len); + if(!pubkey->u.ec.ecpointQ.value) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + memcpy(pubkey->u.ec.ecpointQ.value, args.pubkey.ec.ecPointQ.value, args.pubkey.ec.ecPointQ.len); + + /* The OID is also written to the pubkey->u.ec.params */ + pubkey->u.ec.params.der.value = malloc(alg_id_params->der.len); + if(!pubkey->u.ec.params.der.value) + { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } + memcpy(pubkey->u.ec.params.der.value, alg_id_params->der.value, alg_id_params->der.len); + pubkey->u.ec.params.der.len = alg_id_params->der.len; + r = sc_pkcs15_fix_ec_parameters(card->ctx, &pubkey->u.ec.params); +out: + if(args.pubkey.ec.ecPointQ.value) + { + free(args.pubkey.ec.ecPointQ.value); + args.pubkey.ec.ecPointQ.value = NULL; + } + if(r < 0 && pubkey) + { + if(pubkey->alg_id) + { + free(pubkey->alg_id); + pubkey->alg_id = NULL; + } + if(pubkey->u.ec.params.der.value) + { + free(pubkey->u.ec.params.der.value); + pubkey->u.ec.params.der.value = NULL; + pubkey->u.ec.params.der.len = 0; + } + if(r < 0 && pubkey->u.ec.ecpointQ.value) + { + free(pubkey->u.ec.ecpointQ.value); + pubkey->u.ec.ecpointQ.value = NULL; + pubkey->u.ec.ecpointQ.len = 0; + } + memset(pubkey, 0, sizeof(sc_pkcs15_pubkey_t)); + } + if(r < 0 && alg_id_params) + { + if(alg_id_params->der.value) + { + free(alg_id_params->der.value); + alg_id_params->der.value = NULL; + } + free(alg_id_params); + pubkey->alg_id->params = NULL; + } + LOG_FUNC_RETURN(card->ctx, r); +} + +static int +isoApplet_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, + sc_pkcs15_object_t *obj, + sc_pkcs15_pubkey_t *pubkey) +{ + int r; + sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; + sc_file_t *privKeyFile=NULL; + sc_card_t *card = p15card->card; + + LOG_FUNC_CALLED(card->ctx); + + /* Authentication stuff. */ + r = sc_profile_get_file_by_path(profile, &key_info->path, &privKeyFile); + if(!privKeyFile) + { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); + } + r = sc_pkcs15init_authenticate(profile, p15card, privKeyFile, SC_AC_OP_CREATE_EF); + if(r < 0) + { + sc_file_free(privKeyFile); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); + } + sc_file_free(privKeyFile); + + /* Generate the key. */ + switch(obj->type) + { + case SC_PKCS15_TYPE_PRKEY_RSA: + r = isoApplet_generate_key_rsa(key_info, card, pubkey); + break; + + case SC_PKCS15_TYPE_PRKEY_EC: + r = isoApplet_generate_key_ec(key_info, card, pubkey); + break; + + default: + r = SC_ERROR_NOT_SUPPORTED; + sc_log(card->ctx, "%s: Key generation failed: Unknown/unsupported key type.", strerror(r)); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + +/* + * Create a new key file. This is a no-op, because private keys are stored as key objects on the javacard. + */ +static int +isoApplet_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) +{ + sc_card_t *card = p15card->card; + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +/* + * Select a key reference. + */ +static int +isoApplet_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, + sc_pkcs15_prkey_info_t *key_info) +{ + int rv = SC_SUCCESS; + sc_card_t *card = p15card->card; + + LOG_FUNC_CALLED(card->ctx); + + if(key_info->key_reference < ISOAPPLET_KEY_ID_MIN) + { + key_info->key_reference = ISOAPPLET_KEY_ID_MIN; + rv = SC_SUCCESS; + } + if(key_info->key_reference > ISOAPPLET_KEY_ID_MAX) + { + rv = SC_ERROR_TOO_MANY_OBJECTS; + } + LOG_FUNC_RETURN(card->ctx, rv); +} + +/* + * Store a usable private key on the card. + */ +static int +isoApplet_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *object, + sc_pkcs15_prkey_t *key) +{ + sc_card_t *card = p15card->card; + sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) object->data; + sc_file_t *privKeyFile=NULL; + sc_cardctl_isoApplet_import_key_t args; + int r; + + LOG_FUNC_CALLED(card->ctx); + + /* Authentication stuff. */ + r = sc_profile_get_file_by_path(profile, &key_info->path, &privKeyFile); + if(!privKeyFile) + { + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); + } + r = sc_pkcs15init_authenticate(profile, p15card, privKeyFile, SC_AC_OP_CREATE_EF); + if(r < 0) + { + sc_file_free(privKeyFile); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); + } + sc_file_free(privKeyFile); + + /* Key import. */ + switch(object->type) + { + case SC_PKCS15_TYPE_PRKEY_RSA: + args.algorithm_ref = SC_ISOAPPLET_ALG_REF_RSA_GEN_2048; + if(!key->u.rsa.p.data + ||!key->u.rsa.q.data + ||!key->u.rsa.iqmp.data + ||!key->u.rsa.dmp1.data + ||!key->u.rsa.dmq1.data) + { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Only CRT RSA keys may be imported."); + } + args.privkey.rsa.p.value = key->u.rsa.p.data; + args.privkey.rsa.p.len = key->u.rsa.p.len; + args.privkey.rsa.q.value = key->u.rsa.q.data; + args.privkey.rsa.q.len = key->u.rsa.q.len; + args.privkey.rsa.iqmp.value = key->u.rsa.iqmp.data; + args.privkey.rsa.iqmp.len = key->u.rsa.iqmp.len; + args.privkey.rsa.dmp1.value = key->u.rsa.dmp1.data; + args.privkey.rsa.dmp1.len = key->u.rsa.dmp1.len; + args.privkey.rsa.dmq1.value = key->u.rsa.dmq1.data; + args.privkey.rsa.dmq1.len = key->u.rsa.dmq1.len; + break; + + case SC_PKCS15_TYPE_PRKEY_EC: + { + const struct ec_curve *curve = NULL; + + 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."); + } + 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"); + args.privkey.ec.params.prime.value = curve->prime.value; + args.privkey.ec.params.prime.len = curve->prime.len; + args.privkey.ec.params.coefficientA.value = curve->coefficientA.value; + args.privkey.ec.params.coefficientA.len = curve->coefficientA.len; + args.privkey.ec.params.coefficientB.value = curve->coefficientB.value; + args.privkey.ec.params.coefficientB.len = curve->coefficientB.len; + args.privkey.ec.params.basePointG.value = curve->basePointG.value; + args.privkey.ec.params.basePointG.len = curve->basePointG.len; + args.privkey.ec.params.order.value = curve->order.value; + args.privkey.ec.params.order.len = curve->order.len; + args.privkey.ec.params.coFactor.value = curve->coFactor.value; + args.privkey.ec.params.coFactor.len = curve->coFactor.len; + args.privkey.ec.privateD.value = key->u.ec.privateD.data; + args.privkey.ec.privateD.len = key->u.ec.privateD.len; + } + break; + + default: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + } + args.priv_key_ref = key_info->key_reference; + + r = sc_card_ctl(card, SC_CARDCTL_ISOAPPLET_IMPORT_KEY, &args); + if (r < 0) + { + sc_log(card->ctx, "%s: Error in card_ctl", sc_strerror(r)); + LOG_FUNC_RETURN(card->ctx, r); + } + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static struct sc_pkcs15init_operations sc_pkcs15init_isoApplet_operations = +{ + NULL, /* erase_card */ + NULL, /* init_card */ + isoApplet_create_dir, /* create_dir */ + NULL, /* create_domain */ + isoApplet_select_pin_reference, /* pin_reference*/ + isoApplet_create_pin, /* create_pin */ + isoApplet_select_key_reference, /* key_reference */ + isoApplet_create_key, /* create_key */ + isoApplet_store_key, /* store_key */ + isoApplet_generate_key, /* generate_key */ + NULL, NULL, /* encode private/public key */ + NULL, /* finalize */ + NULL, /* delete_object */ + NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ + NULL, /* sanity_check*/ +}; + +struct +sc_pkcs15init_operations *sc_pkcs15init_get_isoApplet_ops(void) +{ + return &sc_pkcs15init_isoApplet_operations; +} diff --git a/src/pkcs15init/pkcs15-jcop.c b/src/pkcs15init/pkcs15-jcop.c index b20e09f2..31854529 100644 --- a/src/pkcs15init/pkcs15-jcop.c +++ b/src/pkcs15init/pkcs15-jcop.c @@ -140,10 +140,10 @@ jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_obje size_t bytes, mod_len, prv_len; int r; - if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "JCOP supports only RSA keys."); - return SC_ERROR_NOT_SUPPORTED; - } + if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { + sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "JCOP supports only RSA keys."); + return SC_ERROR_NOT_SUPPORTED; + } /* The caller is supposed to have chosen a key file path for us */ if (key_info->path.len == 0 || key_info->modulus_length == 0) return SC_ERROR_INVALID_ARGUMENTS; @@ -155,7 +155,7 @@ jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_obje mod_len = key_info->modulus_length / 8; bytes = mod_len / 2; - prv_len = 2 + 5 * bytes; + prv_len = 2 + 5 * bytes; keyfile->size = prv_len; /* Fix up PIN references in file ACL */ @@ -164,8 +164,7 @@ jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_obje if (r >= 0) r = sc_pkcs15init_create_file(profile, p15card, keyfile); - if (keyfile) - sc_file_free(keyfile); + sc_file_free(keyfile); return r; } diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 913450a2..09feb0ad 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -154,6 +154,7 @@ static struct profile_operations { { "westcos", (void *) sc_pkcs15init_get_westcos_ops }, { "myeid", (void *) sc_pkcs15init_get_myeid_ops }, { "sc-hsm", (void *) sc_pkcs15init_get_sc_hsm_ops }, + { "isoApplet", (void *) sc_pkcs15init_get_isoApplet_ops }, #ifdef ENABLE_OPENSSL { "authentic", (void *) sc_pkcs15init_get_authentic_ops }, { "iasecc", (void *) sc_pkcs15init_get_iasecc_ops }, @@ -350,7 +351,7 @@ sc_pkcs15init_bind(struct sc_card *card, const char *name, const char *profile_o * If none is defined, use the default profile name. */ if (!get_profile_from_config(card, card_profile, sizeof(card_profile))) - strcpy(card_profile, driver); + strlcpy(card_profile, driver, sizeof card_profile); if (profile_option != NULL) strlcpy(card_profile, profile_option, sizeof(card_profile)); @@ -1214,8 +1215,8 @@ sc_pkcs15init_init_prkdf(struct sc_pkcs15_card *p15card, struct sc_profile *prof keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147; } else if (key->algorithm == SC_ALGORITHM_EC) { - struct sc_pkcs15_ec_parameters *ecparams = &keyargs->params.ec; - key_info->params.data = &keyargs->params.ec; + struct sc_ec_parameters *ecparams = &keyargs->key.u.ec.params; + key_info->params.data = &keyargs->key.u.ec.params; key_info->params.free_params = sc_pkcs15init_empty_callback; key_info->field_length = ecparams->field_length; } @@ -1314,10 +1315,14 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr pubkey_args.usage = keygen_args->prkey_args.usage; pubkey_args.x509_usage = keygen_args->prkey_args.x509_usage; - if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_GOSTR3410) + if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_GOSTR3410) { pubkey_args.params.gost = keygen_args->prkey_args.params.gost; - else if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_EC) - pubkey_args.params.ec = keygen_args->prkey_args.params.ec; + } + else if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_EC) { + pubkey_args.key.u.ec.params = keygen_args->prkey_args.key.u.ec.params; + r = sc_copy_ec_params(&pubkey_args.key.u.ec.params, &keygen_args->prkey_args.key.u.ec.params); + LOG_TEST_RET(ctx, r, "Cannot allocate EC parameters"); + } /* Generate the private key on card */ r = profile->ops->create_key(profile, p15card, object); @@ -1504,8 +1509,9 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile case SC_ALGORITHM_EC: type = SC_PKCS15_TYPE_PUBKEY_EC; - key.u.ec.params = keyargs->params.ec; - sc_pkcs15_fix_ec_parameters(ctx, &key.u.ec.params); + key.u.ec.params = keyargs->key.u.ec.params; + r = sc_pkcs15_fix_ec_parameters(ctx, &key.u.ec.params); + LOG_TEST_RET(ctx, r, "Failed to fix EC public key parameters"); keybits = key.u.ec.params.field_length; break; @@ -1624,11 +1630,14 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card, struct sc_pkcs15_cert_info *cert_info = NULL; struct sc_pkcs15_object *object = NULL; struct sc_pkcs15_object *key_object = NULL; + struct sc_path existing_path; const char *label = NULL; int r; LOG_FUNC_CALLED(ctx); + memset(&existing_path, 0, sizeof(struct sc_path)); + label = args->label; if (!label) label = "Certificate"; @@ -1636,10 +1645,25 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card, r = sc_pkcs15init_select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_CERT_X509, &args->id, &args->der_encoded); LOG_TEST_RET(ctx, r, "Get certificate 'intrinsic ID' error"); + sc_log(ctx, "Cert(ID:%s) rv %i", sc_pkcs15_print_id(&args->id), r); - /* Select an ID if the user didn't specify one, otherwise - * make sure it's unique */ + /* Select an ID if the user didn't specify one, otherwise make sure it's unique */ r = select_id(p15card, SC_PKCS15_TYPE_CERT, &args->id); + if (r == SC_ERROR_NON_UNIQUE_ID && args->update) { + struct sc_pkcs15_object *existing_obj = NULL; + + r = sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_CERT, &args->id, &existing_obj); + if (!r) { + sc_log(ctx, "Found cert(ID:%s)", sc_pkcs15_print_id(&args->id)); + existing_path = ((struct sc_pkcs15_cert_info *)existing_obj->data)->path; + + sc_pkcs15_remove_object(p15card, existing_obj); + sc_pkcs15_free_object(existing_obj); + } + + r = select_id(p15card, SC_PKCS15_TYPE_CERT, &args->id); + } + sc_log(ctx, "Select ID Cert(ID:%s) rv %i", sc_pkcs15_print_id(&args->id), r); LOG_TEST_RET(ctx, r, "Select certificate ID error"); object = sc_pkcs15init_new_object(SC_PKCS15_TYPE_CERT_X509, label, NULL, NULL); @@ -1651,8 +1675,14 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card, sc_der_copy(&object->content, &args->der_encoded); sc_der_copy(&cert_info->value, &args->der_encoded); + if (existing_path.len) { + sc_log(ctx, "Using existing path %s", sc_print_path(&existing_path)); + cert_info->path = existing_path; + } + sc_log(ctx, "Store cert(%s,ID:%s,der(%p,%i))", object->label, sc_pkcs15_print_id(&cert_info->id), args->der_encoded.value, args->der_encoded.len); + if (!profile->pkcs15.direct_certificates) r = sc_pkcs15init_store_data(p15card, profile, object, &args->der_encoded, &cert_info->path); @@ -1712,6 +1742,8 @@ sc_pkcs15init_store_data_object(struct sc_pkcs15_card *p15card, unsigned int tid = 0x01; LOG_FUNC_CALLED(ctx); + if (!profile) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing profile"); label = args->label; if (!args->id.len) { @@ -1888,8 +1920,7 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *prof *path = file->path; - if (file) - sc_file_free(file); + sc_file_free(file); LOG_FUNC_RETURN(ctx, r); } @@ -1973,7 +2004,7 @@ check_keygen_params_consistency(struct sc_card *card, struct sc_pkcs15init_keyge int i, rv; if (alg == SC_ALGORITHM_EC) { - struct sc_pkcs15_ec_parameters *ecparams = ¶ms->prkey_args.params.ec; + struct sc_ec_parameters *ecparams = ¶ms->prkey_args.key.u.ec.params; rv = sc_pkcs15_fix_ec_parameters(ctx, ecparams); LOG_TEST_RET(ctx, rv, "Cannot fix EC parameters"); @@ -2009,9 +2040,11 @@ static int check_key_compatibility(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key, unsigned int x509_usage, unsigned int key_length, unsigned int flags) { + struct sc_context *ctx = p15card->card->ctx; struct sc_algorithm_info *info; unsigned int count; + LOG_FUNC_CALLED(ctx); count = p15card->card->algorithm_count; for (info = p15card->card->algorithms; count--; info++) { /* don't check flags if none was specified */ @@ -2037,12 +2070,18 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey * } } else if (key->algorithm == SC_ALGORITHM_EC) { + if (!sc_valid_oid(&key->u.ec.params.id)) + if (sc_pkcs15_fix_ec_parameters(ctx, &key->u.ec.params)) + LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID); + if (sc_valid_oid(&info->u._ec.params.id)) + if (!sc_compare_oid(&info->u._ec.params.id, &key->u.ec.params.id)) + continue; } - return SC_SUCCESS; + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } - return SC_ERROR_OBJECT_NOT_VALID; + LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID); } @@ -2151,9 +2190,12 @@ prkey_bits(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key) } return SC_PKCS15_GOSTR3410_KEYSIZE; case SC_ALGORITHM_EC: - /* calculation returns one bit too small, add one bu default */ - sc_log(ctx, "Private EC key length %u", sc_pkcs15init_keybits(&key->u.ec.privateD) + 1); - return sc_pkcs15init_keybits(&key->u.ec.privateD) + 1; + sc_log(ctx, "Private EC key length %u", key->u.ec.params.field_length); + if (key->u.ec.params.field_length == 0) { + sc_log(ctx, "Invalid EC key length"); + return SC_ERROR_OBJECT_NOT_VALID; + } + return key->u.ec.params.field_length; } sc_log(ctx, "Unsupported key algorithm."); return SC_ERROR_NOT_SUPPORTED; @@ -2197,7 +2239,7 @@ sc_pkcs15init_select_intrinsic_id(struct sc_pkcs15_card *p15card, struct sc_prof { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_pubkey *pubkey = NULL; - unsigned id_style = profile->id_style; + unsigned id_style; struct sc_pkcs15_id id; unsigned char *id_data = NULL; size_t id_data_len = 0; @@ -2207,15 +2249,17 @@ sc_pkcs15init_select_intrinsic_id(struct sc_pkcs15_card *p15card, struct sc_prof #ifndef ENABLE_OPENSSL LOG_FUNC_RETURN(ctx, SC_SUCCESS); #else - if (!id_out) + if (!id_out || !profile) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + id_style = profile->id_style; + /* ID already exists */ if (id_out->len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); /* Native ID style is not intrisic one */ - if (profile->id_style == SC_PKCS15INIT_ID_STYLE_NATIVE) + if (id_style == SC_PKCS15INIT_ID_STYLE_NATIVE) LOG_FUNC_RETURN(ctx, SC_SUCCESS); memset(&id, 0, sizeof(id)); @@ -2283,7 +2327,7 @@ sc_pkcs15init_select_intrinsic_id(struct sc_pkcs15_card *p15card, struct sc_prof break; default: - sc_log(ctx, "Unsupported ID style: %i", profile->id_style); + sc_log(ctx, "Unsupported ID style: %i", id_style); LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Non supported ID style"); } @@ -2312,8 +2356,12 @@ select_id(struct sc_pkcs15_card *p15card, int type, struct sc_pkcs15_id *id) /* If the user provided an ID, make sure we can use it */ if (id->len != 0) { r = sc_pkcs15_find_object_by_id(p15card, type, id, &obj); + if (r == SC_ERROR_OBJECT_NOT_FOUND) r = 0; + else if (!r) + r = SC_ERROR_NON_UNIQUE_ID; + LOG_FUNC_RETURN(ctx, r); } @@ -2672,8 +2720,11 @@ sc_pkcs15init_update_any_df(struct sc_pkcs15_card *p15card, int update_odf = is_new, r = 0; LOG_FUNC_CALLED(ctx); - sc_profile_get_file_by_path(profile, &df->path, &file); - if (file == NULL) + if (!df) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "DF missing"); + + r = sc_profile_get_file_by_path(profile, &df->path, &file); + if (r < 0 || file == NULL) sc_select_file(card, &df->path, &file); r = sc_pkcs15_encode_df(card->ctx, p15card, df, &buf, &bufsize); @@ -3158,6 +3209,7 @@ sc_pkcs15init_get_transport_key(struct sc_profile *profile, struct sc_pkcs15_car if (callbacks.get_key) { rv = callbacks.get_key(profile, type, reference, defbuf, defsize, pinbuf, pinsize); + LOG_TEST_RET(ctx, rv, "Cannot get key"); } else if (rv >= 0) { if (*pinsize < defsize) @@ -3238,25 +3290,23 @@ sc_pkcs15init_verify_secret(struct sc_profile *profile, struct sc_pkcs15_card *p sc_log(ctx, "Symbolic PIN resolved to PIN(type:CHV,reference:%i)", type, reference); } - if (p15card) { - if (path && path->len) { - struct sc_path tmp_path = *path; - int iter; + 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) - 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); - } + 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) + 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); + } - if (!r && pin_obj) { - memcpy(&auth_info, pin_obj->data, sizeof(auth_info)); - sc_log(ctx, "found PIN object '%s'", pin_obj->label); - } + if (!r && pin_obj) { + memcpy(&auth_info, pin_obj->data, sizeof(auth_info)); + sc_log(ctx, "found PIN object '%s'", pin_obj->label); } if (pin_obj) { diff --git a/src/pkcs15init/pkcs15-muscle.c b/src/pkcs15init/pkcs15-muscle.c index 96a0afa8..bcd4fd31 100644 --- a/src/pkcs15init/pkcs15-muscle.c +++ b/src/pkcs15init/pkcs15-muscle.c @@ -283,12 +283,6 @@ muscle_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, pubkey->u.rsa.exponent.len = extArgs.expLength; pubkey->u.rsa.exponent.data = extArgs.expValue; - if (r < 0) { - if (pubkey->u.rsa.modulus.data) - free (pubkey->u.rsa.modulus.data); - if (pubkey->u.rsa.exponent.data) - free (pubkey->u.rsa.exponent.data); - } return r; } diff --git a/src/pkcs15init/pkcs15-myeid.c b/src/pkcs15init/pkcs15-myeid.c index 4ade6974..acd8c06b 100644 --- a/src/pkcs15init/pkcs15-myeid.c +++ b/src/pkcs15init/pkcs15-myeid.c @@ -48,7 +48,7 @@ myeid_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, /* * Get 'Initialize Applet' data - * using the ACLs defined in card profile. + * using the ACLs defined in card profile. */ static int myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card, @@ -70,7 +70,10 @@ myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p1 sc_file_dup(&tmp_file, profile->mf_info->file); if (tmp_file == NULL) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file"); + r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); + if (r < 0) + sc_file_free(tmp_file); LOG_TEST_RET(ctx, r, "MF fixup failed"); /* AC 'Create DF' and 'Create EF' */ @@ -100,6 +103,8 @@ myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p1 if (tmp_file == NULL) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file"); r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); + if (r < 0) + sc_file_free(tmp_file); LOG_TEST_RET(ctx, r, "Application DF fixup failed"); /* AC 'Create DF' and 'Create EF' */ @@ -118,8 +123,8 @@ myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p1 else if (entry->method == SC_AC_NEVER) *(data + 6) = 0xFF; /* 'NEVER'. */ *(data + 7) = 0xFF; - sc_file_free(tmp_file); + sc_file_free(tmp_file); LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS); } @@ -189,7 +194,7 @@ myeid_init_card(sc_profile_t *profile, */ static int myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { - struct sc_context *ctx = p15card->card->ctx; + struct sc_context *ctx = NULL; struct sc_file *file = NULL; int r = 0, ii; static const char *create_dfs[] = { @@ -209,9 +214,10 @@ myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df SC_PKCS15_DODF }; - if (!profile || !p15card || !df) + if (!profile || !p15card || !p15card->card || !df) return SC_ERROR_INVALID_ARGUMENTS; + ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); sc_log(ctx, "id (%x)", df->id); @@ -421,10 +427,10 @@ myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: - LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "20140202: waiting for cards and specification from Aventra. VTA"); - if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, - "Unsupported EC key size"); + /* Here the information about curve is not available, that's why algorithm is checked + without curve OID. */ + if (sc_card_find_ec_alg(p15card->card, keybits, NULL) == NULL) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, @@ -438,6 +444,9 @@ myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, r = myeid_new_file(profile, card, object->type, key_info->key_reference, &file); LOG_TEST_RET(ctx, r, "Cannot get new MyEID private key file"); + if (!file || !file->path.len) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine private key file"); + sc_log(ctx, "Key file size %d", keybits); file->size = keybits; @@ -482,14 +491,15 @@ myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: - LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "20140202: waiting for cards and specification from Aventra. VTA"); - if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) - LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); + if (!sc_valid_oid(&prkey->u.ec.params.id)) + if (sc_pkcs15_fix_ec_parameters(ctx, &prkey->u.ec.params)) + LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID); + if (sc_card_find_ec_alg(p15card->card, keybits, &prkey->u.ec.params.id) == NULL) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported algorithm or key size"); if(key_info->field_length != 0) keybits = key_info->field_length; else key_info->field_length = keybits; - break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store key failed: Unsupported key type"); @@ -571,15 +581,15 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: - LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "20140202: waiting for cards and specification from Aventra. VTA"); - - if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) + /* EC is supported in MyEID v > 3.5. TODO: set correct return value if older MyEID version. */ + /* Here the information about curve is not available, that's why supported algorithm is checked + without curve OID. */ + if (sc_card_find_ec_alg(p15card->card, keybits, NULL) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); if(key_info->field_length != 0) keybits = key_info->field_length; else key_info->field_length = keybits; - break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); @@ -641,7 +651,9 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, memcpy(pubkey->u.rsa.modulus.data, raw_pubkey, pubkey->u.rsa.modulus.len); } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { + struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)key_info->params.data; + sc_log(ctx, "curve '%s', len %i, oid '%s'", ecparams->named_curve, ecparams->field_length, sc_dump_oid(&(ecparams->id))); pubkey->algorithm = SC_ALGORITHM_EC; r = sc_select_file(card, &file->path, NULL); @@ -655,25 +667,27 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed"); - /* - * TODO DEE - this looks like a bug... - * pubkey->u.ec.ecpointQ.value is just value. "04||X||Y" - * pubkey->data.value should be DER OCTET STRING - * but - * pubkey->data.value looks like TLV with TAG if 0x86 - * and single byte length. - * Could call sc_pkcs15_encode_pubkey - * to set pubkey->data.value - */ - + if (pubkey->u.ec.ecpointQ.value) + free(pubkey->u.ec.ecpointQ.value); pubkey->u.ec.ecpointQ.value = malloc(data_obj.DataLen - 2); - pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2; - //pubkey->data.value = malloc(data_obj.DataLen); - //pubkey->data.len = data_obj.DataLen; - pubkey->u.ec.params.field_length = keybits; - /* Omit the first 2 bytes (0x86??) */ + if (pubkey->u.ec.ecpointQ.value == NULL) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(pubkey->u.ec.ecpointQ.value, data_obj.Data + 2, data_obj.DataLen - 2); - //memcpy(pubkey->data.value, data_obj.Data, data_obj.DataLen); + pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2; + + if (pubkey->u.ec.params.named_curve) + free(pubkey->u.ec.params.named_curve); + pubkey->u.ec.params.named_curve = NULL; + if (pubkey->u.ec.params.der.value) + free(pubkey->u.ec.params.der.value); + pubkey->u.ec.params.der.value = NULL; + pubkey->u.ec.params.der.len = 0; + + pubkey->u.ec.params.named_curve = strdup(ecparams->named_curve); + if (!pubkey->u.ec.params.named_curve) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); + LOG_TEST_RET(ctx, r, "Cannot fix EC parameters"); } } diff --git a/src/pkcs15init/pkcs15-oberthur-awp.c b/src/pkcs15init/pkcs15-oberthur-awp.c index 18032fba..2a382f58 100644 --- a/src/pkcs15init/pkcs15-oberthur-awp.c +++ b/src/pkcs15init/pkcs15-oberthur-awp.c @@ -279,7 +279,10 @@ awp_create_container_record (struct sc_pkcs15_card *p15card, struct sc_profile * memset(buff, 0, list_file->record_length); rv = awp_new_container_entry(p15card, buff, list_file->record_length); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); + if (rv < 0) { + free(buff); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); + } *(buff + 0) = (acc->pubkey_id >> 8) & 0xFF; *(buff + 1) = acc->pubkey_id & 0xFF; @@ -289,7 +292,6 @@ awp_create_container_record (struct sc_pkcs15_card *p15card, struct sc_profile * *(buff + 5) = acc->cert_id & 0xFF; rv = sc_select_file(p15card->card, &list_file->path, NULL); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); if (rv == SC_ERROR_FILE_NOT_FOUND) rv = sc_pkcs15init_create_file(profile, p15card, list_file); @@ -297,10 +299,6 @@ awp_create_container_record (struct sc_pkcs15_card *p15card, struct sc_profile * rv = sc_append_record(p15card->card, buff, list_file->record_length, SC_RECORD_BY_REC_NR); free(buff); - - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "return after failure"); - - rv = 0; SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -312,7 +310,6 @@ awp_create_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_context *ctx = p15card->card->ctx; struct sc_file *clist = NULL, *file = NULL; int rv = 0; - unsigned char *list = NULL; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "create container(%X:%X:%X)", acc->prkey_id, acc->cert_id, acc->pubkey_id); @@ -330,12 +327,8 @@ awp_create_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, rv = awp_create_container_record(p15card, profile, file, acc); - if (clist) - sc_file_free(clist); - if (file) - sc_file_free(file); - if (list) - free(list); + sc_file_free(file); + sc_file_free(clist); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -363,14 +356,15 @@ awp_update_container_entry (struct sc_pkcs15_card *p15card, struct sc_profile *p if (rec > list_file->record_count) { rv = awp_new_container_entry(p15card, buff, list_file->record_length); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); } else { rv = sc_select_file(p15card->card, &list_file->path, NULL); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot select list_file"); - - rv = sc_read_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot read record"); + if (!rv) + rv = sc_read_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); + } + if (rv < 0) { + free(buff); + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } switch (type) { @@ -395,7 +389,8 @@ awp_update_container_entry (struct sc_pkcs15_card *p15card, struct sc_profile *p *(buff + offs + 5) = file_id & 0xFF; break; default: - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCORRECT_PARAMETERS, "invalid object type"); + free(buff); + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCORRECT_PARAMETERS); } if (rec > list_file->record_count) { @@ -408,14 +403,9 @@ awp_update_container_entry (struct sc_pkcs15_card *p15card, struct sc_profile *p } else { rv = sc_update_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); } free(buff); - - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "return after failure"); - - rv = 0; SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -448,17 +438,14 @@ awp_update_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); if (rv) goto done; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner cfile(rcount:%i,rlength:%i)", clist->record_count, clist->record_length); rv = sc_select_file(p15card->card, &clist->path, &file); if (rv) goto done; file->record_length = clist->record_length; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner file(rcount:%i,rlength:%i)", file->record_count, file->record_length); if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == COSM_TYPE_PRKEY_RSA) { rec_offs = 0; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Append new record %i for private key", file->record_count + 1); rv = awp_update_container_entry(p15card, profile, file, type, obj_id, file->record_count + 1, rec_offs); goto done; } @@ -495,46 +482,45 @@ awp_update_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_path path = private_path; struct sc_file *ff = NULL; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "container contains PrKey %02X%02X", *(list + offs + 2), *(list + offs + 3)); path.value[path.len - 2] = *(list + offs + 2) | 0x01; path.value[path.len - 1] = *(list + offs + 3); rv = sc_select_file(p15card->card, &path, &ff); if (rv) continue; - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file id %X; size %i", ff->id, ff->size); - buff = malloc(ff->size); - if (!buff) { - rv = SC_ERROR_OUT_OF_MEMORY; - break; - } - rv = sc_pkcs15init_authenticate(profile, p15card, ff, SC_AC_OP_READ); if (rv) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_pkcs15init_authenticate(READ) failed"); + sc_file_free(ff); break; } - rv = sc_read_binary(p15card->card, 0, buff, ff->size, 0); - if ((unsigned)rv == ff->size) { - rv = 0; - id_offs = 5 + *(buff+3); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rec %i; id offset %i",rec, id_offs); - if (key_id->len == *(buff + id_offs) && - !memcmp(key_id->value, buff + id_offs + 1, key_id->len)) { - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "found key file friend"); - if (!rv) - rv = awp_update_container_entry(p15card, profile, file, type, obj_id, rec + 1, rec_offs); + buff = malloc(ff->size); + if (!buff) + rv = SC_ERROR_OUT_OF_MEMORY; - if (rv >= 0 && prkey_id) { - *prkey_id = *(list + offs + 2) * 0x100 + *(list + offs + 3); - sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "*prkey_id 0x%X", *prkey_id); + if (!rv) { + rv = sc_read_binary(p15card->card, 0, buff, ff->size, 0); + if ((unsigned)rv == ff->size) { + rv = 0; + id_offs = 5 + *(buff+3); + + if (key_id->len == *(buff + id_offs) && + !memcmp(key_id->value, buff + id_offs + 1, key_id->len)) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "found key file friend"); + if (!rv) + rv = awp_update_container_entry(p15card, profile, file, type, obj_id, rec + 1, rec_offs); + + if (rv >= 0 && prkey_id) + *prkey_id = *(list + offs + 2) * 0x100 + *(list + offs + 3); } } } free(buff); sc_file_free(ff); + + if (rv) + break; } } } @@ -573,16 +559,15 @@ awp_set_certificate_info (struct sc_pkcs15_card *p15card, blob_size = 2; if (!(blob = malloc(blob_size))) { r = SC_ERROR_OUT_OF_MEMORY; - goto done; + goto done; } /* TODO: cert flags */ *blob = (COSM_TAG_CERT >> 8) & 0xFF; *(blob + 1) = COSM_TAG_CERT & 0xFF; - if (ci->label.len - && ci->label.len != strlen(default_cert_label) - && memcmp(ci->label.value, default_cert_label, strlen(default_cert_label))) + if (ci->label.len && ci->label.len != strlen(default_cert_label) + && memcmp(ci->label.value, default_cert_label, strlen(default_cert_label))) r = awp_update_blob(ctx, &blob, &blob_size, &ci->label, TLV_TYPE_LLV); else r = awp_update_blob(ctx, &blob, &blob_size, &ci->cn, TLV_TYPE_LLV); @@ -591,11 +576,11 @@ awp_set_certificate_info (struct sc_pkcs15_card *p15card, r = awp_update_blob(ctx, &blob, &blob_size, &ci->id, TLV_TYPE_LLV); if (r) - goto done; + goto done; r = awp_update_blob(ctx, &blob, &blob_size, &ci->subject, TLV_TYPE_LLV); if (r) - goto done; + goto done; if (ci->issuer.len != ci->subject.len || memcmp(ci->issuer.value, ci->subject.value, ci->subject.len)) { @@ -784,10 +769,8 @@ awp_encode_key_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj if (obj->type == COSM_TYPE_PUBKEY_RSA || obj->type == COSM_TYPE_PRKEY_RSA) ki->flags |= COSM_GENERATED; - if (obj->label) { - ki->label.value = (unsigned char *)strdup(obj->label); - ki->label.len = strlen(obj->label); - } + ki->label.value = (unsigned char *)strdup(obj->label); + ki->label.len = strlen(obj->label); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cosm_encode_key_info() label(%i):%s",ki->label.len, ki->label.value); /* @@ -945,10 +928,8 @@ awp_encode_cert_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *ob sc_pkcs15_print_id(&cert_info->id), obj->content.value, obj->content.len); memset(&pubkey, 0, sizeof(pubkey)); - if (obj->label) { - ci->label.value = (unsigned char *)strdup(obj->label); - ci->label.len = strlen(obj->label); - } + ci->label.value = (unsigned char *)strdup(obj->label); + ci->label.len = strlen(obj->label); mem = BIO_new_mem_buf(obj->content.value, obj->content.len); if (!mem) @@ -1090,17 +1071,14 @@ awp_encode_data_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *ob di->flags = 0x0000; - if (obj->label) { - di->label.value = (unsigned char *)strdup(obj->label); - di->label.len = strlen(obj->label); - } + di->label.value = (unsigned char *)strdup(obj->label); + di->label.len = strlen(obj->label); di->app.len = strlen(data_info->app_label); if (di->app.len) { di->app.value = (unsigned char *)strdup(data_info->app_label); if (!di->app.value) - SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY, - "AWP encode data failed: cannot allocate App.Label"); + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); } r = sc_asn1_encode_object_id(&buf, &buflen, &data_info->app_oid); @@ -1669,8 +1647,8 @@ awp_delete_from_container(struct sc_pkcs15_card *p15card, rv = 0; if (buff) free(buff); - if (file) sc_file_free(file); if (clist) sc_file_free(clist); + sc_file_free(file); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } @@ -1744,8 +1722,7 @@ awp_remove_from_object_list( struct sc_pkcs15_card *p15card, struct sc_profile * done: if (buff) free(buff); - if (lst) - sc_file_free(lst); + sc_file_free(lst); if (lst_file) sc_file_free(lst_file); diff --git a/src/pkcs15init/pkcs15-oberthur.c b/src/pkcs15init/pkcs15-oberthur.c index 34185987..c968984b 100644 --- a/src/pkcs15init/pkcs15-oberthur.c +++ b/src/pkcs15init/pkcs15-oberthur.c @@ -63,15 +63,17 @@ static int cosm_write_tokeninfo (struct sc_pkcs15_card *p15card, struct sc_profile *profile, char *label, unsigned flags) { - struct sc_context *ctx = p15card->card->ctx; + struct sc_context *ctx; struct sc_file *file = NULL; int rv; size_t sz; char *buffer = NULL; - if (!p15card || !profile) + if (!p15card || !p15card->card || !profile) return SC_ERROR_INVALID_ARGUMENTS; + ctx = p15card->card->ctx; + SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cosm_write_tokeninfo() label '%s'; flags 0x%X", label, flags); if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) @@ -264,7 +266,6 @@ cosm_create_reference_data(struct sc_profile *profile, struct sc_pkcs15_card *p1 struct sc_card *card = p15card->card; struct sc_pkcs15_auth_info profile_auth_pin, profile_auth_puk; struct sc_cardctl_oberthur_createpin_info args; - unsigned char *puk_buff = NULL; int rv; unsigned char oberthur_puk[16] = { 0x6F, 0x47, 0xD9, 0x88, 0x4B, 0x6F, 0x9D, 0xC5, @@ -321,9 +322,6 @@ cosm_create_reference_data(struct sc_profile *profile, struct sc_pkcs15_card *p1 sc_file_free(file); } - if (puk_buff) - free(puk_buff); - SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); } diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c index be1291e6..f5d6089f 100755 --- a/src/pkcs15init/pkcs15-openpgp.c +++ b/src/pkcs15init/pkcs15-openpgp.c @@ -187,7 +187,7 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card /* The OpenPGP supports only 32-bit exponent. */ key_info.exponent_len = 32; - key_info.exponent = calloc(4, 1); + key_info.exponent = calloc(key_info.exponent_len>>3, 1); /* 1/8 */ if (key_info.exponent == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); @@ -204,10 +204,10 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card sc_log(ctx, "Set output exponent info"); pubkey->u.rsa.exponent.len = key_info.exponent_len; - pubkey->u.rsa.exponent.data = calloc(key_info.exponent_len, 1); + pubkey->u.rsa.exponent.data = calloc(key_info.exponent_len>>3, 1); /* 1/8 */ if (pubkey->u.rsa.exponent.data == NULL) goto out; - memcpy(pubkey->u.rsa.exponent.data, key_info.exponent, key_info.exponent_len); + memcpy(pubkey->u.rsa.exponent.data, key_info.exponent, key_info.exponent_len>>3); /* 1/8 */ out: if (key_info.modulus) diff --git a/src/pkcs15init/pkcs15-rtecp.c b/src/pkcs15init/pkcs15-rtecp.c index d3b0bebd..572b55e6 100644 --- a/src/pkcs15init/pkcs15-rtecp.c +++ b/src/pkcs15init/pkcs15-rtecp.c @@ -208,11 +208,13 @@ static int rtecp_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, snprintf(pin_sname, sizeof(pin_sname), "CHV%i", auth_info->attrs.pin.reference); if (auth_info->attrs.pin.reference == RTECP_USER_PIN_REF) { - r = sc_profile_get_file(profile, pin_sname, &file); + r = sc_profile_get_file(profile, pin_sname, &file); if (!r) { const struct sc_acl_entry *acl = NULL; r = sc_pkcs15init_fixup_file(profile, p15card, file); + if (r < 0) + sc_file_free(file); SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot fixup the ACLs of PIN file"); acl = sc_file_get_acl_entry(file, SC_AC_OP_PIN_RESET); diff --git a/src/pkcs15init/pkcs15-sc-hsm.c b/src/pkcs15init/pkcs15-sc-hsm.c index 9e7ebbc8..ddf84af9 100644 --- a/src/pkcs15init/pkcs15-sc-hsm.c +++ b/src/pkcs15init/pkcs15-sc-hsm.c @@ -173,7 +173,7 @@ static int sc_hsm_encode_gakp_rsa(struct sc_pkcs15_card *p15card, sc_cvc_t *cvc, static int sc_hsm_encode_gakp_ec(struct sc_pkcs15_card *p15card, sc_cvc_t *cvc, struct sc_pkcs15_prkey_info *key_info) { struct sc_object_id ecdsaWithSHA256 = { { 0,4,0,127,0,7,2,2,2,2,3,-1 } }; - struct sc_pkcs15_ec_parameters *ecparams = (struct sc_pkcs15_ec_parameters *)key_info->params.data; + struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)key_info->params.data; struct ec_curve *curve = NULL; u8 *curveoid; int curveoidlen,r; @@ -271,9 +271,10 @@ static int sc_hsm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card r = sc_hsm_encode_gakp_ec(p15card, &cvc, key_info); break; default: - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_IMPLEMENTED); + r = SC_ERROR_NOT_IMPLEMENTED; break; } + LOG_TEST_RET(p15card->card->ctx, r, "Could not encode GAKP cdata"); r = sc_pkcs15emu_sc_hsm_encode_cvc(p15card, &cvc, &cvcbin, &cvclen); sc_pkcs15emu_sc_hsm_free_cvc(&cvc); diff --git a/src/pkcs15init/pkcs15-setcos.c b/src/pkcs15init/pkcs15-setcos.c index fdd185ce..0aadc3c1 100644 --- a/src/pkcs15init/pkcs15-setcos.c +++ b/src/pkcs15init/pkcs15-setcos.c @@ -123,12 +123,16 @@ setcos_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) /* Fix up the file's ACLs */ r = sc_pkcs15init_fixup_file(profile, p15card, pinfile); + if (r < 0) + sc_file_free(pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Pinfile fixup failed"); /* Set life cycle state to SC_FILE_STATUS_CREATION, * which means that all ACs are ignored. */ pinfile->status = SC_FILE_STATUS_CREATION; r = sc_create_file(p15card->card, pinfile); + if (r < 0) + sc_file_free(pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Pinfile creation failed"); } sc_file_free(pinfile); @@ -236,8 +240,7 @@ setcos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot set MF into the activated state"); } - if(pinfile) - sc_file_free(pinfile); + sc_file_free(pinfile); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); } diff --git a/src/pkcs15init/pkcs15-westcos.c b/src/pkcs15init/pkcs15-westcos.c index e75fb3ac..023ede60 100644 --- a/src/pkcs15init/pkcs15-westcos.c +++ b/src/pkcs15init/pkcs15-westcos.c @@ -270,6 +270,8 @@ static int westcos_pkcs15init_generate_key(sc_profile_t *profile, pubkey->algorithm = SC_ALGORITHM_RSA; r = sc_pkcs15_decode_pubkey(p15card->card->ctx, pubkey, p, lg); + if (r < 0) + goto out; } (void) BIO_reset(mem); @@ -350,6 +352,3 @@ struct sc_pkcs15init_operations* sc_pkcs15init_get_westcos_ops(void) { return &sc_pkcs15init_westcos_operations; } - - - diff --git a/src/pkcs15init/profile.c b/src/pkcs15init/profile.c index 1c560f89..922b76b4 100644 --- a/src/pkcs15init/profile.c +++ b/src/pkcs15init/profile.c @@ -380,11 +380,15 @@ sc_profile_load(struct sc_profile *profile, const char *filename) sc_log(ctx, "profile %s loaded ok", path); - if (res < 0) + if (res < 0) { + scconf_free(conf); LOG_FUNC_RETURN(ctx, SC_ERROR_FILE_NOT_FOUND); + } - if (res == 0) + if (res == 0) { + scconf_free(conf); LOG_FUNC_RETURN(ctx, SC_ERROR_SYNTAX_ERROR); + } res = process_conf(profile, conf); scconf_free(conf); @@ -507,7 +511,6 @@ sc_profile_get_pin_info(struct sc_profile *profile, if (pi == NULL) return; - pi->pin.tries_left = pi->pin.tries_left; pi->pin.max_tries = pi->pin.tries_left; *info = pi->pin; } @@ -1302,7 +1305,7 @@ do_fileid(struct state *cur, int argc, char **argv) parse_error(cur, "No path/fileid set for parent DF\n"); return 1; } - if (df->path.len + 2 > sizeof(df->path)) { + if (df->path.len + 2 > sizeof(df->path.value)) { parse_error(cur, "File path too long\n"); return 1; } @@ -2059,7 +2062,7 @@ sc_profile_find_file_by_path(struct sc_profile *pro, const sc_path_t *path) sc_log(ctx, "find profile file by path:%s", sc_print_path(path)); #endif - if (!path->len && !path->aid.len) + if (!path || (!path->len && !path->aid.len)) return NULL; for (fi = pro->ef_list; fi; fi = fi->next) { diff --git a/src/scconf/parse.c b/src/scconf/parse.c index 2a9aed3f..2804d7d5 100644 --- a/src/scconf/parse.c +++ b/src/scconf/parse.c @@ -82,8 +82,9 @@ static scconf_item *scconf_item_find(scconf_parser * parser) scconf_item *item; for (item = parser->block->items; item; item = item->next) { - if (item->type == SCCONF_ITEM_TYPE_VALUE && - strcasecmp(item->key, parser->key) == 0) { + if (item && item->type == SCCONF_ITEM_TYPE_VALUE + && item->key && parser->key + && strcasecmp(item->key, parser->key) == 0) { return item; } } @@ -148,20 +149,24 @@ scconf_item *scconf_item_add(scconf_context * config, scconf_block * block, scco scconf_list_copy(dst->name, &parser.name); } scconf_item_add_internal(&parser, type); - switch (parser.current_item->type) { - case SCCONF_ITEM_TYPE_COMMENT: - parser.current_item->value.comment = strdup((const char *) data); - break; - case SCCONF_ITEM_TYPE_BLOCK: - if (!dst) - return NULL; - dst->parent = parser.block; - parser.current_item->value.block = dst; - scconf_list_destroy(parser.name); - break; - case SCCONF_ITEM_TYPE_VALUE: - scconf_list_copy((const scconf_list *) data, &parser.current_item->value.list); - break; + if (parser.current_item) { + switch (parser.current_item->type) { + case SCCONF_ITEM_TYPE_COMMENT: + parser.current_item->value.comment = strdup((const char *) data); + break; + case SCCONF_ITEM_TYPE_BLOCK: + if (!dst) + return NULL; + dst->parent = parser.block; + parser.current_item->value.block = dst; + scconf_list_destroy(parser.name); + break; + case SCCONF_ITEM_TYPE_VALUE: + scconf_list_copy((const scconf_list *) data, &parser.current_item->value.list); + break; + } + } else { + /* FIXME is it an error if item is NULL? */ } return parser.current_item; } @@ -273,7 +278,7 @@ void scconf_parse_token(scconf_parser * parser, int token_type, const char *toke scconf_parse_warning_expect(parser, "\""); } else { /* stoken */ - stoken = token ? strdup(token) : NULL; + stoken = strdup(token); if (stoken) { stoken[len - 1] = '\0'; } diff --git a/src/scconf/sclex.c b/src/scconf/sclex.c index b16db4b7..c5a6758f 100644 --- a/src/scconf/sclex.c +++ b/src/scconf/sclex.c @@ -57,8 +57,10 @@ static void buf_addch(BUFHAN * bp, char ch) bp->bufmax += 256; bp->buf = (char *) realloc(bp->buf, bp->bufmax); } - bp->buf[bp->bufcur++] = ch; - bp->buf[bp->bufcur] = '\0'; + if (bp->buf) { + bp->buf[bp->bufcur++] = ch; + bp->buf[bp->bufcur] = '\0'; + } } static int buf_nextch(BUFHAN * bp) diff --git a/src/smm/sm-card-iasecc.c b/src/smm/sm-card-iasecc.c index d7b6998f..199e8a6a 100644 --- a/src/smm/sm-card-iasecc.c +++ b/src/smm/sm-card-iasecc.c @@ -152,14 +152,12 @@ sm_iasecc_get_apdu_create_file(struct sc_context *ctx, struct sm_info *sm_info, int rv = 0; LOG_FUNC_CALLED(ctx); + + if (!cmd_data || !cmd_data->data || !rdata || !rdata->alloc) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + sc_log(ctx, "SM get 'CREATE FILE' APDU: FCP(%i) %s", cmd_data->size, sc_dump_hex(cmd_data->data,cmd_data->size)); - if (!cmd_data || !cmd_data->data) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - - if (!rdata || !rdata->alloc) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'UPDATE BINARY' APDUs: cannot allocate remote APDU"); @@ -229,14 +227,11 @@ sm_iasecc_get_apdu_verify_pin(struct sc_context *ctx, struct sm_info *sm_info, s int rv; LOG_FUNC_CALLED(ctx); + if (!pin_data || !rdata || !rdata->alloc) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + sc_log(ctx, "SM get 'VERIFY PIN' APDU: ", pin_data->pin_reference); - if (!pin_data) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - - if (!rdata || !rdata->alloc) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'VERIFY PIN' APDUs: cannot allocate remote APDU"); @@ -272,14 +267,12 @@ sm_iasecc_get_apdu_reset_pin(struct sc_context *ctx, struct sm_info *sm_info, st int rv; LOG_FUNC_CALLED(ctx); + + if (!pin_data || !rdata || !rdata->alloc) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + sc_log(ctx, "SM get 'RESET PIN' APDU; reference %i", pin_data->pin_reference); - if (!pin_data) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - - if (!rdata || !rdata->alloc) - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'RESET PIN' APDUs: cannot allocate remote APDU"); diff --git a/src/smm/sm-cwa14890.c b/src/smm/sm-cwa14890.c index 810a5a9c..2ba4b635 100644 --- a/src/smm/sm-cwa14890.c +++ b/src/smm/sm-cwa14890.c @@ -160,17 +160,25 @@ sm_cwa_decode_authentication_data(struct sc_context *ctx, struct sm_cwa_keyset * sc_log(ctx, "sm_ecc_decode_auth_data() decrypted(%i) %s", decrypted_len, sc_dump_hex(decrypted, decrypted_len)); - if (memcmp(decrypted, session_data->icc.rnd, 8)) + if (memcmp(decrypted, session_data->icc.rnd, 8)) { + free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); + } - if (memcmp(decrypted + 8, session_data->icc.sn, 8)) + if (memcmp(decrypted + 8, session_data->icc.sn, 8)) { + free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); + } - if (memcmp(decrypted + 16, session_data->ifd.rnd, 8)) + if (memcmp(decrypted + 16, session_data->ifd.rnd, 8)) { + free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); + } - if (memcmp(decrypted + 24, session_data->ifd.sn, 8)) + if (memcmp(decrypted + 24, session_data->ifd.sn, 8)) { + free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); + } memcpy(session_data->icc.k, decrypted + 32, 32); diff --git a/src/tests/base64.c b/src/tests/base64.c index ec9583dc..f868d12d 100644 --- a/src/tests/base64.c +++ b/src/tests/base64.c @@ -38,6 +38,7 @@ int main(int argc, char *argv[]) fwrite(outbuf, len, 1, stdout); r = 0; err: - fclose(inf); + if (inf) + fclose(inf); return r; } diff --git a/src/tests/lottery.c b/src/tests/lottery.c index ecbce269..c64f093c 100644 --- a/src/tests/lottery.c +++ b/src/tests/lottery.c @@ -4,6 +4,8 @@ #include "config.h" +#include +#include #include #include #ifdef HAVE_UNISTD_H @@ -32,8 +34,12 @@ int main(int argc, char *argv[]) for (i = 0; i < 39; i++) { nbuf[i] = i + 1; } - if (c == 0) - gettimeofday(&tv1, NULL); + if (c == 0) { + if (0 != gettimeofday(&tv1, NULL)) { + fprintf(stderr, "gettimeofday() failed: %s\n", strerror(errno)); + return 1; + } + } sc_lock(card); r = sc_get_challenge(card, buf, 14); sc_unlock(card); @@ -43,7 +49,7 @@ int main(int argc, char *argv[]) printf("Lottery: "); for (i = 0; i < 7; i++) { unsigned short s = buf[2 * i] + (buf[2 * i + 1] << 8); - int lot = s % (left + 1); + int lot = s % left; int num = nbuf[lot]; nbuf[lot] = nbuf[left - 1]; diff --git a/src/tests/p15dump.c b/src/tests/p15dump.c index 433f5db7..24f19fcd 100644 --- a/src/tests/p15dump.c +++ b/src/tests/p15dump.c @@ -23,18 +23,21 @@ static int dump_objects(const char *what, int type) printf("\nEnumerating %s... ", what); fflush(stdout); - sc_lock(card); + if (SC_SUCCESS != sc_lock(card)) + return 1; count = sc_pkcs15_get_objects(p15card, type, NULL, 0); if (count < 0) { printf("failed.\n"); fprintf(stderr, "Error enumerating %s: %s\n", what, sc_strerror(count)); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; return 1; } if (count == 0) { printf("none found.\n"); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; return 0; } printf("%u found.\n", count); @@ -48,7 +51,8 @@ static int dump_objects(const char *what, int type) sc_test_print_object(objs[i]); } free(objs); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; return (count < 0) ? 1 : 0; } @@ -111,7 +115,8 @@ int main(int argc, char *argv[]) return 1; printf("Looking for a PKCS#15 compatible Smart Card... "); fflush(stdout); - sc_lock(card); + if (SC_SUCCESS != sc_lock(card)) + return 1; i = sc_pkcs15_bind(card, NULL, &p15card); /* Keep card locked to prevent useless calls to sc_logout */ if (i) { @@ -129,7 +134,8 @@ int main(int argc, char *argv[]) dump_unusedspace(); sc_pkcs15_unbind(p15card); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; sc_test_cleanup(); return 0; } diff --git a/src/tests/pintest.c b/src/tests/pintest.c index d913a726..16f7947b 100644 --- a/src/tests/pintest.c +++ b/src/tests/pintest.c @@ -36,7 +36,15 @@ static int enum_pins(struct sc_pkcs15_object ***ret) return 0; } objs = calloc(n, sizeof(*objs)); - sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, n); + if (!objs) { + fprintf(stderr, "Not enough memory!\n"); + return 1; + } + if (0 > sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, n)) { + fprintf(stderr, "Error enumerating PIN codes\n"); + free(objs); + return 1; + } for (i = 0; i < n; i++) { sc_test_print_object(objs[i]); } @@ -59,9 +67,11 @@ static int ask_and_verify_pin(struct sc_pkcs15_object *pin_obj) sprintf(prompt, "Please enter PIN code [%s]: ", pin_obj->label); pass = (u8 *) getpass(prompt); - sc_lock(card); + if (SC_SUCCESS != sc_lock(card)) + return 1; i = sc_pkcs15_verify_pin(p15card, pin_obj, pass, strlen((char *) pass)); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; if (i) { if (i == SC_ERROR_PIN_CODE_INCORRECT) fprintf(stderr, @@ -90,9 +100,11 @@ int main(int argc, char *argv[]) printf("Slot is capable of doing pinpad operations!\n"); printf("Looking for a PKCS#15 compatible Smart Card... "); fflush(stdout); - sc_lock(card); + if (SC_SUCCESS != sc_lock(card)) + return 1; i = sc_pkcs15_bind(card, NULL, &p15card); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; if (i) { fprintf(stderr, "failed: %s\n", sc_strerror(i)); sc_test_cleanup(); @@ -100,9 +112,11 @@ int main(int argc, char *argv[]) } printf("found.\n"); printf("Enumerating PIN codes...\n"); - sc_lock(card); + if (SC_SUCCESS != sc_lock(card)) + return 1; count = enum_pins(&objs); - sc_unlock(card); + if (SC_SUCCESS != sc_unlock(card)) + return 1; if (count < 0) { sc_pkcs15_unbind(p15card); sc_test_cleanup(); diff --git a/src/tests/regression/crypt0007 b/src/tests/regression/crypt0007 index 74409658..5f832439 100755 --- a/src/tests/regression/crypt0007 +++ b/src/tests/regression/crypt0007 @@ -10,7 +10,7 @@ msg <&3 >&4 success @@ -356,6 +356,6 @@ function p15_validate { msg "Validating card using pkcs11-tool" run_display_output $p11tool -t --login --pin 0000 \ --module $p11module \ - --slot-label "OpenSC Test Card" $* < /dev/null + --token-label "OpenSC Test Card" $* < /dev/null success } diff --git a/src/tools/cardos-tool.c b/src/tools/cardos-tool.c index f171220c..e271fed6 100644 --- a/src/tools/cardos-tool.c +++ b/src/tools/cardos-tool.c @@ -593,7 +593,7 @@ static int cardos_format(const char *opt_startkey) if (check_apdu(&apdu)) return 1; if (apdu.resplen < 0x04) { - printf("expected 4-6 bytes form GET DATA for startkey data, but got only %u\n", apdu.resplen); + printf("expected 4-6 bytes form GET DATA for startkey data, but got only %zu\n", apdu.resplen); printf("aborting\n"); return 1; } @@ -914,7 +914,7 @@ static int cardos_change_startkey(const char *change_startkey_apdu) if (check_apdu(&apdu)) return 1; if (apdu.resplen < 0x04) { - printf("expected 4-6 bytes form GET DATA for startkey data, but got only %u\n", apdu.resplen); + printf("expected 4-6 bytes form GET DATA for startkey data, but got only %zu\n", apdu.resplen); printf("aborting\n"); return 1; } @@ -999,7 +999,7 @@ change_startkey: if (check_apdu(&apdu)) return 1; if (apdu.resplen < 0x04) { - printf("expected 4-6 bytes form GET DATA for startkey data, but got only %u\n", apdu.resplen); + printf("expected 4-6 bytes form GET DATA for startkey data, but got only %zu\n", apdu.resplen); printf("aborting\n"); return 1; } diff --git a/src/tools/cryptoflex-tool.c b/src/tools/cryptoflex-tool.c index 56113a83..8cbbd856 100644 --- a/src/tools/cryptoflex-tool.c +++ b/src/tools/cryptoflex-tool.c @@ -28,6 +28,7 @@ #include "libopensc/pkcs15.h" #include "common/compat_strlcpy.h" +#include "common/compat_strlcat.h" #include "util.h" static const char *app_name = "cryptoflex-tool"; @@ -145,7 +146,7 @@ static int select_app_df(void) strcpy(str, "3F00"); if (opt_appdf != NULL) - strcat(str, opt_appdf); + strlcat(str, opt_appdf, sizeof str); sc_format_path(str, &path); r = sc_select_file(card, &path, &file); if (r) { @@ -641,7 +642,7 @@ static int read_rsa_privkey(RSA **rsa_out) static int encode_private_key(RSA *rsa, u8 *key, size_t *keysize) { - u8 buf[512], *p = buf; + u8 buf[1024], *p = buf; u8 bnbuf[256]; int base = 0; int r; @@ -715,7 +716,7 @@ static int encode_private_key(RSA *rsa, u8 *key, size_t *keysize) static int encode_public_key(RSA *rsa, u8 *key, size_t *keysize) { - u8 buf[512], *p = buf; + u8 buf[1024], *p = buf; u8 bnbuf[256]; int base = 0; int r; @@ -945,7 +946,7 @@ static int create_pin(void) } strcpy(buf, "3F00"); if (opt_appdf != NULL) - strcat(buf, opt_appdf); + strlcat(buf, opt_appdf, sizeof buf); sc_format_path(buf, &path); return create_pin_file(&path, opt_pin_num, ""); diff --git a/src/tools/dnie-tool.c b/src/tools/dnie-tool.c index 93f7c108..c856a7ba 100644 --- a/src/tools/dnie-tool.c +++ b/src/tools/dnie-tool.c @@ -146,7 +146,7 @@ int main(int argc, char* argv[]) if (r) { fprintf(stderr, "Error: Failed to establish context: %s\n", sc_strerror(r)); - return -1; + goto dnie_tool_end; } if (verbose > 1) { diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c index db37d831..7acf68d9 100644 --- a/src/tools/openpgp-tool.c +++ b/src/tools/openpgp-tool.c @@ -400,6 +400,8 @@ static int do_dump_do(sc_card_t *card, unsigned int tag) #else tmp = _dup(_fileno(stdout)); #endif + if (tmp < 0) + return EXIT_FAILURE; fp = freopen(NULL, "wb", stdout); if (fp) { r = (int)fwrite(buffer, sizeof(char), sizeof(buffer), fp); @@ -410,9 +412,9 @@ static int do_dump_do(sc_card_t *card, unsigned int tag) _dup2(tmp, _fileno(stdout)); #endif clearerr(stdout); - if (sizeof(buffer) != r) { + close(tmp); + if (sizeof(buffer) != r) return EXIT_FAILURE; - } } else { util_hex_dump_asc(stdout, buffer, sizeof(buffer), -1); } diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index cefc3e16..22943596 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -85,6 +85,7 @@ static const char *option_help[] = { static int do_echo(int argc, char **argv); static int do_ls(int argc, char **argv); static int do_find(int argc, char **argv); +static int do_find_tags(int argc, char **argv); static int do_cd(int argc, char **argv); static int do_cat(int argc, char **argv); static int do_info(int argc, char **argv); @@ -127,6 +128,9 @@ static struct command cmds[] = { { do_find, "find", "[ []]", "find all files in the current DF" }, + { do_find_tags, + "find_tags", "[ []]", + "find all tags of data objects in the current context" }, { do_cd, "cd", "{.. | | aid:}", "change to another DF" }, @@ -579,6 +583,73 @@ static int do_find(int argc, char **argv) return 0; } +static int do_find_tags(int argc, char **argv) +{ + u8 start[2], end[2], rbuf[256]; + int r; + unsigned int tag, tag_end; + + start[0] = 0x00; + start[1] = 0x00; + end[0] = 0xFF; + end[1] = 0xFF; + switch (argc) { + case 2: + if (arg_to_fid(argv[1], end) != 0) + return usage(do_find_tags); + /* fall through */ + case 1: + if (arg_to_fid(argv[0], start) != 0) + return usage(do_find_tags); + /* fall through */ + case 0: + break; + default: + return usage(do_find_tags); + } + tag = (start[0] << 8) | start[1]; + tag_end = (end[0] << 8) | end[1]; + + printf("Tag\tType\n"); + while (1) { + printf("(%04X)\r", tag); + fflush(stdout); + + r = sc_get_data(card, tag, rbuf, sizeof rbuf); + if (r >= 0) { + printf(" %04X ", tag); + if (tag == 0) + printf("\tdump file"); + if ((0x0001 <= tag && tag <= 0x00FE) + || (0x1F1F <= tag && tag <= 0xFFFF)) + printf("\tBER-TLV"); + if (tag == 0x00FF || tag == 0x02FF) + printf("\tspecial function"); + if (0x0100 <= tag && tag <= 0x01FF) + printf("\tproprietary"); + if (tag == 0x0200) + printf("\tRFU"); + if (0x0201 <= tag && tag <= 0x02FE) + printf("\tSIMPLE-TLV"); + printf("\n"); + if (r > 0) + util_hex_dump_asc(stdout, rbuf, r, -1); + } else { + switch (r) { + case SC_ERROR_NOT_ALLOWED: + case SC_ERROR_SECURITY_STATUS_NOT_SATISFIED: + printf("(%04X)\t%s\n", tag, sc_strerror(r)); + break; + } + } + + if (tag >= tag_end) + break; + tag++; + } + return 0; +} + static int do_cd(int argc, char **argv) { sc_path_t path; @@ -786,8 +857,10 @@ static int do_info(int argc, char **argv) st = "Unknown File"; break; } - printf("\n%s ID %04X\n\n", st, file->id); - printf("%-15s%s\n", "File path:", path_to_filename(&path, '/')); + printf("\n%s ID %04X", st, file->id); + if (file->sid) + printf(", SFI %02X", file->sid); + printf("\n\n%-15s%s\n", "File path:", path_to_filename(&path, '/')); printf("%-15s%lu bytes\n", "File size:", (unsigned long) file->size); if (file->type == SC_FILE_TYPE_DF) { @@ -1834,7 +1907,7 @@ int main(int argc, char * const argv[]) return 1; } - ctx->enable_default_driver = 1; + ctx->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER; if (verbose > 1) { ctx->debug = verbose; diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c index c1676988..aea526e5 100644 --- a/src/tools/opensc-tool.c +++ b/src/tools/opensc-tool.c @@ -149,7 +149,7 @@ static int opensc_get_conf_entry(const char *config) } section = buffer; - name = section == NULL ? NULL : strchr(section+1, ':'); + name = strchr(section+1, ':'); key = name == NULL ? NULL : strchr(name+1, ':'); if (key == NULL) { r = EINVAL; @@ -203,7 +203,7 @@ static int opensc_set_conf_entry(const char *config) } section = buffer; - name = section == NULL ? NULL : strchr(section+1, ':'); + name = strchr(section+1, ':'); key = name == NULL ? NULL : strchr(name+1, ':'); value = key == NULL ? NULL : strchr(key+1, ':'); if (value == NULL) { @@ -758,7 +758,7 @@ int main(int argc, char * const argv[]) return 1; } - ctx->enable_default_driver = 1; + ctx->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER; if (verbose > 1) { ctx->debug = verbose; diff --git a/src/tools/piv-tool.c b/src/tools/piv-tool.c index c8455317..acf79798 100644 --- a/src/tools/piv-tool.c +++ b/src/tools/piv-tool.c @@ -113,13 +113,16 @@ static int load_object(const char * object_id, const char * object_file) int r; struct stat stat_buf; - if((fp=fopen(object_file, "r"))==NULL){ + if(!object_file || (fp=fopen(object_file, "r")) == NULL){ printf("Cannot open object file, %s %s\n", (object_file)?object_file:"", strerror(errno)); return -1; } - stat(object_file, &stat_buf); + if (0 != stat(object_file, &stat_buf)) { + printf("unable to read file %s\n",object_file); + return -1; + } derlen = stat_buf.st_size; der = malloc(derlen); if (der == NULL) { @@ -165,21 +168,29 @@ static int load_cert(const char * cert_id, const char * cert_file, size_t derlen; int r; + if (!cert_file) { + printf("Missing cert file\n"); + return -1; + } + if((fp=fopen(cert_file, "r"))==NULL){ printf("Cannot open cert file, %s %s\n", - cert_file?cert_file:"", strerror(errno)); + cert_file, strerror(errno)); return -1; } if (compress) { /* file is gziped already */ struct stat stat_buf; - stat(cert_file, &stat_buf); + if (0 != stat(cert_file, &stat_buf)) { + printf("unable to read file %s\n",cert_file); + return -1; + } derlen = stat_buf.st_size; der = malloc(derlen); if (der == NULL) { printf("file %s is too big, %lu\n", cert_file, (unsigned long)derlen); - return-1 ; + return -1 ; } if (1 != fread(der, derlen, 1, fp)) { printf("unable to read file %s\n",cert_file); @@ -484,6 +495,7 @@ int main(int argc, char * const argv[]) break; case 'Z': compress_cert = 1; + /* fall through */ case 'C': do_load_cert = 1; cert_id = optarg; diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index dafd8181..c3861d56 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -24,6 +24,11 @@ #include #include #include +#ifndef _WIN32 +#include +#include +#include +#endif #ifdef ENABLE_OPENSSL #include #if OPENSSL_VERSION_NUMBER >= 0x10000000L @@ -47,6 +52,8 @@ #include "pkcs11/pkcs11.h" #include "pkcs11/pkcs11-opensc.h" #include "libopensc/asn1.h" +#include "common/compat_strlcat.h" +#include "common/compat_strlcpy.h" #include "util.h" extern void *C_LoadModule(const char *name, CK_FUNCTION_LIST_PTR_PTR); @@ -62,19 +69,29 @@ static struct ec_curve_info { size_t size; } ec_curve_infos[] = { {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"prime192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, + {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, + + {"secp224r1", "1.3.132.0.33", "06052b81040021", 224}, + {"nistp224", "1.3.132.0.33", "06052b81040021", 224}, + {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, + {"secp384r1", "1.3.132.0.34", "06052B81040022", 384}, {"prime384v1", "1.3.132.0.34", "06052B81040022", 384}, {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384}, + + {"secp521r1", "1.3.132.0.35", "06052B81040023", 521}, + {"nistp521", "1.3.132.0.35", "06052B81040023", 521}, + {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192}, {"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}, + {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192}, {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256}, {NULL, NULL, NULL, 0}, @@ -105,7 +122,9 @@ enum { OPT_NEW_PIN, OPT_LOGIN_TYPE, OPT_TEST_EC, - OPT_DERIVE + OPT_DERIVE, + OPT_DECRYPT, + OPT_TEST_FORK, }; static const struct option options[] = { @@ -117,6 +136,7 @@ static const struct option options[] = { { "list-objects", 0, NULL, 'O' }, { "sign", 0, NULL, 's' }, + { "decrypt", 0, NULL, OPT_DECRYPT }, { "hash", 0, NULL, 'h' }, { "derive", 0, NULL, OPT_DERIVE }, { "mechanism", 1, NULL, 'm' }, @@ -154,6 +174,7 @@ static const struct option options[] = { { "attr-from", 1, NULL, OPT_ATTR_FROM }, { "input-file", 1, NULL, 'i' }, { "output-file", 1, NULL, 'o' }, + { "signature-format", 1, NULL, 'f' }, { "test", 0, NULL, 't' }, { "test-hotplug", 0, NULL, OPT_TEST_HOTPLUG }, @@ -161,12 +182,15 @@ static const struct option options[] = { { "verbose", 0, NULL, 'v' }, { "private", 0, NULL, OPT_PRIVATE }, { "test-ec", 0, NULL, OPT_TEST_EC }, +#ifndef _WIN32 + { "test-fork", 0, NULL, OPT_TEST_FORK }, +#endif { NULL, 0, NULL, 0 } }; static const char *option_help[] = { - "Specify the module to load (mandatory)", + "Specify the module to load (default:" DEFAULT_PKCS11_PROVIDER ")", "Show global token information", "List available slots", "List slots with tokens", @@ -174,6 +198,7 @@ static const char *option_help[] = { "Show objects on token", "Sign some data", + "Decrypt some data", "Hash some data", "Derive a secret key using another key and some data", "Specify mechanism (use -M for a list of supported mechanisms)", @@ -211,13 +236,17 @@ static const char *option_help[] = { "Use to create some attributes when writing an object", "Specify the input file", "Specify the output file", + "Format for ECDSA signature : 'rs' (default), 'sequence', 'openssl'", "Test (best used with the --login or --pin option)", "Test hotplug capabilities (C_GetSlotList + C_WaitForSlotEvent)", "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)", - "Test EC (best used with the --login or --pin option)" + "Test EC (best used with the --login or --pin option)", +#ifndef _WIN32 + "Test forking and calling C_Initialize() in the child", +#endif }; static const char * app_name = "pkcs11-tool"; /* for utils.c */ @@ -225,7 +254,7 @@ static const char * app_name = "pkcs11-tool"; /* for utils.c */ static int verbose = 0; static const char * opt_input = NULL; static const char * opt_output = NULL; -static const char * opt_module = NULL; +static const char * opt_module = DEFAULT_PKCS11_PROVIDER; static int opt_slot_set = 0; static CK_SLOT_ID opt_slot = 0; static const char * opt_slot_description = NULL; @@ -250,6 +279,7 @@ static char * opt_application_id = NULL; static char * opt_issuer = NULL; static char * opt_subject = NULL; static char * opt_key_type = NULL; +static char * opt_sig_format = NULL; static int opt_is_private = 0; static int opt_test_hotplug = 0; static int opt_login_type = -1; @@ -319,8 +349,8 @@ static void show_object(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); -static void sign_data(CK_SLOT_ID, - CK_SESSION_HANDLE, CK_OBJECT_HANDLE); +static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); +static void decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void hash_data(CK_SLOT_ID, CK_SESSION_HANDLE); static void derive_key(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static int gen_keypair(CK_SESSION_HANDLE, @@ -353,6 +383,9 @@ static int test_card_detection(int); static int hex_to_bin(const char *in, CK_BYTE *out, size_t *outlen); static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session); static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session); +#ifndef _WIN32 +static void test_fork(void); +#endif static CK_RV find_object_with_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *out, CK_ATTRIBUTE *attrs, CK_ULONG attrsLen, CK_ULONG obj_index); static CK_ULONG get_private_key_length(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE prkey); @@ -373,6 +406,7 @@ int main(int argc, char * argv[]) int do_list_mechs = 0; int do_list_objects = 0; int do_sign = 0; + int do_decrypt = 0; int do_hash = 0; int do_derive = 0; int do_gen_keypair = 0; @@ -383,6 +417,9 @@ int main(int argc, char * argv[]) int do_test = 0; int do_test_kpgen_certwrite = 0; int do_test_ec = 0; +#ifndef _WIN32 + int do_test_fork = 0; +#endif int need_session = 0; int opt_login = 0; int do_init_token = 0; @@ -408,7 +445,7 @@ int main(int argc, char * argv[]) CRYPTO_malloc_init(); #endif while (1) { - c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvty:w:z:r", + c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvf:ty:w:z:r", options, &long_optind); if (c == -1) break; @@ -514,6 +551,8 @@ int main(int argc, char * argv[]) opt_output = optarg; break; case 'p': + need_session |= NEED_SESSION_RW; + opt_login = 1; util_get_pin(optarg, &opt_pin); break; case 'c': @@ -531,6 +570,14 @@ int main(int argc, char * argv[]) do_sign = 1; action_count++; break; + case OPT_DECRYPT: + need_session |= NEED_SESSION_RW; + do_decrypt = 1; + action_count++; + break; + case 'f': + opt_sig_format = optarg; + break; case 't': need_session |= NEED_SESSION_RO; do_test = 1; @@ -648,14 +695,17 @@ int main(int argc, char * argv[]) do_derive = 1; action_count++; break; +#ifndef _WIN32 + case OPT_TEST_FORK: + do_test_fork = 1; + action_count++; + break; +#endif default: util_print_usage_and_die(app_name, options, option_help, NULL); } } - if (opt_module == NULL) - util_print_usage_and_die(app_name, options, option_help, NULL); - if (action_count == 0) util_print_usage_and_die(app_name, options, option_help, NULL); @@ -669,6 +719,11 @@ int main(int argc, char * argv[]) else if (rv != CKR_OK) p11_fatal("C_Initialize", rv); +#ifndef _WIN32 + if (do_test_fork) + test_fork(); +#endif + if (do_show_info) show_cryptoki_info(); @@ -739,7 +794,7 @@ int main(int argc, char * argv[]) if (do_list_mechs) list_mechs(opt_slot); - if (do_sign) { + if (do_sign || do_decrypt) { CK_TOKEN_INFO info; get_token_info(opt_slot, &info); @@ -796,7 +851,7 @@ int main(int argc, char * argv[]) goto end; } - if (do_sign || do_derive) { + if (do_sign || do_derive || do_decrypt) { if (!find_object(session, CKO_PRIVATE_KEY, &object, opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0)) @@ -813,6 +868,9 @@ int main(int argc, char * argv[]) if (do_sign) sign_data(opt_slot, session, object); + if (do_decrypt) + decrypt_data(opt_slot, session, object); + if (do_hash) hash_data(opt_slot, session); @@ -1138,15 +1196,17 @@ static void init_token(CK_SLOT_ID slot) opt_object_label); get_token_info(slot, &info); - if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { - if (opt_so_pin == NULL) { + if (opt_so_pin != NULL) { + new_pin = (char *) opt_so_pin; + } else { + if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { printf("Please enter the new SO PIN: "); r = util_getpass(&new_pin, &len, stdin); if (r < 0) util_fatal("No PIN entered, exiting\n"); if (!new_pin || !*new_pin || strlen(new_pin) > 20) util_fatal("Invalid SO PIN\n"); - strcpy(new_buf, new_pin); + strlcpy(new_buf, new_pin, sizeof new_buf); free(new_pin); new_pin = NULL; printf("Please enter the new SO PIN (again): "); r = util_getpass(&new_pin, &len, stdin); @@ -1156,11 +1216,7 @@ static void init_token(CK_SLOT_ID slot) strcmp(new_buf, new_pin) != 0) util_fatal("Different new SO PINs, exiting\n"); pin_allocated = 1; - } else { - new_pin = (char *) opt_so_pin; } - if (!new_pin || !*new_pin) - util_fatal("Invalid SO PIN\n"); } rv = p11->C_InitToken(slot, (CK_UTF8CHAR *) new_pin, @@ -1323,19 +1379,24 @@ static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type) r = util_getpass(&new_pin, &len, stdin); if (r < 0) return 1; - strcpy(new_buf, new_pin); + strlcpy(new_buf, new_pin, sizeof new_buf); printf("Please enter the new PIN again: "); r = util_getpass(&new_pin, &len, stdin); if (r < 0) return 1; if (!new_pin || !*new_pin || strcmp(new_buf, new_pin) != 0) { + if (new_pin != opt_new_pin) + free(new_pin); printf(" different new PINs, exiting\n"); return -1; } - if (!new_pin || !*new_pin || strlen(new_pin) > 20) + if (!new_pin || !*new_pin || strlen(new_pin) > 20) { + if (new_pin != opt_new_pin) + free(new_pin); return 1; + } } rv = p11->C_SetPIN(sess, @@ -1412,39 +1473,86 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, util_fatal("failed to open %s: %m", opt_output); } -#if defined(ENABLE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA) -/* - * PKCS11 implies the ECDSA sig is 2nLen, - * OpenSSL expects sequence of {integer, integer} - * so we will write it for OpenSSL if built with OpenSSL - */ - if (opt_mechanism == CKM_ECDSA) { - int nLen; - ECDSA_SIG * ecsig = NULL; - unsigned char *p = NULL; - int der_len; + if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1) { + if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { + unsigned char *seq; + size_t seqlen; - nLen = sig_len/2; + if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, sig_len, &seq, &seqlen)) { + util_fatal("Failed to convert signature to ASN.1 sequence format."); + } - ecsig = ECDSA_SIG_new(); - ecsig->r = BN_bin2bn(sig_buffer, nLen, ecsig->r); - ecsig->s = BN_bin2bn(sig_buffer + nLen, nLen, ecsig->s); + memcpy(sig_buffer, seq, seqlen); + sig_len = seqlen; - der_len = i2d_ECDSA_SIG(ecsig, &p); - printf("Writing OpenSSL ECDSA_SIG\n"); - r = write(fd, p, der_len); - free(p); - ECDSA_SIG_free(ecsig); - - } else -#endif /* ENABLE_OPENSSL && !OPENSSL_NO_EC && !OPENSSL_NO_ECDSA */ + free(seq); + } + } r = write(fd, sig_buffer, sig_len); + if (r < 0) util_fatal("Failed to write to %s: %m", opt_output); if (fd != 1) close(fd); } + +static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE key) +{ + unsigned char in_buffer[1024], out_buffer[1024]; + CK_MECHANISM mech; + CK_RV rv; + CK_ULONG in_len, out_len; + int fd, r; + + if (!opt_mechanism_used) + if (!find_mechanism(slot, CKF_DECRYPT|CKF_HW, NULL, 0, &opt_mechanism)) + util_fatal("Decrypt mechanism not supported\n"); + + printf("Using decrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); + memset(&mech, 0, sizeof(mech)); + mech.mechanism = opt_mechanism; + + if (opt_input == NULL) + fd = 0; + else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0) + util_fatal("Cannot open %s: %m", opt_input); + + r = read(fd, in_buffer, sizeof(in_buffer)); + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + in_len = r; + + rv = p11->C_DecryptInit(session, &mech, key); + if (rv != CKR_OK) + p11_fatal("C_DecryptInit", rv); + + out_len = sizeof(out_buffer); + rv = p11->C_Decrypt(session, in_buffer, in_len, out_buffer, &out_len); + if (rv != CKR_OK) + p11_fatal("C_Decrypt", rv); + + if (fd != 0) + close(fd); + + if (opt_output == NULL) { + fd = 1; + } + else { + fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR); + if (fd < 0) + util_fatal("failed to open %s: %m", opt_output); + } + + r = write(fd, out_buffer, out_len); + if (r < 0) + util_fatal("Failed to write to %s: %m", opt_output); + if (fd != 1) + close(fd); +} + + static void hash_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { unsigned char buffer[64]; @@ -1708,7 +1816,7 @@ do_read_private_key(unsigned char *data, size_t data_len, EVP_PKEY **key) mem = BIO_new(BIO_s_mem()); BIO_set_mem_buf(mem, &buf_mem, BIO_NOCLOSE); - if (!strstr((char *)data, "-----BEGIN PRIVATE KEY-----")) + if (!strstr((char *)data, "-----BEGIN PRIVATE KEY-----") && !strstr((char *)data, "-----BEGIN EC PRIVATE KEY-----")) *key = d2i_PrivateKey_bio(mem, NULL); else *key = PEM_read_bio_PrivateKey(mem, NULL, NULL, NULL); @@ -1815,6 +1923,7 @@ static int parse_gost_private_key(EVP_PKEY *evp_key, struct gostkey_info *gost) static int write_object(CK_SESSION_HANDLE session) { CK_BBOOL _true = TRUE; + CK_BBOOL _false = FALSE; unsigned char contents[MAX_OBJECT_SIZE + 1]; int contents_len = 0; unsigned char certdata[MAX_OBJECT_SIZE]; @@ -1887,7 +1996,8 @@ static int write_object(CK_SESSION_HANDLE session) rv = parse_rsa_private_key(&rsa, contents, contents_len); } #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) - else if (evp_key->type == NID_id_GostR3410_2001) { + else if (evp_key->type == NID_id_GostR3410_2001 || evp_key->type == EVP_PKEY_EC) { + /* parsing ECDSA is identical to GOST */ rv = parse_gost_private_key(evp_key, &gost); } #endif @@ -1917,28 +2027,24 @@ static int write_object(CK_SESSION_HANDLE session) FILL_ATTR(cert_templ[1], CKA_VALUE, contents, contents_len); FILL_ATTR(cert_templ[2], CKA_CLASS, &clazz, sizeof(clazz)); FILL_ATTR(cert_templ[3], CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)); - n_cert_attr = 4; + FILL_ATTR(cert_templ[4], CKA_PRIVATE, &_false, sizeof(_false)); + n_cert_attr = 5; if (opt_object_label != NULL) { - FILL_ATTR(cert_templ[n_cert_attr], CKA_LABEL, - opt_object_label, strlen(opt_object_label)); + FILL_ATTR(cert_templ[n_cert_attr], CKA_LABEL, opt_object_label, strlen(opt_object_label)); n_cert_attr++; } if (opt_object_id_len != 0) { - FILL_ATTR(cert_templ[n_cert_attr], CKA_ID, - opt_object_id, opt_object_id_len); + FILL_ATTR(cert_templ[n_cert_attr], CKA_ID, opt_object_id, opt_object_id_len); n_cert_attr++; } #ifdef ENABLE_OPENSSL /* according to PKCS #11 CKA_SUBJECT MUST be specified */ - FILL_ATTR(cert_templ[n_cert_attr], CKA_SUBJECT, - cert.subject, cert.subject_len); + FILL_ATTR(cert_templ[n_cert_attr], CKA_SUBJECT, cert.subject, cert.subject_len); n_cert_attr++; - FILL_ATTR(cert_templ[n_cert_attr], CKA_ISSUER, - cert.issuer, cert.issuer_len); + FILL_ATTR(cert_templ[n_cert_attr], CKA_ISSUER, cert.issuer, cert.issuer_len); n_cert_attr++; - FILL_ATTR(cert_templ[n_cert_attr], CKA_SERIAL_NUMBER, - cert.serialnum, cert.serialnum_len); + FILL_ATTR(cert_templ[n_cert_attr], CKA_SERIAL_NUMBER, cert.serialnum, cert.serialnum_len); n_cert_attr++; #endif } @@ -1964,6 +2070,19 @@ static int write_object(CK_SESSION_HANDLE session) FILL_ATTR(privkey_templ[n_privkey_attr], CKA_ID, opt_object_id, opt_object_id_len); n_privkey_attr++; } + if (opt_key_usage_sign != 0) { + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_SIGN, &_true, sizeof(_true)); + n_privkey_attr++; + } + if (opt_key_usage_decrypt != 0) { + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_DECRYPT, &_true, sizeof(_true)); + n_privkey_attr++; + } + if (opt_key_usage_derive != 0) { + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_DERIVE, &_true, sizeof(_true)); + n_privkey_attr++; + } + #ifdef ENABLE_OPENSSL if (cert.subject_len != 0) { FILL_ATTR(privkey_templ[n_privkey_attr], CKA_SUBJECT, cert.subject, cert.subject_len); @@ -1990,6 +2109,16 @@ static int write_object(CK_SESSION_HANDLE session) n_privkey_attr++; } #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) + else if (evp_key->type == EVP_PKEY_EC) { + type = CKK_EC; + + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type)); + n_privkey_attr++; + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_EC_PARAMS, gost.param_oid.value, gost.param_oid.len); + n_privkey_attr++; + FILL_ATTR(privkey_templ[n_privkey_attr], CKA_VALUE, gost.private.value, gost.private.len); + n_privkey_attr++; + } else if (evp_key->type == NID_id_GostR3410_2001) { type = CKK_GOSTR3410; @@ -2018,9 +2147,12 @@ static int write_object(CK_SESSION_HANDLE session) n_pubkey_attr = 3; if (opt_is_private != 0) { - FILL_ATTR(data_templ[n_data_attr], CKA_PRIVATE, - &_true, sizeof(_true)); - n_data_attr++; + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PRIVATE, &_true, sizeof(_true)); + n_pubkey_attr++; + } + else { + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PRIVATE, &_false, sizeof(_false)); + n_pubkey_attr++; } if (opt_object_label != NULL) { @@ -2033,17 +2165,27 @@ static int write_object(CK_SESSION_HANDLE session) opt_object_id, opt_object_id_len); n_pubkey_attr++; } -#ifdef ENABLE_OPENSSL - if (cert.subject_len != 0) { - FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_SUBJECT, - cert.subject, cert.subject_len); + if (opt_key_usage_sign != 0) { + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_VERIFY, &_true, sizeof(_true)); n_pubkey_attr++; } - FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS, - rsa.modulus, rsa.modulus_len); + if (opt_key_usage_decrypt != 0) { + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_ENCRYPT, &_true, sizeof(_true)); + n_pubkey_attr++; + } + if (opt_key_usage_derive != 0) { + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_DERIVE, &_true, sizeof(_true)); + n_pubkey_attr++; + } + +#ifdef ENABLE_OPENSSL + if (cert.subject_len != 0) { + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_SUBJECT, cert.subject, cert.subject_len); + n_pubkey_attr++; + } + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS, rsa.modulus, rsa.modulus_len); n_pubkey_attr++; - FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT, - rsa.public_exponent, rsa.public_exponent_len); + FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT, rsa.public_exponent, rsa.public_exponent_len); n_pubkey_attr++; #endif } @@ -2057,8 +2199,11 @@ static int write_object(CK_SESSION_HANDLE session) n_data_attr = 3; if (opt_is_private != 0) { - FILL_ATTR(data_templ[n_data_attr], CKA_PRIVATE, - &_true, sizeof(_true)); + FILL_ATTR(data_templ[n_data_attr], CKA_PRIVATE, &_true, sizeof(_true)); + n_data_attr++; + } + else { + FILL_ATTR(data_templ[n_data_attr], CKA_PRIVATE, &_false, sizeof(_false)); n_data_attr++; } @@ -2082,8 +2227,7 @@ static int write_object(CK_SESSION_HANDLE session) } if (opt_object_label != NULL) { - FILL_ATTR(data_templ[n_data_attr], CKA_LABEL, - opt_object_label, strlen(opt_object_label)); + FILL_ATTR(data_templ[n_data_attr], CKA_LABEL, opt_object_label, strlen(opt_object_label)); n_data_attr++; } @@ -2311,9 +2455,8 @@ find_mechanism(CK_SLOT_ID slot, CK_FLAGS flags, else { *result = mechs[0]; } - - free(mechs); } + free(mechs); return count; } @@ -2841,7 +2984,7 @@ get_mechanisms(CK_SLOT_ID slot, CK_MECHANISM_TYPE_PTR *pList, CK_FLAGS flags) CK_RV rv; rv = p11->C_GetMechanismList(slot, *pList, &ulCount); - *pList = calloc(ulCount, sizeof(*pList)); + *pList = calloc(ulCount, sizeof(**pList)); if (*pList == NULL) util_fatal("calloc failed: %m"); @@ -3253,9 +3396,9 @@ static EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv if ( !pkey || !rsa || !mod || !exp) { printf("public key not extractable\n"); if (pkey) - free(pkey); + EVP_PKEY_free(pkey); if (rsa) - free(rsa); + RSA_free(rsa); if (mod) free(mod); if (exp) @@ -3310,7 +3453,7 @@ static int sign_verify_openssl(CK_SESSION_HANDLE session, #ifdef ENABLE_OPENSSL int err; EVP_PKEY *pkey; - EVP_MD_CTX md_ctx; + EVP_MD_CTX *md_ctx; const EVP_MD *evp_mds[] = { EVP_sha1(), @@ -3354,9 +3497,16 @@ static int sign_verify_openssl(CK_SESSION_HANDLE session, if (!(pkey = get_public_key(session, privKeyObject))) return errors; - EVP_VerifyInit(&md_ctx, evp_mds[evp_md_index]); - EVP_VerifyUpdate(&md_ctx, verifyData, verifyDataLen); - err = EVP_VerifyFinal(&md_ctx, sig1, sigLen1, pkey); + md_ctx = EVP_MD_CTX_create(); + if (!md_ctx) + err = -1; + else { + EVP_VerifyInit(md_ctx, evp_mds[evp_md_index]); + EVP_VerifyUpdate(md_ctx, verifyData, verifyDataLen); + err = EVP_VerifyFinal(md_ctx, sig1, sigLen1, pkey); + EVP_MD_CTX_destroy(md_ctx); + EVP_PKEY_free(pkey); + } if (err == 0) { printf("ERR: verification failed\n"); errors++; @@ -3486,6 +3636,9 @@ static int test_signature(CK_SESSION_HANDLE sess) ck_mech.mechanism = firstMechType; rv = p11->C_SignInit(sess, &ck_mech, privKeyObject); + /* mechanism not implemented, don't test */ + if (rv == CKR_MECHANISM_INVALID) + return errors; if (rv != CKR_OK) p11_fatal("C_SignInit", rv); @@ -3805,17 +3958,26 @@ static int wrap_unwrap(CK_SESSION_HANDLE session, printf(" %s: ", OBJ_nid2sn(EVP_CIPHER_nid(algo))); - EVP_SealInit(&seal_ctx, algo, + if (!EVP_SealInit(&seal_ctx, algo, &key, &key_len, - iv, &pkey, 1); + iv, &pkey, 1)) { + printf("Internal error.\n"); + return 1; + } /* Encrypt something */ len = sizeof(ciphered); - EVP_SealUpdate(&seal_ctx, ciphered, &len, (const unsigned char *) "hello world", 11); + if (!EVP_SealUpdate(&seal_ctx, ciphered, &len, (const unsigned char *) "hello world", 11)) { + printf("Internal error.\n"); + return 1; + } ciphered_len = len; len = sizeof(ciphered) - ciphered_len; - EVP_SealFinal(&seal_ctx, ciphered + ciphered_len, &len); + if (!EVP_SealFinal(&seal_ctx, ciphered + ciphered_len, &len)) { + printf("Internal error.\n"); + return 1; + } ciphered_len += len; EVP_PKEY_free(pkey); @@ -3849,14 +4011,23 @@ static int wrap_unwrap(CK_SESSION_HANDLE session, return 1; } - EVP_DecryptInit(&seal_ctx, algo, key, iv); + if (!EVP_DecryptInit(&seal_ctx, algo, key, iv)) { + printf("Internal error.\n"); + return 1; + } len = sizeof(cleartext); - EVP_DecryptUpdate(&seal_ctx, cleartext, &len, ciphered, ciphered_len); + if (!EVP_DecryptUpdate(&seal_ctx, cleartext, &len, ciphered, ciphered_len)) { + printf("Internal error.\n"); + return 1; + } cleartext_len = len; len = sizeof(cleartext) - len; - EVP_DecryptFinal(&seal_ctx, cleartext + cleartext_len, &len); + if (!EVP_DecryptFinal(&seal_ctx, cleartext + cleartext_len, &len)) { + printf("Internal error.\n"); + return 1; + } cleartext_len += len; if (cleartext_len != 11 @@ -4220,7 +4391,7 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session) return; tmp = getID(session, priv_key, (CK_ULONG *) &opt_object_id_len); - if (opt_object_id == NULL || opt_object_id_len == 0) { + if (opt_object_id_len == 0) { printf("ERR: newly generated private key has no (or an empty) CKA_ID\n"); return; } @@ -4375,7 +4546,7 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session) return; tmp = getID(session, priv_key, (CK_ULONG *) &opt_object_id_len); - if (opt_object_id == NULL || opt_object_id_len == 0) { + if (opt_object_id_len == 0) { printf("ERR: newly generated private key has no (or an empty) CKA_ID\n"); return; } @@ -4430,6 +4601,29 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session) printf("==> OK\n"); } +#ifndef _WIN32 +static void test_fork(void) +{ + CK_RV rv; + pid_t pid = fork(); + + if (!pid) { + printf("*** Calling C_Initialize in forked child process ***\n"); + rv = p11->C_Initialize(NULL); + if (rv != CKR_OK) + p11_fatal("C_Initialize in child\n", rv); + exit(0); + } else if (pid < 0) { + util_fatal("Failed to fork for test: %s", strerror(errno)); + } else { + int st; + waitpid(pid, &st, 0); + if (!WIFEXITED(st) || WEXITSTATUS(st)) + util_fatal("Child process exited with status %d", st); + } + +} +#endif static const char *p11_flag_names(struct flag_info *list, CK_FLAGS value) { @@ -4439,8 +4633,8 @@ static const char *p11_flag_names(struct flag_info *list, CK_FLAGS value) buffer[0] = '\0'; while (list->value) { if (list->value & value) { - strcat(buffer, sepa); - strcat(buffer, list->name); + strlcat(buffer, sepa, sizeof buffer); + strlcat(buffer, list->name, sizeof buffer); value &= ~list->value; sepa = ", "; } diff --git a/src/tools/pkcs15-crypt.c b/src/tools/pkcs15-crypt.c index 95b6593b..bbc0008b 100644 --- a/src/tools/pkcs15-crypt.c +++ b/src/tools/pkcs15-crypt.c @@ -36,6 +36,7 @@ #include "common/compat_getpass.h" #include "libopensc/opensc.h" #include "libopensc/pkcs15.h" +#include "libopensc/asn1.h" #include "util.h" static const char *app_name = "pkcs15-crypt"; @@ -45,10 +46,11 @@ static char * opt_reader; static char * opt_pincode = NULL, * opt_key_id = NULL; static char * opt_input = NULL, * opt_output = NULL; static char * opt_bind_to_aid = NULL; +static char * opt_sig_format = NULL; static int opt_crypt_flags = 0; enum { - OPT_SHA1 = 0x100, + OPT_SHA1 = 0x100, OPT_SHA256, OPT_SHA384, OPT_SHA512, @@ -65,6 +67,7 @@ static const struct option options[] = { { "reader", 1, NULL, 'r' }, { "input", 1, NULL, 'i' }, { "output", 1, NULL, 'o' }, + { "signature-format", 1, NULL, 'f' }, { "raw", 0, NULL, 'R' }, { "sha-1", 0, NULL, OPT_SHA1 }, { "sha-256", 0, NULL, OPT_SHA256 }, @@ -87,6 +90,7 @@ static const char *option_help[] = { "Uses reader number ", "Selects the input file to use", "Outputs to file ", + "Format for ECDSA signature : 'rs' (default), 'sequence', 'openssl'", "Outputs raw 8 bit data", "Input file is a SHA-1 hash", "Input file is a SHA-256 hash", @@ -142,8 +146,8 @@ static char * get_pin(struct sc_pkcs15_object *obj) if (strlen(pincode) == 0) return NULL; if (strlen(pincode) < pinfo->attrs.pin.min_length || - strlen(pincode) > pinfo->attrs.pin.max_length) - continue; + strlen(pincode) > pinfo->attrs.pin.max_length) + continue; return strdup(pincode); } } @@ -181,10 +185,12 @@ static int write_output(const u8 *buf, int len) } else { outf = stdout; } + if (output_binary == 0) util_print_binary(outf, buf, len); else fwrite(buf, len, 1, outf); + if (outf != stdout) fclose(outf); return 0; @@ -222,10 +228,28 @@ static int sign(struct sc_pkcs15_object *obj) fprintf(stderr, "Compute signature failed: %s\n", sc_strerror(r)); return 1; } + len = r; - r = write_output(out, r); + if (obj->type == SC_PKCS15_TYPE_PRKEY_EC) { + if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { + unsigned char *seq; + size_t seqlen; - return 0; + if (sc_asn1_sig_value_rs_to_sequence(ctx, out, len, &seq, &seqlen)) { + fprintf(stderr, "Failed to convert signature to ASN1 sequence format.\n"); + return 2; + } + + memcpy(out, seq, seqlen); + len = seqlen; + + free(seq); + } + } + + r = write_output(out, len); + + return r; } static int decipher(struct sc_pkcs15_object *obj) @@ -302,15 +326,17 @@ static int get_key(unsigned int usage, sc_pkcs15_object_t **result) pincode = get_pin(pin); if (((pincode == NULL || *pincode == '\0')) && - !(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)) - return 5; + !(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)) { + free(pincode); + return 5; + } r = sc_pkcs15_verify_pin(p15card, pin, (const u8 *)pincode, pincode ? strlen(pincode) : 0); + free(pincode); if (r) { fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r)); return 5; } - free(pincode); if (verbose) fprintf(stderr, "PIN code correct.\n"); prev_pin = pin; @@ -329,7 +355,7 @@ int main(int argc, char * const argv[]) sc_context_param_t ctx_param; while (1) { - c = getopt_long(argc, argv, "sck:r:i:o:Rp:vw", options, &long_optind); + c = getopt_long(argc, argv, "sck:r:i:o:f:Rp:vw", options, &long_optind); if (c == -1) break; if (c == '?') @@ -356,6 +382,9 @@ int main(int argc, char * const argv[]) case 'o': opt_output = optarg; break; + case 'f': + opt_sig_format = optarg; + break; case 'R': opt_raw = 1; break; diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c index b3d00581..44c0f734 100644 --- a/src/tools/pkcs15-init.c +++ b/src/tools/pkcs15-init.c @@ -138,6 +138,7 @@ enum { OPT_UPDATE_LAST_UPDATE, OPT_ERASE_APPLICATION, OPT_IGNORE_CA_CERTIFICATES, + OPT_UPDATE_EXISTING, OPT_PIN1 = 0x10000, /* don't touch these values */ OPT_PUK1 = 0x10001, @@ -189,6 +190,7 @@ const struct option options[] = { { "finalize", no_argument, NULL, 'F' }, { "update-last-update", no_argument, NULL, OPT_UPDATE_LAST_UPDATE}, { "ignore-ca-certificates",no_argument, NULL, OPT_IGNORE_CA_CERTIFICATES}, + { "update-existing", no_argument, NULL, OPT_UPDATE_EXISTING}, { "extractable", no_argument, NULL, OPT_EXTRACTABLE }, { "insecure", no_argument, NULL, OPT_INSECURE }, @@ -249,6 +251,7 @@ static const char * option_help[] = { "Finish initialization phase of the smart card", "Update 'lastUpdate' attribut 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", @@ -348,8 +351,9 @@ static char * opt_puk_label = NULL; static char * opt_pubkey_label = NULL; static char * opt_cert_label = NULL; static const char * opt_pins[4]; +static char * pins[4]; static char * opt_serial = NULL; -static char * opt_passphrase = NULL; +static const char * opt_passphrase = NULL; static char * opt_newkey = NULL; static char * opt_outkey = NULL; static char * opt_application_id = NULL; @@ -363,6 +367,7 @@ static int ignore_cmdline_pins = 0; static struct secret opt_secrets[MAX_SECRETS]; static unsigned int opt_secret_count; static int opt_ignore_ca_certs = 0; +static int opt_update_existing = 0; static int verbose = 0; static struct sc_pkcs15init_callbacks callbacks = { @@ -458,6 +463,10 @@ main(int argc, char **argv) return 1; } + for (n = 0; n < sizeof(pins)/sizeof(pins[0]); n++) { + pins[n] = NULL; + } + for (n = 0; n < ACTION_MAX; n++) { unsigned int action = n; @@ -577,6 +586,10 @@ main(int argc, char **argv) } } + for (n = 0; n < sizeof(pins)/sizeof(pins[0]); n++) { + free(pins[n]); + } + out: if (profile) { sc_pkcs15init_unbind(profile); @@ -675,10 +688,10 @@ do_erase(sc_card_t *in_card, struct sc_profile *profile) struct sc_aid aid; aid.len = sizeof(aid.value); - if (sc_hex_to_bin(opt_bind_to_aid, aid.value, &aid.len)) { + r = sc_hex_to_bin(opt_bind_to_aid, aid.value, &aid.len); + if (r < 0) { fprintf(stderr, "Invalid AID value: '%s'\n", opt_bind_to_aid); - return 1; - + goto err; } r = sc_pkcs15init_erase_card(p15card, profile, &aid); @@ -688,6 +701,7 @@ do_erase(sc_card_t *in_card, struct sc_profile *profile) } ignore_cmdline_pins--; +err: sc_pkcs15_card_free(p15card); return r; } @@ -754,9 +768,10 @@ do_init_app(struct sc_profile *profile) if (!opt_pins[2] && !opt_no_prompt && !opt_no_sopin) { - r = get_new_pin(&hints, role, "pin", &opt_pins[2]); + r = get_new_pin(&hints, role, "pin", &pins[2]); if (r < 0) goto failed; + opt_pins[2] = pins[2]; } if (!so_puk_disabled && opt_pins[2] && !opt_pins[3] && !opt_no_prompt) { @@ -766,9 +781,10 @@ do_init_app(struct sc_profile *profile) role = "user"; hints.flags |= SC_UI_PIN_OPTIONAL; - r = get_new_pin(&hints, role, "puk", &opt_pins[3]); + r = get_new_pin(&hints, role, "puk", &pins[3]); if (r < 0) goto failed; + opt_pins[3] = pins[3]; } args.so_pin = (const u8 *) opt_pins[2]; @@ -819,9 +835,11 @@ do_store_pin(struct sc_profile *profile) } sc_pkcs15init_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &info); - if (opt_pins[0] == NULL) - if ((r = get_new_pin(&hints, "user", "pin", &opt_pins[0])) < 0) + if (opt_pins[0] == NULL) { + if ((r = get_new_pin(&hints, "user", "pin", &pins[0])) < 0) goto failed; + opt_pins[0] = pins[0]; + } if (*opt_pins[0] == '\0') { util_error("You must specify a PIN\n"); @@ -839,9 +857,9 @@ do_store_pin(struct sc_profile *profile) sc_pkcs15init_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &info); hints.flags |= SC_UI_PIN_OPTIONAL; - if ((r = get_new_pin(&hints, "user", "puk", &opt_pins[1])) < 0) + if ((r = get_new_pin(&hints, "user", "puk", &pins[1])) < 0) goto failed; - + opt_pins[1] = pins[1]; } if (opt_puk_authid && opt_pins[1]) @@ -997,8 +1015,7 @@ is_cacert_already_present(struct sc_pkcs15init_certargs *args) if (!cinfo->authority) continue; - if (args->label && objs[i]->label - && strcmp(args->label, objs[i]->label)) + if (strcmp(args->label, objs[i]->label)) continue; /* XXX we should also match the usage field here */ @@ -1061,8 +1078,12 @@ do_store_certificate(struct sc_profile *profile) memset(&args, 0, sizeof(args)); + if (opt_update_existing) + args.update = 1; + if (opt_objectid) sc_pkcs15_format_id(opt_objectid, &args.id); + args.label = (opt_cert_label != 0 ? opt_cert_label : opt_label); args.authority = opt_authority; @@ -1070,8 +1091,7 @@ do_store_certificate(struct sc_profile *profile) if (r >= 0) r = do_convert_cert(&args.der_encoded, cert); if (r >= 0) - r = sc_pkcs15init_store_certificate(p15card, profile, - &args, NULL); + r = sc_pkcs15init_store_certificate(p15card, profile, &args, NULL); if (args.der_encoded.value) free(args.der_encoded.value); @@ -1283,8 +1303,7 @@ static int get_cert_info(sc_pkcs15_card_t *myp15card, sc_pkcs15_object_t *certob } done: - if (cert) - sc_pkcs15_free_certificate(cert); + sc_pkcs15_free_certificate(cert); if (othercert) sc_pkcs15_free_certificate(othercert); @@ -1299,7 +1318,7 @@ done: */ static int do_delete_crypto_objects(sc_pkcs15_card_t *myp15card, struct sc_profile *profile, - const sc_pkcs15_id_t id, + const sc_pkcs15_id_t *id, unsigned int which) { sc_pkcs15_object_t *objs[10]; /* 1 priv + 1 pub + chain of at most 8 certs, should be enough */ @@ -1315,23 +1334,23 @@ static int do_delete_crypto_objects(sc_pkcs15_card_t *myp15card, } for (i = 0; i< r; i++) - if (sc_pkcs15_compare_id(&id, &((struct sc_pkcs15_prkey_info *)key_objs[i]->data)->id)) + if (sc_pkcs15_compare_id(id, &((struct sc_pkcs15_prkey_info *)key_objs[i]->data)->id)) objs[count++] = key_objs[i]; if (!count) - fprintf(stderr, "NOTE: couldn't find privkey %s to delete\n", sc_pkcs15_print_id(&id)); + fprintf(stderr, "NOTE: couldn't find privkey %s to delete\n", sc_pkcs15_print_id(id)); } if (which & SC_PKCS15INIT_TYPE_PUBKEY) { - if (sc_pkcs15_find_pubkey_by_id(myp15card, &id, &objs[count]) != 0) - fprintf(stderr, "NOTE: couldn't find pubkey %s to delete\n", sc_pkcs15_print_id(&id)); + if (sc_pkcs15_find_pubkey_by_id(myp15card, id, &objs[count]) != 0) + fprintf(stderr, "NOTE: couldn't find pubkey %s to delete\n", sc_pkcs15_print_id(id)); else count++; } if (which & SC_PKCS15INIT_TYPE_CERT) { - if (sc_pkcs15_find_cert_by_id(myp15card, &id, &objs[count]) != 0) - fprintf(stderr, "NOTE: couldn't find cert %s to delete\n", sc_pkcs15_print_id(&id)); + if (sc_pkcs15_find_cert_by_id(myp15card, id, &objs[count]) != 0) + fprintf(stderr, "NOTE: couldn't find cert %s to delete\n", sc_pkcs15_print_id(id)); else { count++; del_cert = 1; @@ -1404,7 +1423,7 @@ do_delete_objects(struct sc_profile *profile, unsigned int myopt_delete_flags) util_fatal("Specify the --id for key(s) or cert(s) to be deleted\n"); sc_pkcs15_format_id(opt_objectid, &id); - r = do_delete_crypto_objects(p15card, profile, id, myopt_delete_flags); + r = do_delete_crypto_objects(p15card, profile, &id, myopt_delete_flags); if (r >= 0) count += r; } @@ -1513,7 +1532,7 @@ do_generate_key(struct sc_profile *profile, const char *spec) if (*spec) { if (isalpha(*spec) && keygen_args.prkey_args.key.algorithm == SC_ALGORITHM_EC) { - keygen_args.prkey_args.params.ec.named_curve = strdup(spec); + keygen_args.prkey_args.key.u.ec.params.named_curve = strdup(spec); keybits = 0; } else { @@ -1693,19 +1712,19 @@ get_pin_callback(struct sc_profile *profile, switch (id) { case SC_PKCS15INIT_USER_PIN: name = "User PIN"; - secret = opt_pins[OPT_PIN1 & 3]; + secret = (char *) opt_pins[OPT_PIN1 & 3]; break; case SC_PKCS15INIT_USER_PUK: name = "User PIN unlock key"; - secret = opt_pins[OPT_PUK1 & 3]; + secret = (char *) opt_pins[OPT_PUK1 & 3]; break; case SC_PKCS15INIT_SO_PIN: name = "Security officer PIN"; - secret = opt_pins[OPT_PIN2 & 3]; + secret = (char *) opt_pins[OPT_PIN2 & 3]; break; case SC_PKCS15INIT_SO_PUK: name = "Security officer PIN unlock key"; - secret = opt_pins[OPT_PUK2 & 3]; + secret = (char *) opt_pins[OPT_PUK2 & 3]; break; } } @@ -1713,22 +1732,22 @@ get_pin_callback(struct sc_profile *profile, if (!(info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) && !(info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { name = "User PIN"; - secret = opt_pins[OPT_PIN1 & 3]; + secret = (char *) opt_pins[OPT_PIN1 & 3]; } else if (!(info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) && (info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { name = "User PUK"; - secret = opt_pins[OPT_PUK1 & 3]; + secret = (char *) opt_pins[OPT_PUK1 & 3]; } else if ((info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) && !(info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { name = "Security officer PIN"; - secret = opt_pins[OPT_PIN2 & 3]; + secret = (char *) opt_pins[OPT_PIN2 & 3]; } else if ((info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) && (info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { name = "Security officer PIN unlock key"; - secret = opt_pins[OPT_PUK2 & 3]; + secret = (char *) opt_pins[OPT_PUK2 & 3]; } } if (secret) @@ -1786,8 +1805,11 @@ get_pin_callback(struct sc_profile *profile, allocated = 1; } - if (len > *pinsize) + if (len > *pinsize) { + if (allocated) + free(secret); return SC_ERROR_BUFFER_TOO_SMALL; + } memcpy(pinbuf, secret, len + 1); *pinsize = len; if (allocated) @@ -1997,7 +2019,7 @@ do_read_private_key(const char *filename, const char *format, int r; if (opt_passphrase) - passphrase = opt_passphrase; + passphrase = (char *) opt_passphrase; if (!format || !strcasecmp(format, "pem")) { r = do_read_pem_private_key(filename, passphrase, pk); @@ -2026,8 +2048,12 @@ do_read_private_key(const char *filename, const char *format, return SC_ERROR_NOT_SUPPORTED; } + if (NULL == opt_passphrase) + free(passphrase); + if (r < 0) util_fatal("Unable to read private key from %s\n", filename); + return r; } @@ -2157,7 +2183,7 @@ static size_t determine_filesize(const char *filename) static int do_read_data_object(const char *name, u8 **out, size_t *outlen) { - FILE *inf; + FILE *inf; size_t filesize = determine_filesize(name); int c; @@ -2452,8 +2478,6 @@ handle_option(const struct option *opt) opt_serial = optarg; break; case OPT_PASSPHRASE: - free(opt_passphrase); - opt_passphrase = NULL; util_get_pin(optarg, &opt_passphrase); break; case OPT_PUBKEY: @@ -2525,6 +2549,9 @@ handle_option(const struct option *opt) case OPT_IGNORE_CA_CERTIFICATES: opt_ignore_ca_certs = 1; break; + case OPT_UPDATE_EXISTING: + opt_update_existing = 1; + break; default: util_print_usage_and_die(app_name, options, option_help, NULL); } @@ -2773,7 +2800,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; + char *pin = NULL; int r; if (!auth_id_str) { @@ -2817,7 +2844,7 @@ static int verify_pin(struct sc_pkcs15_card *p15card, char *auth_id_str) } if (opt_pins[0] != NULL) { - pin = opt_pins[0]; + pin = (char *) opt_pins[0]; } else { sc_ui_hints_t hints; @@ -2825,7 +2852,7 @@ static int verify_pin(struct sc_pkcs15_card *p15card, char *auth_id_str) if (opt_no_prompt) return SC_ERROR_OBJECT_NOT_FOUND; - if (pin_obj->label) + if (0 < strnlen(pin_obj->label, sizeof pin_obj->label)) snprintf(pin_label, sizeof(pin_label), "User PIN [%s]", pin_obj->label); else snprintf(pin_label, sizeof(pin_label), "User PIN"); @@ -2844,5 +2871,8 @@ static int verify_pin(struct sc_pkcs15_card *p15card, char *auth_id_str) if (r < 0) fprintf(stderr, "Operation failed: %s\n", sc_strerror(r)); + if (NULL == opt_pins[0]) + free(pin); + return r; } diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index e5689fc0..4b0cbd85 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -21,6 +21,7 @@ #include "config.h" #include +#include #ifdef ENABLE_OPENSSL #if defined(HAVE_INTTYPES_H) @@ -52,11 +53,14 @@ static char * opt_data = NULL; static char * opt_pubkey = NULL; static char * opt_outfile = NULL; static char * opt_bind_to_aid = NULL; -static const u8 * opt_newpin = NULL; -static const u8 * opt_pin = NULL; -static const u8 * opt_puk = NULL; +static const char * opt_newpin = NULL; +static const char * opt_pin = NULL; +static const char * opt_puk = NULL; static int verbose = 0; static int opt_no_prompt = 0; +#if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) +static int opt_rfc4716 = 0; +#endif enum { OPT_CHANGE_PIN = 0x100, @@ -68,6 +72,7 @@ enum { OPT_READ_PUB, #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) OPT_READ_SSH, + OPT_RFC4716, #endif OPT_PIN, OPT_NEWPIN, @@ -76,7 +81,7 @@ enum { OPT_BIND_TO_AID, OPT_LIST_APPLICATIONS, OPT_LIST_SKEYS, - OPT_NO_PROMPT + OPT_NO_PROMPT, }; #define NELEMENTS(x) (sizeof(x)/sizeof((x)[0])) @@ -100,6 +105,7 @@ static const struct option options[] = { { "read-public-key", required_argument, NULL, OPT_READ_PUB }, #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) { "read-ssh-key", required_argument, NULL, OPT_READ_SSH }, + { "rfc4716", no_argument, NULL, OPT_RFC4716 }, #endif { "test-update", no_argument, NULL, 'T' }, { "update", no_argument, NULL, 'U' }, @@ -135,6 +141,7 @@ static const char *option_help[] = { "Reads public key with ID ", #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) "Reads public key with ID , outputs ssh format", + "Outputs the public key in RFC 4716 format (requires --read-ssh-key)", #endif "Test if the card needs a security update", "Update the card with a security update", @@ -150,6 +157,7 @@ static const char *option_help[] = { "Wait for card insertion", "Verbose operation. Use several times to enable debug output.", "Do not prompt the user; if no PINs supplied, pinpad will be used.", + NULL }; static sc_context_t *ctx = NULL; @@ -306,7 +314,7 @@ print_pem_object(const char *kind, const u8*data, size_t data_len) return 0; } -static int +static void list_data_object(const char *kind, const unsigned char *data, size_t data_len) { char title[0x100]; @@ -321,8 +329,6 @@ list_data_object(const char *kind, const unsigned char *data, size_t data_len) printf("%02X", data[i]); } printf("\n"); - - return 0; } static int @@ -457,7 +463,7 @@ static int list_data_objects(void) int idx; struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data; - if (objs[i]->label) + if (0 < strnlen(objs[i]->label, sizeof objs[i]->label)) printf("Data object '%s'\n", objs[i]->label); else printf("Data object <%i>\n", i); @@ -478,7 +484,7 @@ static int list_data_objects(void) continue; /* DEE emulation may say there is a file */ return 1; } - r = list_data_object("\tData", data_object->data, data_object->data_len); + list_data_object("\tData", data_object->data, data_object->data_len); sc_pkcs15_free_data_object(data_object); } else { @@ -589,6 +595,7 @@ static void print_pubkey_info(const struct sc_pkcs15_object *obj) "neverExtract", "local" }; const unsigned int af_count = NELEMENTS(access_flags); + int have_path = (pubkey->path.len != 0) || (pubkey->path.aid.len != 0); printf("Public %s Key [%s]\n", types[7 & obj->type], obj->label); print_common_flags(obj); @@ -607,18 +614,29 @@ static void print_pubkey_info(const struct sc_pkcs15_object *obj) print_access_rules(obj->access_rules, SC_PKCS15_MAX_ACCESS_RULES); - if (pubkey->modulus_length) + if (pubkey->modulus_length) { printf("\tModLength : %lu\n", (unsigned long)pubkey->modulus_length); - else - printf("\tFieldLength : %lu\n", (unsigned long)pubkey->field_length); + } + else if (pubkey->field_length) { + printf("\tFieldLength : %lu\n", (unsigned long)pubkey->field_length); + } + else if (obj->type == SC_PKCS15_TYPE_PUBKEY_EC && have_path) { + sc_pkcs15_pubkey_t *pkey = NULL; + if (!sc_pkcs15_read_pubkey(p15card, obj, &pkey)) { + printf("\tFieldLength : %lu\n", (unsigned long)pkey->u.ec.params.field_length); + sc_pkcs15_free_pubkey(pkey); + } + } + printf("\tKey ref : %d (0x%X)\n", pubkey->key_reference, pubkey->key_reference); printf("\tNative : %s\n", pubkey->native ? "yes" : "no"); - if (pubkey->path.len || pubkey->path.aid.len) + if (have_path) printf("\tPath : %s\n", sc_print_path(&pubkey->path)); if (obj->auth_id.len != 0) printf("\tAuth ID : %s\n", sc_pkcs15_print_id(&obj->auth_id)); printf("\tID : %s\n", sc_pkcs15_print_id(&pubkey->id)); - printf("\tDirectValue : <%s>\n", obj->content.len ? "present" : "absent"); + if (!have_path || obj->content.len) + printf("\tDirectValue : <%s>\n", obj->content.len ? "present" : "absent"); } static int list_public_keys(void) @@ -776,6 +794,41 @@ static int list_skeys(void) #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) + +static void print_ssh_key(FILE *outf, const char * alg, struct sc_pkcs15_object *obj, unsigned char * buf, uint32_t len) { + unsigned char *uu; + int r; + + uu = malloc(len*2); // Way over - even if we have extra LFs; as each 6 bits take one byte. + + if (opt_rfc4716) { + r = sc_base64_encode(buf, len, uu, 2*len, 64); + if (r < 0) + return; + + fprintf(outf,"---- BEGIN SSH2 PUBLIC KEY ----\n"); + + if (obj->label && strlen(obj->label)) + fprintf(outf,"Comment: \"%s\"\n", obj->label); + + fprintf(outf,"%s", uu); + fprintf(outf,"---- END SSH2 PUBLIC KEY ----\n"); + } else { + // Old style openssh - [ [ anything else] + // + r = sc_base64_encode(buf, len, uu, 2*len, 0); + if (r < 0) + return; + + if (obj->label && strlen(obj->label)) + fprintf(outf,"ssh-%s %s %s\n", alg, uu, obj->label); + else + fprintf(outf,"ssh-%s %s\n", alg, uu); + } + free(uu); + return; +} + static int read_ssh_key(void) { int r; @@ -783,17 +836,17 @@ static int read_ssh_key(void) struct sc_pkcs15_object *obj = NULL; sc_pkcs15_pubkey_t *pubkey = NULL; sc_pkcs15_cert_t *cert = NULL; - FILE *outf = NULL; + FILE *outf = NULL; - if (opt_outfile != NULL) { - outf = fopen(opt_outfile, "w"); - if (outf == NULL) { - fprintf(stderr, "Error opening file '%s': %s\n", opt_outfile, strerror(errno)); - goto fail2; - } - } + if (opt_outfile != NULL) { + outf = fopen(opt_outfile, "w"); + if (outf == NULL) { + fprintf(stderr, "Error opening file '%s': %s\n", opt_outfile, strerror(errno)); + goto fail2; + } + } else { - outf = stdout; + outf = stdout; } id.len = SC_PKCS15_MAX_ID_SIZE; @@ -834,7 +887,6 @@ static int read_ssh_key(void) if (pubkey->algorithm == SC_ALGORITHM_RSA) { unsigned char buf[2048]; - unsigned char *uu; uint32_t len, n; if (!pubkey->u.rsa.modulus.data || !pubkey->u.rsa.modulus.len || @@ -885,16 +937,11 @@ static int read_ssh_key(void) memcpy(buf+len,pubkey->u.rsa.modulus.data, pubkey->u.rsa.modulus.len); len += pubkey->u.rsa.modulus.len; - uu = malloc(len*2); - r = sc_base64_encode(buf, len, uu, 2*len, 2*len); - - fprintf(outf,"ssh-rsa %s", uu); - free(uu); + print_ssh_key(outf, "rsa", obj, buf, len); } if (pubkey->algorithm == SC_ALGORITHM_DSA) { unsigned char buf[2048]; - unsigned char *uu; uint32_t len; uint32_t n; @@ -981,32 +1028,28 @@ static int read_ssh_key(void) memcpy(buf+len,pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len); len += pubkey->u.dsa.pub.len; - uu = malloc(len*2); - r = sc_base64_encode(buf, len, uu, 2*len, 2*len); - - fprintf(outf,"ssh-dss %s", uu); - free(uu); + print_ssh_key(outf, "dss", obj, buf, len); } - if (outf != stdout) - fclose(outf); + if (outf != stdout) + fclose(outf); if (cert) sc_pkcs15_free_certificate(cert); - else if (pubkey) - sc_pkcs15_free_pubkey(pubkey); + sc_pkcs15_free_pubkey(pubkey); return 0; fail: printf("can't convert key: buffer too small\n"); fail2: - if (outf != stdout) - fclose(outf); + if (outf && outf != stdout) + fclose(outf); if (cert) sc_pkcs15_free_certificate(cert); else if (pubkey) sc_pkcs15_free_pubkey(pubkey); return SC_ERROR_OUT_OF_MEMORY; } + #endif static sc_pkcs15_object_t * @@ -1116,7 +1159,7 @@ static int verify_pin(void) } if (opt_pin != NULL) - pin = opt_pin; + pin = (unsigned char *) opt_pin; else pin = get_pin("Please enter PIN", pin_obj); @@ -1127,13 +1170,16 @@ static int verify_pin(void) return -1; } + if (opt_pin == NULL) + free(pin); + return 0; } static int authenticate(sc_pkcs15_object_t *obj) { sc_pkcs15_object_t *pin_obj; - u8 *pin; + u8 *pin = NULL; int r; if (obj->auth_id.len == 0) @@ -1143,11 +1189,16 @@ static int authenticate(sc_pkcs15_object_t *obj) return r; if (opt_pin != NULL) - pin = opt_pin; + pin = (u8 *) opt_pin; else pin = get_pin("Please enter PIN", pin_obj); - return sc_pkcs15_verify_pin(p15card, pin_obj, pin, pin? strlen((char *) pin) : 0); + r = sc_pkcs15_verify_pin(p15card, pin_obj, pin, pin? strlen((char *) pin) : 0); + + if (opt_pin == NULL) + free(pin); + + return r; } static void print_pin_info(const struct sc_pkcs15_object *obj) @@ -1307,7 +1358,7 @@ static int unblock_pin(void) if (pinfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return 1; - puk = opt_puk; + puk = (u8 *) opt_puk; if (puk == NULL) { sc_pkcs15_object_t *puk_obj = NULL; @@ -1338,7 +1389,7 @@ static int unblock_pin(void) printf("PUK value will be prompted with pinpad.\n"); /* FIXME should OPENSSL_cleanse on pin/puk data */ - pin = opt_pin ? opt_pin : opt_newpin; + pin = opt_pin ? (u8 *) opt_pin : (u8 *) opt_newpin; while (pin == NULL) { u8 *pin2; @@ -1348,12 +1399,17 @@ static int unblock_pin(void) printf("New PIN value will be prompted with pinpad.\n"); break; } - if (pin == NULL || strlen((char *) pin) == 0) + if (pin == NULL || strlen((char *) pin) == 0) { + free(pin); return 2; + } pin2 = get_pin("Enter new PIN again", pin_obj); - if (pin2 == NULL || strlen((char *) pin2) == 0) + if (pin2 == NULL || strlen((char *) pin2) == 0) { + free(pin); + free(pin2); return 2; + } if (strcmp((char *) pin, (char *) pin2) != 0) { printf("PIN codes do not match, try again.\n"); free(pin); @@ -1365,7 +1421,12 @@ static int unblock_pin(void) r = sc_pkcs15_unblock_pin(p15card, pin_obj, puk, puk ? strlen((char *) puk) : 0, pin, pin ? strlen((char *) pin) : 0); - /* FIXME must free the puk somewhere */ + + if (NULL == opt_puk) + free(puk); + if (NULL == opt_pin && NULL == opt_newpin) + free(pin); + if (r == SC_ERROR_PIN_CODE_INCORRECT) { fprintf(stderr, "PUK code incorrect; tries left: %d\n", pinfo->tries_left); return 3; @@ -1405,7 +1466,7 @@ static int change_pin(void) } } - pincode = opt_pin; + pincode = (u8 *) opt_pin; if (pincode == NULL) { pincode = get_pin("Enter old PIN", pin_obj); if (!pinpad_present && pincode == NULL) @@ -1420,7 +1481,7 @@ static int change_pin(void) if (pincode == NULL && verbose) printf("Old PIN value will be prompted with pinpad.\n"); - newpin = opt_newpin; + newpin = (u8 *) opt_newpin; while (newpin == NULL) { u8 *newpin2; @@ -1432,6 +1493,7 @@ static int change_pin(void) } if (newpin == NULL || strlen((char *) newpin) == 0) { fprintf(stderr, "No new PIN value supplied.\n"); + free(newpin); return 2; } @@ -1459,7 +1521,12 @@ static int change_pin(void) } if (verbose) printf("PIN code changed successfully.\n"); - /* FIXME must free the pincode somewhere */ + + if (opt_pin == NULL) + free(pincode); + if (opt_newpin == NULL) + free(newpin); + return 0; } @@ -1803,6 +1870,8 @@ int main(int argc, char * const argv[]) int action_count = 0; sc_context_param_t ctx_param; + assert(sizeof(option_help)/sizeof(char *)==sizeof(options)/sizeof(struct option)); + c = OPT_PUK; while (1) { @@ -1873,6 +1942,9 @@ int main(int argc, char * const argv[]) do_read_sshkey = 1; action_count++; break; + case OPT_RFC4716: + opt_rfc4716 = 1; + break; #endif case 'L': do_learn_card = 1; @@ -1890,13 +1962,13 @@ int main(int argc, char * const argv[]) opt_reader = optarg; break; case OPT_PIN: - util_get_pin(optarg, (const u8 **) &opt_pin); + util_get_pin(optarg, &opt_pin); break; case OPT_NEWPIN: - util_get_pin(optarg, (const u8 **) &opt_newpin); + util_get_pin(optarg, &opt_newpin); break; case OPT_PUK: - util_get_pin(optarg, (const u8 **) &opt_puk); + util_get_pin(optarg, &opt_puk); break; case 'o': opt_outfile = optarg; diff --git a/src/tools/sc-hsm-tool.c b/src/tools/sc-hsm-tool.c index 2d173a0e..22680c33 100644 --- a/src/tools/sc-hsm-tool.c +++ b/src/tools/sc-hsm-tool.c @@ -62,6 +62,8 @@ static int verbose = 0; #define MAX_KEY 1024 #define MAX_WRAPPED_KEY (MAX_CERT + MAX_PRKD + MAX_KEY) +#define SEED_LENGTH 16 + enum { OPT_SO_PIN = 0x100, OPT_PIN, @@ -139,14 +141,15 @@ static sc_card_t *card = NULL; * @param s Secret to share * @param n Maximum number of shares * @param rngSeed Seed value for CPRNG + * @param rngSeedLength Lenght of Seed value for CPRNG * */ -static void generatePrime(BIGNUM *prime, const BIGNUM *s, const unsigned int n, unsigned char *rngSeed) +static void generatePrime(BIGNUM *prime, const BIGNUM *s, const unsigned int n, unsigned char *rngSeed, const unsigned int rngSeedLength) { int bits = 0; // Seed the RNG - RAND_seed(rngSeed, sizeof(rngSeed)); + RAND_seed(rngSeed, rngSeedLength); // Determine minimum number of bits for prime >= max(2^r, n + 1) bits = BN_num_bits_word(n + 1) > BN_num_bits(s) ? (BN_num_bits_word(n + 1)) : (BN_num_bits(s)); @@ -342,6 +345,7 @@ static int reconstructSecret(secret_share_t *shares, unsigned char t, const BIGN * multiplication */ if (BN_mod_inverse(&denominator, &denominator, &prime, ctx) == NULL ) { + free(bValue); return -1; } @@ -417,14 +421,18 @@ static int cleanUpShares(secret_share_t *shares, unsigned char n) void clearScreen() { - if (system( "clear" )) system( "cls" ); + if (system( "clear" )) { + if (system( "cls" )) { + fprintf(stderr, "Clearing the screen failed\n"); + } + } } void waitForEnterKeyPressed() { - char c; + int c; fflush(stdout); while ((c = getchar()) != '\n' && c != EOF) { @@ -588,6 +596,11 @@ static int recreate_password_from_shares(char **pwd, int *pwdlen, int num_of_pas secret_share_t *shares = NULL; secret_share_t *sp; + if (num_of_password_shares < 2) { + fprintf(stderr, "--pwd-shares-total must 2 or larger\n"); + return -1; + } + /* * Initialize prime and secret */ @@ -602,7 +615,10 @@ static int recreate_password_from_shares(char **pwd, int *pwdlen, int num_of_pas printf("\nPlease remember to present the share id as well as the share value."); printf("\n\nPlease enter prime: "); memset(inbuf, 0, sizeof(inbuf)); - fgets(inbuf, sizeof(inbuf), stdin); + if (fgets(inbuf, sizeof(inbuf), stdin) == NULL) { + fprintf(stderr, "Input aborted\n"); + return -1; + } binlen = 64; sc_hex_to_bin(inbuf, bin, &binlen); BN_bin2bn(bin, binlen, &prime); @@ -623,13 +639,19 @@ static int recreate_password_from_shares(char **pwd, int *pwdlen, int num_of_pas printf("Please enter share ID: "); memset(inbuf, 0, sizeof(inbuf)); - fgets(inbuf, sizeof(inbuf), stdin); + if (fgets(inbuf, sizeof(inbuf), stdin) == NULL) { + fprintf(stderr, "Input aborted\n"); + return -1; + } p = &(sp->x); BN_hex2bn(&p, inbuf); printf("Please enter share value: "); memset(inbuf, 0, sizeof(inbuf)); - fgets(inbuf, sizeof(inbuf), stdin); + if (fgets(inbuf, sizeof(inbuf), stdin) == NULL) { + fprintf(stderr, "Input aborted\n"); + return -1; + } binlen = 64; sc_hex_to_bin(inbuf, bin, &binlen); BN_bin2bn(bin, binlen, &(sp->y)); @@ -643,6 +665,7 @@ static int recreate_password_from_shares(char **pwd, int *pwdlen, int num_of_pas if (r < 0) { printf("\nError during reconstruction of secret. Wrong shares?\n"); + cleanUpShares(shares, num_of_password_shares); return r; } @@ -664,7 +687,7 @@ static int recreate_password_from_shares(char **pwd, int *pwdlen, int num_of_pas -static int import_dkek_share(sc_card_t *card, const char *inf, int iter, char *password, int num_of_password_shares) +static int import_dkek_share(sc_card_t *card, const char *inf, int iter, const char *password, int num_of_password_shares) { sc_cardctl_sc_hsm_dkek_t dkekinfo; EVP_CIPHER_CTX ctx; @@ -687,6 +710,7 @@ static int import_dkek_share(sc_card_t *card, const char *inf, int iter, char *p if (fread(filebuff, 1, sizeof(filebuff), in) != sizeof(filebuff)) { perror(inf); + fclose(in); return -1; } @@ -712,7 +736,7 @@ static int import_dkek_share(sc_card_t *card, const char *inf, int iter, char *p } } else { - pwd = password; + pwd = (char *) password; pwdlen = strlen(password); } @@ -814,6 +838,26 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas u8 rngseed[16]; + if ((password_shares_threshold == -1) || (password_shares_total == -1)) { + fprintf(stderr, "Must specify both, --pwd-shares-total and --pwd-shares-threshold\n"); + return -1; + } + + if (password_shares_total < 3) { + fprintf(stderr, "--pwd-shares-total must be 3 or larger\n"); + return -1; + } + + if (password_shares_threshold < 2) { + fprintf(stderr, "--pwd-shares-threshold must 2 or larger\n"); + return -1; + } + + if (password_shares_threshold > password_shares_total) { + fprintf(stderr, "--pwd-shares-threshold must be smaller or equal to --pwd-shares-total\n"); + return -1; + } + printf( "\nThe DKEK will be enciphered using a randomly generated 64 bit password.\n"); printf( "This password is split using a (%i-of-%i) threshold scheme.\n\n", password_shares_threshold, password_shares_total); @@ -851,7 +895,7 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas /* * Generate seed and calculate a prime depending on the size of the secret */ - r = sc_get_challenge(card, rngseed, 16); + r = sc_get_challenge(card, rngseed, SEED_LENGTH); if (r < 0) { printf("Error generating random seed failed with %s", sc_strerror(r)); OPENSSL_cleanse(*pwd, *pwdlen); @@ -859,7 +903,7 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas return r; } - generatePrime(&prime, &secret, password_shares_total, rngseed); + generatePrime(&prime, &secret, password_shares_total, rngseed, SEED_LENGTH); // Allocate data buffer for the generated shares shares = malloc(password_shares_total * sizeof(secret_share_t)); @@ -904,7 +948,7 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas -static int create_dkek_share(sc_card_t *card, const char *outf, int iter, char *password, int password_shares_threshold, int password_shares_total) +static int create_dkek_share(sc_card_t *card, const char *outf, int iter, const char *password, int password_shares_threshold, int password_shares_total) { EVP_CIPHER_CTX ctx; FILE *out = NULL; @@ -919,15 +963,14 @@ static int create_dkek_share(sc_card_t *card, const char *outf, int iter, char * } if (password == NULL) { - - if (password_shares_threshold == -1) { + if ((password_shares_threshold == -1) && (password_shares_total == -1)) { ask_for_password(&pwd, &pwdlen); } else { // create password using threshold scheme r = generate_pwd_shares(card, &pwd, &pwdlen, password_shares_threshold, password_shares_total); } } else { - pwd = password; + pwd = (char *) password; pwdlen = strlen(password); } @@ -979,6 +1022,7 @@ static int create_dkek_share(sc_card_t *card, const char *outf, int iter, char * if (fwrite(filebuff, 1, sizeof(filebuff), out) != sizeof(filebuff)) { perror(outf); + fclose(out); return -1; } @@ -1169,7 +1213,10 @@ static int wrap_key(sc_card_t *card, int keyid, const char *outf, const char *pi memcpy(ptr, key, key_len); ptr += key_len; + free(key); + key = NULL; + key_len = 0; // Add private key description if (ef_prkd_len > 0) { @@ -1184,7 +1231,6 @@ static int wrap_key(sc_card_t *card, int keyid, const char *outf, const char *pi } // Encode key, key decription and certificate object in sequence - key_len = 0; wrap_with_tag(0x30, keyblob, ptr - keyblob, &key, &key_len); out = fopen(outf, "wb"); @@ -1198,6 +1244,7 @@ static int wrap_key(sc_card_t *card, int keyid, const char *outf, const char *pi if (fwrite(key, 1, key_len, out) != key_len) { perror(outf); free(key); + fclose(out); return -1; } @@ -1439,7 +1486,7 @@ int main(int argc, char * const argv[]) const char *opt_so_pin = NULL; const char *opt_pin = NULL; const char *opt_filename = NULL; - char *opt_password = NULL; + const char *opt_password = NULL; int opt_retry_counter = 3; int opt_dkek_shares = -1; int opt_key_reference = -1; @@ -1484,18 +1531,12 @@ int main(int argc, char * const argv[]) action_count++; break; case OPT_PASSWORD: - free(opt_password); - opt_password = NULL; util_get_pin(optarg, &opt_password); break; case OPT_SO_PIN: - free(opt_so_pin); - opt_so_pin = NULL; util_get_pin(optarg, &opt_so_pin); break; case OPT_PIN: - free(opt_pin); - opt_pin = NULL; util_get_pin(optarg, &opt_pin); break; case OPT_RETRY: diff --git a/src/tools/util.c b/src/tools/util.c index 0b0cebd6..e11ffb02 100644 --- a/src/tools/util.c +++ b/src/tools/util.c @@ -376,7 +376,8 @@ util_getpass (char **lineptr, size_t *len, FILE *stream) { #define MAX_PASS_SIZE 128 char *buf; - unsigned int i; + size_t i; + int ch = 0; #ifndef _WIN32 struct termios old, new; @@ -395,26 +396,26 @@ util_getpass (char **lineptr, size_t *len, FILE *stream) for (i = 0; i < MAX_PASS_SIZE - 1; i++) { #ifndef _WIN32 - buf[i] = getchar(); + ch = getchar(); #else - buf[i] = _getch(); + ch = _getch(); #endif - if (buf[i] == 0 || buf[i] == 3) + if (ch == 0 || ch == 3) break; - if (buf[i] == '\n' || buf[i] == '\r') + if (ch == '\n' || ch == '\r') break; + + buf[i] = (char) ch; } #ifndef _WIN32 tcsetattr (fileno (stdout), TCSAFLUSH, &old); fputs("\n", stdout); #endif - if (buf[i] == 0 || buf[i] == 3) { + if (ch == 0 || ch == 3) { free(buf); return -1; } - buf[i] = 0; - if (*lineptr && (!len || *len < i+1)) { free(*lineptr); *lineptr = NULL; diff --git a/src/tools/westcos-tool.c b/src/tools/westcos-tool.c index 83ece8e8..24136fbb 100644 --- a/src/tools/westcos-tool.c +++ b/src/tools/westcos-tool.c @@ -126,7 +126,7 @@ static void print_openssl_error(void) printf("%s\n", ERR_error_string(r, NULL)); } -static int verify_pin(sc_card_t *card, int pin_reference, char *pin_value) +static int verify_pin(sc_card_t *card, int pin_reference, const char *pin_value) { int r, tries_left = -1; struct sc_pin_cmd_data data; @@ -178,8 +178,8 @@ static int verify_pin(sc_card_t *card, int pin_reference, char *pin_value) static int change_pin(sc_card_t *card, int pin_reference, - char *pin_value1, - char *pin_value2) + const char *pin_value1, + const char *pin_value2) { int r, tries_left = -1; struct sc_pin_cmd_data data; @@ -236,8 +236,8 @@ static int change_pin(sc_card_t *card, static int unlock_pin(sc_card_t *card, int pin_reference, - char *puk_value, - char *pin_value) + const char *puk_value, + const char *pin_value) { int r, tries_left = -1; struct sc_pin_cmd_data data; @@ -305,7 +305,7 @@ static int cert2der(X509 *cert, u8 **value) static int create_file_cert(sc_card_t *card) { int r; - int size; + int size = 0; sc_path_t path; sc_file_t *file = NULL; @@ -313,12 +313,13 @@ static int create_file_cert(sc_card_t *card) r = sc_select_file(card, &path, &file); if(r) goto out; - size = (file->size) - 32; - if(file) { + size = (file->size) - 32; sc_file_free(file); file = NULL; + } else { + size = 2048; } sc_format_path("0002", &path); @@ -903,8 +904,7 @@ out: sc_disconnect_card(card); } - if (ctx) - sc_release_context(ctx); + sc_release_context(ctx); return EXIT_SUCCESS; } diff --git a/win32/Make.rules.mak b/win32/Make.rules.mak index 316988cf..e13eae2f 100644 --- a/win32/Make.rules.mak +++ b/win32/Make.rules.mak @@ -6,10 +6,26 @@ MINIDRIVER_DEF = /DENABLE_MINIDRIVER #Build MSI with the Windows Installer XML (WIX) toolkit, requires WIX >= 3.6 !IF "$(BUILD_ON)" == "WIN64" WIX_PATH = "C:\Program Files (x86)\Windows Installer XML v3.6" +WIX_INCL_DIR = "/IC:\Program Files (x86)\Windows Installer XML v3.6\SDK\inc" +!IF "$(BUILD_FOR)" == "WIN64" +WIX_LIBS = "C:\Program Files (x86)\Windows Installer XML v3.6\SDK\lib\dutil_2010_x64.lib" "C:\Program Files (x86)\Windows Installer XML v3.6\SDK\lib\wcautil_2010_x64.lib" +!ELSE +WIX_LIBS = "C:\Program Files (x86)\Windows Installer XML v3.6\SDK\lib\dutil_2010.lib" "C:\Program Files (x86)\Windows Installer XML v3.6\SDK\lib\wcautil_2010.lib" +!ENDIF + !ELSE WIX_PATH = "C:\Program Files\Windows Installer XML v3.6" +WIX_INCL_DIR = "/IC:\Program Files\Windows Installer XML v3.6\SDK\inc" +!IF "$(BUILD_FOR)" == "WIN64" +WIX_LIBS = "C:\Program Files\Windows Installer XML v3.6\SDK\lib\dutil_2010_x64.lib" "C:\Program Files\Windows Installer XML v3.6\SDK\lib\wcautil_2010_x64.lib" +!ELSE +WIX_LIBS = "C:\Program Files\Windows Installer XML v3.6\SDK\lib\dutil_2010.lib" "C:\Program Files\Windows Installer XML v3.6\SDK\lib\wcautil_2010.lib" !ENDIF +!ENDIF + + + #Include support for Secure Messaging SM_DEF = /DENABLE_SM @@ -67,7 +83,7 @@ CNGSDK_INCL_DIR = "/IC:\Program Files\Microsoft CNG Development Kit\Include" # O1 - minimal code size CODE_OPTIMIZATION = /O1 -ALL_INCLUDES = /I$(TOPDIR)\win32 /I$(TOPDIR)\src $(OPENSSL_INCL_DIR) $(ZLIB_INCL_DIR) $(LIBLTDL_INCL) $(INTTYPES_INCL_DIR) $(CNGSDK_INCL_DIR) +ALL_INCLUDES = /I$(TOPDIR)\win32 /I$(TOPDIR)\src $(OPENSSL_INCL_DIR) $(ZLIB_INCL_DIR) $(LIBLTDL_INCL) $(INTTYPES_INCL_DIR) $(CNGSDK_INCL_DIR) $(WIX_INCL_DIR) !IF "$(DEBUG_DEF)" == "/DDEBUG" LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMT /DEBUG @@ -91,6 +107,9 @@ CANDLEFLAGS = -dPlatform=x86 .c.obj:: cl $(CODE_OPTIMIZATION) $(COPTS) /c $< +.cpp.obj:: + cl $(CODE_OPTIMIZATION) $(COPTS) /c $< + .rc.res:: rc /l 0x0409 $< diff --git a/win32/Makefile.am b/win32/Makefile.am index c42d7be6..8bdb1df1 100644 --- a/win32/Makefile.am +++ b/win32/Makefile.am @@ -1,9 +1,29 @@ +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)/license.rtf + $(srcdir)/OpenSC.iss $(srcdir)/OpenSC.wxs $(srcdir)/OpenSC.ico $(srcdir)/license.rtf \ + $(srcdir)/dlgbmp.bmp $(srcdir)/bannrbmp.bmp $(srcdir)/versioninfo-customactions.rc EXTRA_DIST = ltrc.inc Makefile.mak Make.rules.mak opensc-install.bat \ - versioninfo.rc.in winconfig.h.in OpenSC.iss.in OpenSC.wxs.in -dist_noinst_HEADERS = versioninfo.rc winconfig.h OpenSC.iss OpenSC.wxs license.rtf OpenSC.ico + 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 license.rtf OpenSC.ico dlgbmp.bmp bannrbmp.bmp if WIN32 sbin_SCRIPTS = opensc-install.bat endif + +if ENABLE_MINIDRIVER +lib_LTLIBRARIES = customactions@LIBRARY_BITNESS@.la + +AM_CPPFLAGS = -I$(top_srcdir) + + +customactions@LIBRARY_BITNESS@_la_SOURCES = customactions.cpp customactions.exports versioninfo-customactions.rc +customactions@LIBRARY_BITNESS@_la_LIBADD = \ + $(top_builddir)/win32/customactions.la +customactions@LIBRARY_BITNESS@_la_LDFLAGS = $(AM_LDFLAGS) \ + -export-symbols "$(srcdir)/customactions.exports" \ + -module -avoid-version -no-undefined + +install-exec-hook: + mv "$(DESTDIR)$(libdir)/customactions@LIBRARY_BITNESS@.dll" "$(DESTDIR)$(bindir)/" +endif diff --git a/win32/Makefile.mak b/win32/Makefile.mak index f3be55bd..465e2f44 100644 --- a/win32/Makefile.mak +++ b/win32/Makefile.mak @@ -2,16 +2,22 @@ TOPDIR = .. !INCLUDE $(TOPDIR)\win32\Make.rules.mak -all: config.h +all: versioninfo-customactions.res config.h config.h: winconfig.h copy /y winconfig.h config.h +customactions.dll: versioninfo-customactions.res customactions.obj + echo LIBRARY $* > $*.def + echo EXPORTS >> $*.def + type customactions.exports >> $*.def + link /dll $(LINKFLAGS) /def:$*.def /out:customactions.dll versioninfo-customactions.res customactions.obj msi.lib $(WIX_LIBS) Advapi32.lib User32.lib Version.lib Shell32.lib + OpenSC.msi: OpenSC.wixobj $(WIX_PATH)\bin\light.exe -sh -ext WixUIExtension -ext WiXUtilExtension $? -OpenSC.wixobj: OpenSC.wxs - $(WIX_PATH)\bin\candle.exe -ext WiXUtilExtension -dSOURCE_DIR=$(TOPDIR) $(CANDLEFLAGS) $? +OpenSC.wixobj: OpenSC.wxs customactions.dll + $(WIX_PATH)\bin\candle.exe -ext WiXUtilExtension -dSOURCE_DIR=$(TOPDIR) $(CANDLEFLAGS) OpenSC.wxs clean:: del /Q config.h *.msi *.wixobj *.wixpdb diff --git a/win32/OpenSC.wxs.in b/win32/OpenSC.wxs.in index eb793c11..39db85ed 100644 --- a/win32/OpenSC.wxs.in +++ b/win32/OpenSC.wxs.in @@ -23,7 +23,7 @@ Manufacturer="OpenSC Project"> + + + + + + + + @@ -49,9 +57,29 @@ + + + + + + + + + + + @@ -77,6 +105,7 @@ + @@ -180,6 +209,9 @@ + + + @@ -187,7 +219,7 @@ - + @@ -203,12 +235,14 @@ + + @@ -245,6 +279,7 @@ + @@ -252,5 +287,20 @@ + + + + + + + + + + + + + + + diff --git a/win32/bannrbmp.bmp b/win32/bannrbmp.bmp new file mode 100644 index 00000000..84bed88a Binary files /dev/null and b/win32/bannrbmp.bmp differ diff --git a/win32/customactions.cpp b/win32/customactions.cpp new file mode 100644 index 00000000..988e1ffd --- /dev/null +++ b/win32/customactions.cpp @@ -0,0 +1,264 @@ +/* + * opensc-setup-custom-action.c: OpenSC setup custom action + * + * Copyright (C) 2015 vincent.letoux@mysmartlogon.com + * + * 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 + */ + +/* + * This module requires the WIX SDK to build. + */ + +#include "config.h" +#ifdef ENABLE_MINIDRIVER + +#ifdef _MANAGED +#pragma managed(push, off) +#endif + +#include +#include + +#include +#include +#include + +#include + +// WiX Header Files: +#include + +#define X86onX64_SC_DATABASE TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\Cryptography\\Calais\\SmartCards") +#define SC_DATABASE TEXT("SOFTWARE\\Microsoft\\Cryptography\\Calais\\SmartCards") +#define BASE_CSP TEXT("OpenSC CSP") +#define BASE_KSP TEXT("Microsoft Smart Card Key Storage Provider") + +typedef struct _MD_REGISTRATION +{ + TCHAR szName[256]; + BYTE pbAtr[256]; + DWORD dwAtrSize; + BYTE pbAtrMask[256]; +} MD_REGISTRATION, *PMD_REGISTRATION; + +/* note: we could have added the minidriver registration data directly in OpenSC.wxs but coding it allows for more checks. +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}}, + /* 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}, + 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}, + 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 */ + {TEXT("MaskTech smart card (a)"), {0x3b,0x89,0x80,0x01,0x4d,0x54,0x43,0x4f,0x53,0x70,0x02,0x02,0x05,0x3b}, + 14, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("MaskTech smart card (b)"), {0x3B,0x9D,0x13,0x81,0x31,0x60,0x37,0x80,0x31,0xC0,0x69,0x4D,0x54,0x43,0x4F,0x53,0x73,0x02,0x02,0x05,0x41}, + 21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("MaskTech smart card (c)"), {0x3B,0x88,0x80,0x01,0x00,0x00,0x00,0x00,0x77,0x81,0x81,0x00,0x7E}, + 13, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("MaskTech smart card (d)"), {0x3B,0x9D,0x13,0x81,0x31,0x60,0x37,0x80,0x31,0xC0,0x69,0x4D,0x54,0x43,0x4F,0x53,0x73,0x02,0x01,0x02,0x45}, + 21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, +}; + + +/* remove a card in the database if and only if the CSP match the OpenSC CSP +The program try to avoid any failure to not break the uninstall process */ +VOID RemoveKey(PTSTR szSubKey) +{ + HKEY hKey = NULL; + LONG lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) + { + WcaLog(LOGMSG_STANDARD, "RegOpenKeyEx %S 0x%08X", szSubKey, lResult); + return; + } + TCHAR szName[MAX_PATH]; + DWORD dwSize = MAX_PATH; + FILETIME ftWrite; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + if (lResult == ERROR_SUCCESS) + { + DWORD dwIndex = 0; + do { + HKEY hTempKey = NULL; + dwIndex++; + lResult = RegOpenKeyEx (hKey, szName, 0, KEY_READ, &hTempKey); + if (lResult == ERROR_SUCCESS) + { + TCHAR szCSP[MAX_PATH] = {0}; + dwSize = MAX_PATH; + lResult = RegQueryValueEx(hTempKey, TEXT("Crypto Provider"), NULL, NULL, (PBYTE) szCSP, &dwSize); + RegCloseKey(hTempKey); + if (lResult == ERROR_SUCCESS) + { + if ( _tcsstr(szCSP, TEXT("OpenSC CSP")) != 0) + { + lResult = RegDeleteKey(hKey, szName); + if (lResult != ERROR_SUCCESS) + { + WcaLog(LOGMSG_STANDARD, "RegDeleteKey %S 0x%08X", szName, lResult); + } + else + { + dwIndex--; + } + } + } + else + { + WcaLog(LOGMSG_STANDARD, "RegQueryValueEx %S 0x%08X", szName, lResult); + } + } + dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey,dwIndex, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + } while (lResult == ERROR_SUCCESS); + } + RegCloseKey(hKey); +} + +UINT WINAPI RemoveSmartCardConfiguration(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "RemoveSmartCardConfiguration"); + ExitOnFailure(hr, "Failed to initialize"); + + WcaLog(LOGMSG_STANDARD, "Initialized."); + + /* clean a smart card database. As today the x64 setup doesn't handle x86 installation on x64 machine */ + RemoveKey(SC_DATABASE); + /* when this happens, just uncomment the following line: +#ifdef _M_X64 + RemoveKey(X86onX64_SC_DATABASE); +#endif + */ + + /* never fails or only if the msi uninstall didn't work. If the uninstall custom action trigger a failure, the user is unable to uninstall the software */ +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/* note: szKey is here in case the card has to be registered in the Calais and WOW3264node\Calais databases */ +void RegisterCardWithKey(PTSTR szKey, PTSTR szCard, PTSTR szPath, PBYTE pbATR, DWORD dwATRSize, PBYTE pbAtrMask) +{ + HKEY hKey = NULL; + HKEY hTempKey = NULL; + LONG lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) + { + WcaLog(LOGMSG_STANDARD, "unable to open the calais database."); + return; + } + lResult = RegCreateKeyEx(hKey, szCard, 0,NULL,0,KEY_WRITE, NULL,&hTempKey,NULL); + if(!lResult) + { + RegSetValueEx( hTempKey,TEXT("Crypto Provider"),0, REG_SZ, (PBYTE)BASE_CSP,sizeof(BASE_CSP) - sizeof(TCHAR)); + RegSetValueEx( hTempKey,TEXT("Smart Card Key Storage Provider"),0, REG_SZ, (PBYTE)BASE_KSP,sizeof(BASE_KSP) - sizeof(TCHAR)); + RegSetValueEx( hTempKey,TEXT("80000001"),0, REG_SZ, (PBYTE)szPath,(DWORD) (sizeof(TCHAR) * _tcslen(szPath))); + RegSetValueEx( hTempKey,TEXT("ATR"),0, REG_BINARY, (PBYTE)pbATR, dwATRSize); + RegSetValueEx( hTempKey,TEXT("ATRMask"),0, REG_BINARY, (PBYTE)pbAtrMask, dwATRSize); + RegCloseKey(hTempKey); + } + else + { + WcaLog(LOGMSG_STANDARD, "unable to create the card entry"); + } + RegCloseKey(hKey); +} + +VOID RegisterSmartCard(PMD_REGISTRATION registration) +{ + RegisterCardWithKey(SC_DATABASE, registration->szName, TEXT("opensc-minidriver.dll"),registration->pbAtr, registration->dwAtrSize, registration->pbAtrMask ); + +} + +UINT WINAPI AddSmartCardConfiguration(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + int i ; + + hr = WcaInitialize(hInstall, "AddSmartCardConfiguration"); + ExitOnFailure(hr, "Failed to initialize"); + + WcaLog(LOGMSG_STANDARD, "Initialized."); + + for (i = 0; i < sizeof(minidriver_registration) / sizeof(MD_REGISTRATION); i++) + { + RegisterSmartCard(minidriver_registration + i); + } + + /* never fails or only if the msi install functions didn't work. If the install custom action trigger a failure, the user is unable to install the software */ +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +// DllMain - Initialize and cleanup WiX custom action utils. +BOOL APIENTRY DllMain( + __in HINSTANCE hInst, + __in ULONG ulReason, + __in LPVOID + ) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} +#else + +UINT WINAPI AddSmartCardConfiguration(unsigned long hInstall) +{ + return 0; +} + +UINT WINAPI RemoveSmartCardConfiguration(unsigned long hInstall) +{ + return 0; +} +#endif diff --git a/win32/customactions.exports b/win32/customactions.exports new file mode 100644 index 00000000..614fd3cf --- /dev/null +++ b/win32/customactions.exports @@ -0,0 +1,2 @@ +AddSmartCardConfiguration +RemoveSmartCardConfiguration diff --git a/win32/dlgbmp.bmp b/win32/dlgbmp.bmp new file mode 100644 index 00000000..4e7a46f0 Binary files /dev/null and b/win32/dlgbmp.bmp differ diff --git a/win32/versioninfo-customactions.rc.in b/win32/versioninfo-customactions.rc.in new file mode 100644 index 00000000..757e9165 --- /dev/null +++ b/win32/versioninfo-customactions.rc.in @@ -0,0 +1,37 @@ +#include + +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 0x2L + 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 custom actions setup" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/win32/winconfig.h.in b/win32/winconfig.h.in index 57a313e0..c8e88770 100644 --- a/win32/winconfig.h.in +++ b/win32/winconfig.h.in @@ -95,4 +95,8 @@ #define OPENSC_FEATURES "N/A" #endif +#ifndef DEFAULT_PKCS11_PROVIDER +#define DEFAULT_PKCS11_PROVIDER "opensc-pkcs11.dll" +#endif + #endif