diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 49ba8602..183fb662 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,9 @@ ### Problem Description ### Proposed Resolution @@ -21,7 +23,7 @@ Debug output is essential to identify the problem. You can enable debugging by e #debug_file = opensc-debug.log ``` -Please use [Gist](https://gist.github.com/) or a similar code paster for longer logs. Before pasting here, remove your sensitive data from your log (e.g. PIN code or certificates). +Please use a Gist (https://gist.github.com/) or a similar code paster for longer logs. Before pasting here, remove your sensitive data from your log (e.g. PIN code or certificates). ``` Paste Log output with less than 10 lines here (between the backticks) diff --git a/.github/add_signing_key.sh b/.github/add_signing_key.sh new file mode 100755 index 00000000..689e2cad --- /dev/null +++ b/.github/add_signing_key.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +set -ex -o xtrace + +pushd .github/ +tar xvf secrets.tar +KEY_CHAIN=mac-build.keychain + +# Create the keychain with a password +security create-keychain -p travis $KEY_CHAIN + +# Make the custom keychain default, so xcodebuild will use it for signing +security default-keychain -s $KEY_CHAIN + +# Unlock the keychain for one hour +security unlock-keychain -p travis $KEY_CHAIN +security set-keychain-settings -t 3600 -u $KEY_CHAIN + +# Add certificates to keychain and allow codesign to access them +curl -L https://developer.apple.com/certificationauthority/AppleWWDRCA.cer > AppleWWDRCA.cer +security import AppleWWDRCA.cer -k ~/Library/Keychains/$KEY_CHAIN -T /usr/bin/codesign +security import certificate.cer -k ~/Library/Keychains/$KEY_CHAIN -T /usr/bin/codesign +security import certificate.p12 -k ~/Library/Keychains/$KEY_CHAIN -P $KEY_PASSWORD -T /usr/bin/codesign +security unlock-keychain -p travis $KEY_CHAIN + +# https://docs.travis-ci.com/user/common-build-problems/#mac-macos-sierra-1012-code-signing-errors +security set-key-partition-list -S apple-tool:,apple: -s -k travis $KEY_CHAIN +popd diff --git a/.github/push_artifacts.sh b/.github/push_artifacts.sh index 15d07868..4b7f5d9a 100755 --- a/.github/push_artifacts.sh +++ b/.github/push_artifacts.sh @@ -9,7 +9,7 @@ git clone --single-branch https://${GH_TOKEN}@github.com/OpenSC/Nightly.git > /d cd Nightly git checkout -b "${BRANCH}" -for file in ${BUILDPATH}/win32/Output/OpenSC*.exe ${BUILDPATH}/opensc*.tar.gz ${BUILDPATH}/OpenSC*.dmg ${BUILDPATH}/OpenSC*.msi ${BUILDPATH}/OpenSC*.zip ${BUILDPATH}/*.pkg +for file in ${BUILDPATH}/win32/Output/OpenSC*.exe ${BUILDPATH}/opensc*.tar.gz ${BUILDPATH}/OpenSC*.dmg ${BUILDPATH}/OpenSC*.msi ${BUILDPATH}/OpenSC*.zip do if [ -f ${file} ] then diff --git a/.github/remove_signing_key.sh b/.github/remove_signing_key.sh new file mode 100755 index 00000000..218471c5 --- /dev/null +++ b/.github/remove_signing_key.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -ex -o xtrace + +pushd .github/ +security delete-keychain mac-build.keychain +rm -f certificate.cer certificate.p12 +popd diff --git a/.github/secrets.tar.enc b/.github/secrets.tar.enc new file mode 100644 index 00000000..20690baa Binary files /dev/null and b/.github/secrets.tar.enc differ diff --git a/.gitignore b/.gitignore index 76f431d3..5dc35ee1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ core archive acinclude.m4 aclocal.m4 +aminclude_static.am autom4te.cache compile confdefs.h @@ -22,6 +23,7 @@ mkinstalldirs so_locations stamp-h* tags +test-driver .deps .libs .#*# diff --git a/.travis.yml b/.travis.yml index c565a8e2..d1b2e4e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ matrix: include: - compiler: clang os: osx + osx_image: xcode9.4 env: DO_PUSH_ARTIFACT=yes - compiler: gcc os: linux @@ -11,13 +12,11 @@ matrix: env: - DO_SIMULATION=javacard - ENABLE_DOC=--enable-doc - sudo: true - compiler: gcc os: linux dist: bionic env: - DO_SIMULATION=oseid - sudo: true - env: - HOST=x86_64-w64-mingw32 - DO_PUSH_ARTIFACT=yes @@ -30,7 +29,6 @@ matrix: dist: bionic env: - DO_SIMULATION=cac - sudo: true env: global: @@ -68,12 +66,17 @@ addons: before_install: # brew install gengetopt help2man cmocka ccache llvm; # export PATH="/usr/local/opt/ccache/libexec:/usr/local/opt/llvm/bin:$PATH"; + # add magic notarization flags for macOS, see https://github.com/akeru-inc/xcnotary/blob/master/README.md - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew uninstall libtool; brew install libtool; brew install gengetopt help2man cmocka ccache; export PATH="/usr/local/opt/ccache/libexec:$PATH"; + openssl aes-256-cbc -K $encrypted_3b9f0b9d36d1_key -iv $encrypted_3b9f0b9d36d1_iv -in .github/secrets.tar.enc -out .github/secrets.tar -d; + .github/add_signing_key.sh; + export OTHER_CODE_SIGN_FLAGS=--timestamp CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO CODE_SIGN_STYLE=Manual; + git clone https://github.com/frankmorgner/OpenSCToken.git; fi - if [ "${DO_SIMULATION}" = "cac" ]; then sudo apt-get install -y libglib2.0-dev libnss3-dev pkgconf libtool make autoconf autoconf-archive automake libsofthsm2-dev softhsm2 softhsm2-common help2man gnutls-bin libcmocka-dev libusb-dev libudev-dev flex libnss3-tools libssl-dev libpcsclite1; @@ -102,8 +105,11 @@ before_script: if [ ! -f "$(winepath 'C:/Program Files (x86)/Inno Setup 5/ISCC.exe')" ]; then /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16; export DISPLAY=:99.0; + [ -d isetup ] || mkdir isetup; + pushd isetup; [ -f isetup-5.5.6.exe ] || wget http://files.jrsoftware.org/is/5/isetup-5.5.6.exe; wine isetup-5.5.6.exe /SILENT /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART; + popd; fi; unset CC; unset CXX; @@ -283,7 +289,7 @@ script: fi - if [ "${DO_SIMULATION}" = "cac" ]; then cd $TRAVIS_BUILD_DIR; - make check && sudo make install || (cat tests/*log && exit); + make check && sudo make install || (cat tests/*log src/tests/unittests/*log && exit); export LD_LIBRARY_PATH=/usr/local/lib; cd src/tests/p11test/; ./p11test -s 0 -p 12345678 -i & @@ -309,6 +315,10 @@ after_script: git config --global user.name "Travis CI"; .github/push_artifacts.sh "Travis CI build ${TRAVIS_JOB_NUMBER}"; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then + .github/remove_signing_key.sh; + rm -f .github/secrets.tar; + fi before_cache: - brew cleanup @@ -321,5 +331,4 @@ cache: - $HOME/Library/Caches/Homebrew - openssl_bin - openpace_bin - files: - - isetup-5.5.6.exe + - isetup diff --git a/MacOSX/Makefile.am b/MacOSX/Makefile.am index 4d032aee..b0fa2130 100644 --- a/MacOSX/Makefile.am +++ b/MacOSX/Makefile.am @@ -1,5 +1,5 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -EXTRA_DIST = build build-package.in build-package-from-ci.in Distribution.xml.in libtool-bundle opensc-uninstall \ +EXTRA_DIST = build build-package.in Distribution.xml.in libtool-bundle opensc-uninstall \ resources \ resources/background.jpg \ resources/Welcome.html.in \ diff --git a/MacOSX/build-package-from-ci.in b/MacOSX/build-package-from-ci.in deleted file mode 100755 index 24e626bb..00000000 --- a/MacOSX/build-package-from-ci.in +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# temporary build script until we've fixed the CI to include CTK - -# You need to install the following packages from homebrew or macports or fink: -# autoconf automake libtool pkg-config help2man gengetopt - -export MACOSX_DEPLOYMENT_TARGET="10.10" - -set -ex -test -x ./configure || ./bootstrap -BUILDPATH=${PWD} - -# Locate the latest OSX SDK -SDK_PATH=$(xcrun --sdk macosx --show-sdk-path) - -# Set SDK path -export CFLAGS="$CFLAGS -isysroot $SDK_PATH -arch x86_64" - -# Build OpenSCToken -if ! test -e OpenSCToken; then - git clone --depth=1 https://github.com/frankmorgner/OpenSCToken.git -fi -cd OpenSCToken -# make sure OpenSCToken builds with the same dependencies as before -if ! test -e OpenSC; then - git clone --depth=1 ../../OpenSC -else - cd OpenSC && git pull && cd .. -fi -if ! test -e openssl; then - git clone --depth=1 https://github.com/openssl/openssl.git -b OpenSSL_1_0_2-stable -else - cd openssl && git pull && cd .. -fi -if ! test -e openpace; then - git clone --depth=1 https://github.com/frankmorgner/openpace.git -b 1.1.0 -else - cd openpace && git pull && cd .. -fi -BP=${BUILDPATH} -. ./bootstrap -BUILDPATH=${BP} -xcodebuild -target OpenSCTokenApp -configuration Debug -project OpenSCTokenApp.xcodeproj install DSTROOT=${BUILDPATH}/target_token -cd .. - -imagedir=$(mktemp -d) - -# Get name of branch in Nightly which corresponds to the latest commit in OpenSC -BRANCH=`git log --max-count=1 --date=short --abbrev=8 --pretty=format:"%cd_%h"` -if ! test -e Nightly-${BRANCH}; then - # Download the build - curl -L https://github.com/OpenSC/Nightly/archive/${BRANCH}.zip > ${BRANCH}.zip - # Unpack the build - unzip ${BRANCH}.zip -fi -cp Nightly-${BRANCH}/OpenSC-startup.pkg . -cp Nightly-${BRANCH}/OpenSC-tokend.pkg . -cp Nightly-${BRANCH}/OpenSC.pkg . - -# Build package -pkgbuild --root ${BUILDPATH}/target_token --identifier org.opensc-project.mac.opensctoken --version @PACKAGE_VERSION@ --install-location / OpenSCToken.pkg - -# Build product -productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION@.pkg" - -# Build "Uninstaller" -osacompile -o "${imagedir}/OpenSC Uninstaller.app" "MacOSX/OpenSC_Uninstaller.applescript" - -# Create .dmg -rm -f OpenSC-@PACKAGE_VERSION@.dmg -i=0 -while ! hdiutil create -srcfolder "${imagedir}" -volname "@PACKAGE_NAME@" -fs JHFS+ OpenSC-@PACKAGE_VERSION@.dmg -do - i=$[$i+1] - if [ $i -gt 2 ] - then - exit 1 - fi -done -rm -rf ${imagedir} diff --git a/MacOSX/build-package.in b/MacOSX/build-package.in index ad31336e..a5f4e871 100755 --- a/MacOSX/build-package.in +++ b/MacOSX/build-package.in @@ -19,6 +19,13 @@ SDK_PATH=$(xcrun --sdk macosx --show-sdk-path) # Set SDK path export CFLAGS="$CFLAGS -isysroot $SDK_PATH -arch x86_64" +# xcodebuild doesn't read the environment variables +# transform them into parameters +P1="${CODE_SIGN_IDENTITY:+CODE_SIGN_IDENTITY=${CODE_SIGN_IDENTITY}}" +P2="${OTHER_CODE_SIGN_FLAGS:+OTHER_CODE_SIGN_FLAGS=${OTHER_CODE_SIGN_FLAGS}}" +P3="${CODE_SIGN_INJECT_BASE_ENTITLEMENTS:+CODE_SIGN_INJECT_BASE_ENTITLEMENTS=${CODE_SIGN_INJECT_BASE_ENTITLEMENTS}}" +P4="${CODE_SIGN_STYLE:+CODE_SIGN_STYLE=${CODE_SIGN_STYLE}}" + export SED=/usr/bin/sed PREFIX=/Library/OpenSC export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig @@ -28,15 +35,13 @@ if ! pkg-config libcrypto --atleast-version=1.0.1; then if ! test -e $BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig; then # Build OpenSSL manually, because Apple's binaries are deprecated if ! test -e openssl; then - git clone --depth=1 https://github.com/openssl/openssl.git -b OpenSSL_1_0_2-stable + git clone --depth=1 https://github.com/openssl/openssl.git -b OpenSSL_1_1_1-stable fi cd openssl KERNEL_BITS=64 ./config --prefix=$PREFIX make clean - make update - make depend make -j 4 - make INSTALL_PREFIX=$BUILDPATH/openssl_bin install_sw + make DESTDIR=$BUILDPATH/openssl_bin install_sw cd .. fi export OPENSSL_CFLAGS="`env PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openssl_bin pkg-config --static --cflags libcrypto`" @@ -49,7 +54,8 @@ if ! test -e $BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig; then fi cd openpace autoreconf -vis - ./configure --disable-shared --prefix=$PREFIX CRYPTO_CFLAGS="$OPENSSL_CFLAGS" CRYPTO_LIBS="$OPENSSL_LIBS" + ./configure --disable-shared --prefix=$PREFIX CRYPTO_CFLAGS="$OPENSSL_CFLAGS" CRYPTO_LIBS="$OPENSSL_LIBS" HELP2MAN=/usr/bin/true + touch src/cvc-create.1 src/cvc-print.1 make DESTDIR=$BUILDPATH/openpace_bin install cd .. fi @@ -91,13 +97,13 @@ fi if ! test -e NotificationProxy; then git clone http://github.com/frankmorgner/NotificationProxy.git fi -xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/OpenSC/ +xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/OpenSC/ "$P1" "$P2" "$P3" "$P4" mkdir -p "$BUILDPATH/target/Applications" osacompile -o "$BUILDPATH/target/Applications/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript" # Build OpenSC.tokend when XCode version < 10 -if (( xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9]+)\.[0-9]*/\1/p' < 10 )); then +if (( $(xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9]+)(\.[0-9]*)*/\1/p') < 10 )); then # Check out OpenSC.tokend, if not already fetched. if ! test -e OpenSC.tokend; then git clone http://github.com/OpenSC/OpenSC.tokend.git @@ -107,7 +113,7 @@ if (( xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9]+)\.[0-9]*/\1/p' < test -L OpenSC.tokend/build/opensc-src || ln -sf ${BUILDPATH}/src OpenSC.tokend/build/opensc-src # Build and copy OpenSC.tokend - xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj install DSTROOT=${BUILDPATH}/target_tokend + xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj install DSTROOT=${BUILDPATH}/target_tokend "$P1" $P2 "$P3" "$P4" else # https://github.com/OpenSC/OpenSC.tokend/issues/33 mkdir -p ${BUILDPATH}/target_tokend @@ -140,24 +146,25 @@ if test -e OpenSCToken; then cd OpenSCToken # make sure OpenSCToken builds with the same dependencies as before if ! test -e OpenSC; then - git clone --depth=1 ../../OpenSC + git clone --depth=1 file://$PWD/../../OpenSC else cd OpenSC && git pull && cd .. fi - if ! test -e openssl; then - git clone --depth=1 ../openssl - else - cd openssl && git pull && cd .. + mkdir -p build + if ! test -e build/openssl; then + # build/openssl/lib/libcrypto.a is hardcoded in OpenSCToken + ln -sf $BUILDPATH/openssl_bin/$PREFIX build/openssl + # in OpenSCToken's variant of OpenSC we still use OpenSSL flags from above fi - if ! test -e openpace; then - git clone --depth=1 ../openpace - else - cd openpace && git pull && cd .. + if ! test -e build/openpace; then + # build/openpace/lib/libeac.a is hardcoded in OpenSCToken + ln -sf $BUILDPATH/openpace_bin/$PREFIX build/openpace + # in OpenSCToken's variant of OpenSC we still use OpenPACE flags from above fi BP=${BUILDPATH} . ./bootstrap BUILDPATH=${BP} - xcodebuild -target OpenSCTokenApp -configuration Debug -project OpenSCTokenApp.xcodeproj install DSTROOT=${BUILDPATH}/target_token + xcodebuild -target OpenSCTokenApp -configuration Debug -project OpenSCTokenApp.xcodeproj install DSTROOT=${BUILDPATH}/target_token "$P1" "$P2" "$P3" "$P4" cd .. else # if no OpenSCToken is checked out, then we create a dummy package diff --git a/MacOSX/opensc-uninstall b/MacOSX/opensc-uninstall index 6a14cecd..ab1d7f99 100755 --- a/MacOSX/opensc-uninstall +++ b/MacOSX/opensc-uninstall @@ -6,6 +6,8 @@ if [ "$(id -u)" != "0" ]; then exit 1 fi +pluginkit -r -i org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken + for f in \ /Library/OpenSC/bin/* \ /Library/OpenSC/etc/bash_completion.d/* \ diff --git a/MacOSX/scripts/postinstall b/MacOSX/scripts/postinstall index ff11f831..45f21436 100755 --- a/MacOSX/scripts/postinstall +++ b/MacOSX/scripts/postinstall @@ -36,8 +36,12 @@ for f in \ do if [ -e "$f" ] then - /bin/launchctl asuser $(id -u "${USER}") /bin/launchctl load "$f" + /bin/launchctl asuser $(id -u "${USER}") /bin/launchctl load "$f" || true fi done +if [ -e /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex ] + sudo -u _securityagent pluginkit -a /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex +fi + exit 0 diff --git a/appveyor.yml b/appveyor.yml index ec15bb3b..08f22abe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,10 +11,21 @@ configuration: environment: GH_TOKEN: secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY + PATH: C:\cygwin\bin;%PATH% + OPENPACE_VER: 1.1.0 + ZLIB_VER_DOT: 1.2.11 matrix: - - VSVER: 14 - - VSVER: 12 - DO_PUSH_ARTIFACT: yes + # not compatible with OpenSSL 1.1.1: + # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 + # VCVARSALL: "%VS120COMNTOOLS%/../../VC/vcvarsall.bat" + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + VCVARSALL: "%VS140COMNTOOLS%/../../VC/vcvarsall.bat" + DO_PUSH_ARTIFACT: yes + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat" + # not compatible with WiX 3.11.2: + # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + # VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat" install: - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` @@ -22,26 +33,21 @@ install: Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` throw "There are newer queued builds for this pull request, failing early." } - date /T & time /T - - set PATH=C:\cygwin\bin;%PATH% - - set OPENPACE_VER=1.1.0 - - set ZLIB_VER_DOT=1.2.11 - ps: $env:PACKAGE_NAME=(git describe --tags --abbrev=0) - ps: >- If ($env:Platform -Match "x86") { - $env:VCVARS_PLATFORM="x86" $env:OPENSSL_PF="Win32" $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win32" } Else { - $env:VCVARS_PLATFORM="amd64" $env:OPENSSL_PF="Win64" $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win64" } - ps: >- If ($env:Configuration -Like "*Light*") { - $env:ARTIFACT="${env:ARTIFACT}-Light" + $env:ARTIFACT+="-Light" } Else { - $env:NMAKE_EXTRA="OPENSSL_DEF=/DENABLE_OPENSSL ${env:NMAKE_EXTRA}" - $env:NMAKE_EXTRA="OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536 ${env:NMAKE_EXTRA}" + $env:NMAKE_EXTRA+=" OPENSSL_DEF=/DENABLE_OPENSSL OPENSSL_DIR=C:\OpenSSL-v111-${env:OPENSSL_PF}" + $env:NMAKE_EXTRA+=" OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536" If (!(Test-Path C:\zlib )) { appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip 7z x zlib.zip -oC:\ @@ -56,9 +62,8 @@ install: If (!(Test-Path cngsdk.msi )) { appveyor DownloadFile "http://download.microsoft.com/download/2/C/9/2C93059C-0532-42DF-8C24-9AEAFF00768E/cngsdk.msi" } - - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS")) - - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%" - - call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM% + - echo "Using %APPVEYOR_BUILD_WORKER_IMAGE% with %VCVARSALL%" + - call "%VCVARSALL%" %Platform% - cngsdk.msi /quiet - uname -a - set @@ -71,21 +76,23 @@ build_script: xcopy C:\zlib C:\zlib-${env:OPENSSL_PF} /e /i /y /s cd C:\zlib-${env:OPENSSL_PF} (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc - nmake -f win32/Makefile.msc zlib.lib + nmake /nologo -f win32/Makefile.msc zlib.lib } - $env:NMAKE_EXTRA="ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib ${env:NMAKE_EXTRA}" + $env:NMAKE_EXTRA+=" ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib" If (!(Test-Path -Path "C:\openpace-${env:OPENSSL_PF}" )) { # build libeac.lib as a static library xcopy C:\openpace C:\openpace-${env:OPENSSL_PF} /e /i /y /s cd C:\openpace-${env:OPENSSL_PF}\src # OpenSSL 1.1.0 - #cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c + #cl /nologo /IC:\OpenSSL-v110-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c + # OpenSSL 1.1.1 + cl /nologo /IC:\OpenSSL-v111-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /DHAVE_EC_POINT_GET_AFFINE_COORDINATES=1 /DHAVE_EC_POINT_SET_AFFINE_COORDINATES=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c # OpenSSL 1.0.2 - cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c - lib /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj + #cl /nologo /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c + lib /nologo /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj cd C:\projects\OpenSC } - $env:NMAKE_EXTRA="OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF} ${env:NMAKE_EXTRA}" + $env:NMAKE_EXTRA+=" OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF}" } - bash -c "exec 0]]) AC_CHECK_SIZEOF(void *) if test "${ac_cv_sizeof_void_p}" = 8; then LIBRARY_BITNESS="64" @@ -1072,10 +1074,10 @@ AS_IF([test "${enable_shared}" = "yes"], [AC_DEFINE([ENABLE_SHARED], [1], [Enabl if test "${enable_pedantic}" = "yes"; then enable_strict="yes"; - CFLAGS="${CFLAGS} -pedantic" + CFLAGS="-pedantic ${CFLAGS}" fi if test "${enable_strict}" = "yes"; then - CFLAGS="${CFLAGS} -Wall -Wextra -Wno-unused-parameter -Werror" + CFLAGS="-Wall -Wextra -Wno-unused-parameter -Werror ${CFLAGS}" fi AC_CONFIG_FILES([ @@ -1116,7 +1118,6 @@ AC_CONFIG_FILES([ win32/OpenSC.wxs MacOSX/Makefile MacOSX/build-package - MacOSX/build-package-from-ci MacOSX/Distribution.xml MacOSX/resources/Welcome.html ]) diff --git a/doc/tools/dnie-tool.1.xml b/doc/tools/dnie-tool.1.xml index 0daac27d..6467a68f 100644 --- a/doc/tools/dnie-tool.1.xml +++ b/doc/tools/dnie-tool.1.xml @@ -75,11 +75,23 @@ pin, pin - Specify the user pin pin to use. - If set to env:VARIABLE, the - value of the environment variable - VARIABLE is used. - The default is do not enter pin + + + These options can be used to specify the PIN value + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + + diff --git a/doc/tools/gids-tool.1.xml b/doc/tools/gids-tool.1.xml index a7d4f8be..9bad4d5c 100644 --- a/doc/tools/gids-tool.1.xml +++ b/doc/tools/gids-tool.1.xml @@ -46,9 +46,25 @@ - argument + pin - Define user PIN. + + + This option can be used to specify the PIN value + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + + diff --git a/doc/tools/goid-tool.1.xml b/doc/tools/goid-tool.1.xml new file mode 100644 index 00000000..53e23140 --- /dev/null +++ b/doc/tools/goid-tool.1.xml @@ -0,0 +1,126 @@ + + + + goid-tool + 1 + OpenSC + OpenSC Tools + opensc + + + + goid-tool + ??? + + + + + goid-tool + OPTIONS + mode + + + + + Description + + The goid-tool utility can be used from + the command line to ??? + + + + + Options + + + + + , + + + Print help message on screen. + + + + , + + + Print the OpenSC package release version. + + + + string, + string + + + Specify the number of the reader to use. By default, the + first reader with present card is used. If + the arguement is an ATR, the reader with a + matching card will be chosen. + + + + + , + + + + Cause goid-tool to be + more verbose. Use it multiple times to be even more + verbose. + + + + + , + + + + Verify PIN. + + + + + , + + + + Verify finger print. + + + + + + + + Verify PIN or finger print (user's choice). + + + + + + + + See also + + + pkcs11-tool + 1 + + + opensc.conf + 5 + + + + + + Authors + pkcs11-register was written by + Frank Morgner frankmorgner@gmail.com. + + + + + + diff --git a/doc/tools/openpgp-tool.1.xml b/doc/tools/openpgp-tool.1.xml index 5f46be29..cc513131 100644 --- a/doc/tools/openpgp-tool.1.xml +++ b/doc/tools/openpgp-tool.1.xml @@ -149,14 +149,25 @@ - string + pin - - The PIN text to verify. If set to - env:VARIABLE, the value of - the environment variable - VARIABLE is used. - + + + This option can be used to specify the PIN value + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + + diff --git a/doc/tools/opensc-tool.1.xml b/doc/tools/opensc-tool.1.xml index ea2c235a..43acf612 100644 --- a/doc/tools/opensc-tool.1.xml +++ b/doc/tools/opensc-tool.1.xml @@ -35,7 +35,7 @@ - , + Print the OpenSC package release version. diff --git a/doc/tools/pkcs11-register.1.xml b/doc/tools/pkcs11-register.1.xml new file mode 100644 index 00000000..a3da7546 --- /dev/null +++ b/doc/tools/pkcs11-register.1.xml @@ -0,0 +1,124 @@ + + + + pkcs11-register + 1 + OpenSC + OpenSC Tools + opensc + + + + pkcs11-register + Simple tool to install PKCS#11 modules to known applications. + + + + + pkcs11-register + OPTIONS + + + + + Description + + The pkcs11-register utility can be used from + the command line to register PKCS#11 modules to various applications + + + + + Options + + + + + , + + + Print help message on screen. + + + + , + + + Print the OpenSC package release version. + + + + filename, + filename + + + Path to the PKCS#11 module to load. The default + is OpenSC PKCS#11 module. + + + + + + + + Don't install module for Chrome browser. By default, + the tool attempts to install the module for Chrome + browser. + + + + + + + + Don't install module for Firefox browser. By default, + the tool attempts to install the module for Firefox + browser. + + + + + + + + Don't install module for Thunderbird mail client. + By default, the tool attempts to install the module + for Thunderbird mail client. + + + + + + + + Don't install module for Seamonkey. By default, + the tool attempts to install the module Seamonkey. + + + + + + + + See also + + + pkcs11-tool + 1 + + + opensc.conf + 5 + + + + + + Authors + pkcs11-register was written by + Frank Morgner frankmorgner@gmail.com. + + + + + diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml index 32b04114..a433c66d 100644 --- a/doc/tools/pkcs11-tool.1.xml +++ b/doc/tools/pkcs11-tool.1.xml @@ -170,6 +170,13 @@ Specify 'derive' key usage flag (EC only). + + + + + Specify 'wrap' key usage flag. + + name, diff --git a/doc/tools/pkcs15-init.1.xml b/doc/tools/pkcs15-init.1.xml index bed58f43..e7c87383 100644 --- a/doc/tools/pkcs15-init.1.xml +++ b/doc/tools/pkcs15-init.1.xml @@ -348,46 +348,26 @@ - filename + pin, + puk, + sopin, + sopuk - Tells pkcs15-init to read additional options - from filename. The file is supposed to - contain one long option per line, without the leading dashes, - for instance: - -pin 1234 -puk 87654321 - + These options can be used to specify the PIN/PUK values + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. - You can specify several times. - - - - - - - , - - , - , - - - - These options can be used to specify PIN/PUK values - on the command line. If set to - env:VARIABLE, the value - of the environment variable - VARIABLE is used. Note - that on most operation systems, any user can + Note that on most operation systems, any user can display the command line of any process on the system using utilities such as - ps(1). Therefore, you should use - these options only on a secured system, or in an - options file specified with - . + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. diff --git a/doc/tools/pkcs15-tool.1.xml b/doc/tools/pkcs15-tool.1.xml index 02b3b03b..45bbb077 100644 --- a/doc/tools/pkcs15-tool.1.xml +++ b/doc/tools/pkcs15-tool.1.xml @@ -310,16 +310,27 @@ - PIN + pin, + newpin + puk - Specify PIN - - - - - PUK - - Specify Unblock PIN + + + These options can be used to specify the PIN/PUK values + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + + diff --git a/doc/tools/sc-hsm-tool.1.xml b/doc/tools/sc-hsm-tool.1.xml index ced876ae..3f63eda6 100644 --- a/doc/tools/sc-hsm-tool.1.xml +++ b/doc/tools/sc-hsm-tool.1.xml @@ -120,26 +120,25 @@ - value + pin, + sopin, - Define SO-PIN for initialization. If set to - env:VARIABLE, the value of - the environment variable - VARIABLE is used. - - - - - - value - - - Define user PIN for initialization, wrap or - unwrap operation. If set to - env:VARIABLE, the value of - the environment variable - VARIABLE is used. + + These options can be used to specify the PIN values + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + diff --git a/doc/tools/westcos-tool.1.xml b/doc/tools/westcos-tool.1.xml index 3034f2e8..9950ecf2 100644 --- a/doc/tools/westcos-tool.1.xml +++ b/doc/tools/westcos-tool.1.xml @@ -115,25 +115,28 @@ - value, - value + pin, + pin + puk, + puk - Set value of PIN. If set to - env:VARIABLE, the value of - the environment variable - VARIABLE is used. - - - - - value, - value - - set value of PUK (or value of new PIN for change PIN - command see ). If set to - env:VARIABLE, the value of - the environment variable - VARIABLE is used. + + + These options can be used to specify the PIN/PUK values + on the command line. If the value is set to + env:VARIABLE, the value + of the specified environment variable is used. By default, + the code is prompted on the command line if needed. + + + Note that on most operation systems, any user can + display the command line of any process on the + system using utilities such as + ps(1). Therefore, you should prefer + passing the codes via an environment variable + on an unsecured system. + + diff --git a/src/common/compat_strlcat.c b/src/common/compat_strlcat.c index af373f11..fa51cd29 100644 --- a/src/common/compat_strlcat.c +++ b/src/common/compat_strlcat.c @@ -31,7 +31,7 @@ #include "config.h" #endif -#ifndef HAVE_STRLCAT +#if !defined(HAVE_DECL_STRLCAT) || !HAVE_DECL_STRLCAT #include #include diff --git a/src/common/compat_strlcat.h b/src/common/compat_strlcat.h index f0284aca..9debdfad 100644 --- a/src/common/compat_strlcat.h +++ b/src/common/compat_strlcat.h @@ -10,9 +10,11 @@ #include "config.h" #endif -#ifndef HAVE_STRLCAT +#if !defined(HAVE_DECL_STRLCAT) || !HAVE_DECL_STRLCAT #include size_t strlcat(char *dst, const char *src, size_t siz); +#else +#include #endif #endif diff --git a/src/common/compat_strlcpy.c b/src/common/compat_strlcpy.c index 88f3a5fb..c8505707 100644 --- a/src/common/compat_strlcpy.c +++ b/src/common/compat_strlcpy.c @@ -20,7 +20,7 @@ #include "config.h" #endif -#ifndef HAVE_STRLCPY /* empty file if strlcpy is available */ +#if !defined(HAVE_DECL_STRLCPY) || !HAVE_DECL_STRLCPY #include #include diff --git a/src/common/compat_strlcpy.h b/src/common/compat_strlcpy.h index 5a6067fb..9da1604e 100644 --- a/src/common/compat_strlcpy.h +++ b/src/common/compat_strlcpy.h @@ -38,9 +38,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "config.h" #endif -#ifndef HAVE_STRLCPY +#if !defined(HAVE_DECL_STRLCPY) || !HAVE_DECL_STRLCPY #include size_t strlcpy(char *dst, const char *src, size_t siz); +#else +#include #endif #endif diff --git a/src/common/libpkcs11.c b/src/common/libpkcs11.c index 9f99b8af..337bb5b1 100644 --- a/src/common/libpkcs11.c +++ b/src/common/libpkcs11.c @@ -100,7 +100,6 @@ C_UnloadModule(void *module) if (mod->handle != NULL && sc_dlclose(mod->handle) < 0) return CKR_FUNCTION_FAILED; - memset(mod, 0, sizeof(*mod)); free(mod); return CKR_OK; } diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 49d12268..44e74db6 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -12,7 +12,8 @@ noinst_HEADERS = cards.h ctbcs.h internal.h muscle.h muscle-filesystem.h \ errors.h types.h compression.h itacns.h iso7816.h \ authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \ pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h \ - jpki.h sc-ossl-compat.h card-npa.h ccid-types.h reader-tr03119.h \ + jpki.h sc-ossl-compat.h card-npa.h card-openpgp.h \ + ccid-types.h reader-tr03119.h \ card-cac-common.h AM_CPPFLAGS = -D'OPENSC_CONF_PATH="$(sysconfdir)/opensc.conf"' \ @@ -48,14 +49,14 @@ libopensc_la_SOURCES_BASE = \ card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \ card-dnie.c cwa14890.c cwa-dnie.c \ card-isoApplet.c card-masktech.c card-gids.c card-jpki.c \ - card-npa.c card-esteid2018.c \ + card-npa.c card-esteid2018.c card-idprime.c \ \ - pkcs15-openpgp.c pkcs15-starcert.c \ + pkcs15-openpgp.c pkcs15-starcert.c pkcs15-cardos.c \ pkcs15-tcos.c pkcs15-esteid.c pkcs15-gemsafeGPK.c \ pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \ pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \ pkcs15-oberthur.c pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \ - pkcs15-coolkey.c pkcs15-din-66291.c \ + pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \ pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \ compression.c p15card-helper.c sm.c \ aux-data.c @@ -64,10 +65,9 @@ if ENABLE_CRYPTOTOKENKIT # most platforms don't support objective C the way we needed. # Only include it if needed libopensc_la_SOURCES_BASE += reader-cryptotokenkit.m -else +endif libopensc_la_LIBTOOLFLAGS = --tag CC libopensc_static_la_LIBTOOLFLAGS = --tag CC -endif libopensc_la_SOURCES = $(libopensc_la_SOURCES_BASE) \ libopensc.exports @@ -131,14 +131,14 @@ TIDY_FILES = \ card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \ cwa14890.c cwa-dnie.c \ card-isoApplet.c card-masktech.c card-jpki.c \ - card-npa.c card-esteid2018.c \ + card-npa.c card-esteid2018.c card-idprime.c \ \ - pkcs15-openpgp.c \ + pkcs15-openpgp.c pkcs15-cardos.c \ pkcs15-tcos.c pkcs15-esteid.c \ pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c \ pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \ pkcs15-oberthur.c pkcs15-itacns.c pkcs15-sc-hsm.c \ - pkcs15-coolkey.c pkcs15-din-66291.c \ + pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \ pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \ compression.c p15card-helper.c sm.c \ aux-data.c \ diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 487fbeb4..1b0ff45c 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -27,15 +27,15 @@ OBJECTS = \ card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj cwa-dnie.obj cwa14890.obj \ card-sc-hsm.obj card-dnie.obj card-isoApplet.obj pkcs15-coolkey.obj \ card-masktech.obj card-gids.obj card-jpki.obj \ - card-npa.obj card-esteid2018.obj \ + card-npa.obj card-esteid2018.obj card-idprime.obj \ \ - pkcs15-openpgp.obj pkcs15-starcert.obj \ + pkcs15-openpgp.obj pkcs15-starcert.obj pkcs15-cardos.obj \ pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-gemsafeGPK.obj \ pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \ pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \ pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \ pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \ - pkcs15-esteid2018.obj \ + pkcs15-esteid2018.obj pkcs15-idprime.obj \ compression.obj p15card-helper.obj sm.obj \ aux-data.obj \ $(TOPDIR)\win32\versioninfo.res diff --git a/src/libopensc/asn1.c b/src/libopensc/asn1.c index 61da5601..e19a8d32 100644 --- a/src/libopensc/asn1.c +++ b/src/libopensc/asn1.c @@ -961,6 +961,9 @@ static int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen, return 0; } +/* + * This assumes the tag is already encoded + */ 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; @@ -1506,7 +1509,7 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry, case SC_ASN1_INTEGER: case SC_ASN1_ENUMERATED: if (parm != NULL) { - r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm, 1); + r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm, 0); sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s' returned %d\n", depth, depth, "", entry->name, *((int *) entry->parm)); } @@ -2154,8 +2157,10 @@ sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, const unsigned char *in } memset(buf, 0, buflen); - memcpy(buf + (halflen - r_len), r, r_len); - memcpy(buf + (buflen - s_len), s, s_len); + if (r_len > 0) + memcpy(buf + (halflen - r_len), r, r_len); + if (s_len > 0) + memcpy(buf + (buflen - s_len), s, s_len); sc_log(ctx, "r(%"SC_FORMAT_LEN_SIZE_T"u): %s", halflen, sc_dump_hex(buf, halflen)); diff --git a/src/libopensc/card-atrust-acos.c b/src/libopensc/card-atrust-acos.c index 83da3923..86bbf7ab 100644 --- a/src/libopensc/card-atrust-acos.c +++ b/src/libopensc/card-atrust-acos.c @@ -123,7 +123,7 @@ static int atrust_acos_init(struct sc_card *card) | SC_ALGORITHM_RSA_HASH_RIPEMD160 | SC_ALGORITHM_RSA_HASH_MD5_SHA1; - if (!strcmp(card->name, ACOS_EMV_A05)) + if (card->name != NULL && !strcmp(card->name, ACOS_EMV_A05)) flags |= SC_ALGORITHM_RSA_HASH_SHA256; _sc_card_add_rsa_alg(card, 1536, flags, 0x10001); diff --git a/src/libopensc/card-cac.c b/src/libopensc/card-cac.c index a7bc43d2..29280030 100644 --- a/src/libopensc/card-cac.c +++ b/src/libopensc/card-cac.c @@ -54,6 +54,7 @@ #endif #include "iso7816.h" #include "card-cac-common.h" +#include "pkcs15.h" /* * CAC hardware and APDU constants @@ -105,6 +106,8 @@ #define CAC_ACR_AMP 0x20 #define CAC_ACR_SERVICE 0x21 +#define CAC_MAX_CCC_DEPTH 16 + /* hardware data structures (returned in the CCC) */ /* part of the card_url */ typedef struct cac_access_profile { @@ -1081,10 +1084,8 @@ static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc * We only need to do this for private keys. */ if ((pathlen > 2) && (pathlen <= 4) && memcmp(path, "\x3F\x00", 2) == 0) { - if (pathlen > 2) { - path += 2; - pathlen -= 2; - } + path += 2; + pathlen -= 2; } @@ -1410,10 +1411,10 @@ static int cac_parse_cuid(sc_card_t *card, cac_private_data_t *priv, cac_cuid_t priv->cac_id_len = card_id_len; return SC_SUCCESS; } -static int cac_process_CCC(sc_card_t *card, cac_private_data_t *priv); +static int cac_process_CCC(sc_card_t *card, cac_private_data_t *priv, int depth); static int cac_parse_CCC(sc_card_t *card, cac_private_data_t *priv, const u8 *tl, - size_t tl_len, u8 *val, size_t val_len) + size_t tl_len, u8 *val, size_t val_len, int depth) { size_t len = 0; const u8 *tl_end = tl + tl_len; @@ -1510,7 +1511,8 @@ static int cac_parse_CCC(sc_card_t *card, cac_private_data_t *priv, const u8 *tl if (r < 0) return r; - r = cac_process_CCC(card, priv); + /* Increase depth to avoid infinite recursion */ + r = cac_process_CCC(card, priv, depth + 1); if (r < 0) return r; break; @@ -1523,12 +1525,16 @@ static int cac_parse_CCC(sc_card_t *card, cac_private_data_t *priv, const u8 *tl return SC_SUCCESS; } -static int cac_process_CCC(sc_card_t *card, cac_private_data_t *priv) +static int cac_process_CCC(sc_card_t *card, cac_private_data_t *priv, int depth) { u8 *tl = NULL, *val = NULL; size_t tl_len, val_len; int r; + if (depth > CAC_MAX_CCC_DEPTH) { + sc_log(card->ctx, "Too much recursive CCC found. Exiting"); + return SC_ERROR_INVALID_CARD; + } r = cac_read_file(card, CAC_FILE_TAG, &tl, &tl_len); if (r < 0) @@ -1538,7 +1544,7 @@ static int cac_process_CCC(sc_card_t *card, cac_private_data_t *priv) if (r < 0) goto done; - r = cac_parse_CCC(card, priv, tl, tl_len, val, val_len); + r = cac_parse_CCC(card, priv, tl, tl_len, val, val_len, depth); done: if (tl) free(tl); @@ -1765,7 +1771,7 @@ static int cac_find_and_initialize(sc_card_t *card, int initialize) priv = cac_new_private_data(); if (!priv) return SC_ERROR_OUT_OF_MEMORY; - r = cac_process_CCC(card, priv); + r = cac_process_CCC(card, priv, 0); if (r == SC_SUCCESS) { card->type = SC_CARD_TYPE_CAC_II; card->drv_data = priv; diff --git a/src/libopensc/card-cac1.c b/src/libopensc/card-cac1.c index a0c98bad..50c0928f 100644 --- a/src/libopensc/card-cac1.c +++ b/src/libopensc/card-cac1.c @@ -54,6 +54,7 @@ #endif #include "iso7816.h" #include "card-cac-common.h" +#include "pkcs15.h" /* * CAC hardware and APDU constants diff --git a/src/libopensc/card-cardos.c b/src/libopensc/card-cardos.c index f55cadcb..4ef6ead0 100644 --- a/src/libopensc/card-cardos.c +++ b/src/libopensc/card-cardos.c @@ -53,13 +53,42 @@ static const struct sc_atr_table cardos_atrs[] = { /* CardOS v5.0 */ { "3b:d2:18:00:81:31:fe:58:c9:01:14", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, /* CardOS v5.3 */ - { "3b:d2:18:00:81:31:fe:58:c9:02:17", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, - { "3b:d2:18:00:81:31:fe:58:c9:03:16", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, + { "3b:d2:18:00:81:31:fe:58:c9:02:17", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_3, 0, NULL}, + { "3b:d2:18:00:81:31:fe:58:c9:03:16", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_3, 0, NULL}, { NULL, NULL, NULL, 0, 0, NULL } }; -static unsigned int algorithm_ids_in_tokeninfo[SC_MAX_SUPPORTED_ALGORITHMS]; -static unsigned int algorithm_ids_in_tokeninfo_count=0; +/* private data for cardos driver */ +typedef struct cardos_data { + /* constructed internally */ + unsigned int algorithm_ids_in_tokeninfo[SC_MAX_SUPPORTED_ALGORITHMS]; + unsigned int algorithm_ids_in_tokeninfo_count; + unsigned long flags; /* flags used by init to create sc_algorithms */ + unsigned long ec_flags; + unsigned long ext_flags; + int rsa_2048; + const sc_security_env_t * sec_env; +} cardos_data_t; + +/* copied from iso7816.c */ +static void fixup_transceive_length(const struct sc_card *card, + struct sc_apdu *apdu) +{ + if (card == NULL || apdu == NULL) { + return; + } + + if (apdu->lc > sc_get_max_send_size(card)) { + /* The lower layers will automatically do chaining */ + apdu->flags |= SC_APDU_FLAGS_CHAINING; + } + + if (apdu->le > sc_get_max_recv_size(card)) { + /* The lower layers will automatically do a GET RESPONSE, if possible. + * All other workarounds must be carried out by the upper layers. */ + apdu->le = sc_get_max_recv_size(card); + } +} static int cardos_match_card(sc_card_t *card) { @@ -79,6 +108,8 @@ static int cardos_match_card(sc_card_t *card) return 1; if (card->type == SC_CARD_TYPE_CARDOS_V5_0) return 1; + if (card->type == SC_CARD_TYPE_CARDOS_V5_3) + return 1; if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { int rv; sc_apdu_t apdu; @@ -159,42 +190,102 @@ static int cardos_have_2048bit_package(sc_card_t *card) return 0; } + +/* Called from cardos_init for old cards, from cardos_cardctl_parsed_token_info for new cards */ +/* TODO see if works from old cards too */ +static int cardos_add_algs(sc_card_t *card, unsigned long flags, unsigned long ec_flags, unsigned long ext_flags) +{ + + cardos_data_t * priv = (cardos_data_t *)card->drv_data; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + _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); + if (priv->rsa_2048 == 1) { + _sc_card_add_rsa_alg(card, 1280, flags, 0); + _sc_card_add_rsa_alg(card, 1536, flags, 0); + _sc_card_add_rsa_alg(card, 1792, flags, 0); + _sc_card_add_rsa_alg(card, 2048, flags, 0); + } + + if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + /* Starting with CardOS 5, the card supports PIN query commands */ + card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; + _sc_card_add_rsa_alg(card, 3072, flags, 0); + _sc_card_add_rsa_alg(card, 4096, flags, 0); + } + + /* TODO need to get sizes from supported_algos too */ + if (ec_flags != 0) { + _sc_card_add_ec_alg(card, 256, ec_flags, priv->ext_flags, NULL); + _sc_card_add_ec_alg(card, 384, ec_flags, priv->ext_flags, NULL); + } + + return 0; +} + static int cardos_init(sc_card_t *card) { - unsigned long flags = 0, rsa_2048 = 0; + cardos_data_t * priv = NULL; + unsigned long flags = 0; size_t data_field_length; sc_apdu_t apdu; u8 rbuf[2]; int r; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + priv = calloc(1, sizeof(cardos_data_t)); + if (!priv) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + card->drv_data = priv; + card->name = "Atos CardOS"; card->cla = 0x00; - /* Set up algorithm info. */ - flags = 0; - if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { - flags |= SC_ALGORITHM_RSA_PAD_PKCS1; + /* let user override flags and type from opensc.conf */ + /* user can override card->type too.*/ + if (card->flags) { + flags = card->flags; } else { - flags |= SC_ALGORITHM_RSA_RAW - | SC_ALGORITHM_RSA_HASH_NONE - | SC_ALGORITHM_NEED_USAGE - | SC_ALGORITHM_ONBOARD_KEY_GEN; + + /* Set up algorithm info. */ + flags = 0; + if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { + flags |= SC_ALGORITHM_RSA_PAD_PKCS1; + } else if(card->type == SC_CARD_TYPE_CARDOS_V5_3) { + flags |= SC_ALGORITHM_RSA_RAW + | SC_ALGORITHM_RSA_HASH_NONE + | SC_ALGORITHM_ONBOARD_KEY_GEN; + } else { + flags |= SC_ALGORITHM_RSA_RAW + | SC_ALGORITHM_RSA_HASH_NONE + | SC_ALGORITHM_NEED_USAGE + | SC_ALGORITHM_ONBOARD_KEY_GEN; + } } + priv->flags = flags; + if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { r = cardos_have_2048bit_package(card); if (r < 0) return SC_ERROR_INVALID_CARD; if (r == 1) - rsa_2048 = 1; + priv->rsa_2048 = 1; card->caps |= SC_CARD_CAP_APDU_EXT; - } else if (card->type == SC_CARD_TYPE_CARDOS_M4_3 + } else if (card->type == SC_CARD_TYPE_CARDOS_M4_3 || card->type == SC_CARD_TYPE_CARDOS_M4_2B || card->type == SC_CARD_TYPE_CARDOS_M4_2C || card->type == SC_CARD_TYPE_CARDOS_M4_4 - || card->type == SC_CARD_TYPE_CARDOS_V5_0) { - rsa_2048 = 1; + || card->type == SC_CARD_TYPE_CARDOS_V5_0 + || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + priv->rsa_2048 = 1; card->caps |= SC_CARD_CAP_APDU_EXT; + /* TODO check this. EC only if in supported_algo */ + priv->ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; } /* probe DATA FIELD LENGTH with GET DATA */ @@ -202,6 +293,7 @@ static int cardos_init(sc_card_t *card) apdu.le = sizeof rbuf; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); + r = sc_transmit_apdu(card, &apdu); if (r < 0) LOG_TEST_RET(card->ctx, @@ -216,34 +308,99 @@ static int cardos_init(sc_card_t *card) return SC_ERROR_INVALID_CARD; 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; + /* TODO is this really needed? strip the length of possible Lc and Le bytes */ - _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); - if (rsa_2048 == 1) { - _sc_card_add_rsa_alg(card, 1280, flags, 0); - _sc_card_add_rsa_alg(card, 1536, flags, 0); - _sc_card_add_rsa_alg(card, 1792, flags, 0); - _sc_card_add_rsa_alg(card, 2048, flags, 0); + /* Use Min card sizes and reader too. for V5_3 at least*/ + + if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "data_field_length:%"SC_FORMAT_LEN_SIZE_T"u " + "card->reader->max_send_size:%"SC_FORMAT_LEN_SIZE_T"u " + "card->reader->max_recv_size:%"SC_FORMAT_LEN_SIZE_T"u %s", + data_field_length, card->reader->max_send_size, card->reader->max_recv_size, + (card->caps & SC_CARD_CAP_APDU_EXT) ? "SC_CARD_CAP_APDU_EXT" : " "); + + if (card->caps & SC_CARD_CAP_APDU_EXT) { + card->max_send_size = data_field_length - 6; +#ifdef _WIN32 + /* Windows does not support PCSC PART_10 and may have forced reader to 255/256 + * https://github.com/OpenSC/OpenSC/commit/eddea6f3c2d3dafc2c09eba6695c745a61b5186f + * may have reset this. if so, will override and force extended + * Most, if not all, cardos cards do extended, but not chaining + */ + if (card->reader->max_send_size == 255 && card->reader->max_recv_size == 256) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "reseting reader to use data_field_length"); + card->reader->max_send_size = data_field_length - 6; + card->reader->max_recv_size = data_field_length - 3; + } +#endif + } else + card->max_send_size = data_field_length - 3; + + card->max_send_size = sc_get_max_send_size(card); /* include reader sizes and protocol */ + card->max_recv_size = data_field_length - 2; + card->max_recv_size = sc_get_max_recv_size(card); + } else { + /* old way, disregards reader capabilities */ + 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 (card->type == SC_CARD_TYPE_CARDOS_V5_0) { - /* Starting with CardOS 5, the card supports PIN query commands */ - card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; - _sc_card_add_rsa_alg(card, 3072, flags, 0); - _sc_card_add_rsa_alg(card, 4096, flags, 0); + /*for new cards, wait till after sc_pkcs15_bind_internal reads tokeninfo */ + if (card->type != SC_CARD_TYPE_CARDOS_V5_0 && card->type != SC_CARD_TYPE_CARDOS_V5_3) { + r = cardos_add_algs(card, flags, 0, 0); } return 0; } +static int cardos_pass_algo_flags(sc_card_t *card, struct sc_cardctl_cardos_pass_algo_flags * ptr) +{ + cardos_data_t * priv = (cardos_data_t *)card->drv_data; + int r = 0; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + switch (ptr->pass) { + case 1: + ptr->card_flags = card->flags; + ptr->used_flags = priv->flags; + ptr->ec_flags = priv->ec_flags; + ptr->ext_flags = priv->ext_flags; + break; + case 2: + r = cardos_add_algs(card,ptr->new_flags, ptr->ec_flags, ptr->ext_flags); + break; + default: + sc_log(card->ctx, "ptr->pass: %ul invalid", ptr->pass); + r = SC_ERROR_INTERNAL; + } + LOG_FUNC_RETURN(card->ctx, r); +} + + +static int cardos_finish(sc_card_t *card) +{ + int r = 0; + + if (card) + return 0; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* free priv data */ + if (card->drv_data) { /* priv */ + free(card->drv_data); + card->drv_data = NULL; + } + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); +} + + + static const struct sc_card_error cardos_errors[] = { /* some error inside the card */ /* i.e. nothing you can do */ @@ -381,8 +538,7 @@ get_next_part: q = sc_asn1_find_tag(card->ctx, p, tlen, 0x8a, &ilen); if (q != NULL && ilen == 1) { offset = (u8)ilen; - if (offset != 0) - goto get_next_part; + goto get_next_part; } len -= tlen + 2; p += tlen; @@ -773,8 +929,9 @@ cardos_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) { + cardos_data_t* priv = (cardos_data_t*)card->drv_data; sc_apdu_t apdu; - u8 data[6]; + u8 data[9]; int key_id, r; assert(card != NULL && env != NULL); @@ -783,6 +940,15 @@ cardos_set_security_env(sc_card_t *card, sc_log(card->ctx, "No or invalid key reference\n"); return SC_ERROR_INVALID_ARGUMENTS; } + priv->sec_env = env; /* pass on to crypto routines */ + + /* key_ref includes card mechanism and key number + * But newer cards appear to get this some other way, + * We can use flags passed to know what OpenSC expects from the card + * and have derived what these machanisums are. + * Newer cards may change how this is done + */ + key_id = env->key_ref[0]; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0); @@ -803,16 +969,39 @@ cardos_set_security_env(sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; } - if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { + if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + /* some cards appear to have key_id be both Cryptographic mechanism reference 4 bits + * and key_ref 4 bits. But this limits card to 16 keys. + * TODO may need to be looked at at a later time + */ /* Private key reference */ data[0] = 0x84; data[1] = 0x01; - data[2] = key_id; + data[2] = key_id & 0x0F; /* Usage qualifier byte */ data[3] = 0x95; data[4] = 0x01; data[5] = 0x40; apdu.lc = apdu.datalen = 6; + if (key_id & 0xF0) { + /* Cryptographic mechanism reference */ + data[6] = 0x80; + data[7] = 0x01; + data[8] = key_id & 0xF0; + apdu.lc = apdu.datalen = 9; + } else if (priv->sec_env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { + /* TODO this may only apply to c903 cards */ + /* TODO or only for cards without any supported_algos or EIDComplient only */ + data[6] = 0x80; + data[7] = 0x01; + data[8] = 0x10; + apdu.lc = apdu.datalen = 9; + } else if (priv->sec_env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW) { + data[6] = 0x80; + data[7] = 0x01; + data[8] = 0x30; + apdu.lc = apdu.datalen = 9; + } } else { data[0] = 0x83; data[1] = 0x01; @@ -840,12 +1029,12 @@ cardos_set_security_env(sc_card_t *card, sc_log(card->ctx, "is signature"); sc_log(card->ctx, "Adding ID %d at index %d", algorithm_id, algorithm_id_count); - algorithm_ids_in_tokeninfo[algorithm_id_count++] = algorithm_id; + priv->algorithm_ids_in_tokeninfo[algorithm_id_count++] = algorithm_id; } sc_log(card->ctx, "reference=%d, mechanism=%d, operations=%d, algo_ref=%d", alg.reference, alg.mechanism, alg.operations, alg.algo_ref); } - algorithm_ids_in_tokeninfo_count = algorithm_id_count; + priv -> algorithm_ids_in_tokeninfo_count = algorithm_id_count; } while (0); LOG_FUNC_RETURN(card->ctx, r); @@ -860,6 +1049,7 @@ static int do_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, u8 *out, size_t outlen) { + /* cardos_data_t* priv = (cardos_data_t*)card->drv_dataa */; int r; sc_apdu_t apdu; @@ -874,6 +1064,7 @@ do_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, apdu.data = data; apdu.lc = datalen; apdu.datalen = datalen; + fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); @@ -887,6 +1078,7 @@ static int cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, u8 *out, size_t outlen) { + cardos_data_t* priv; int r; sc_context_t *ctx; int do_rsa_pure_sig = 0; @@ -896,8 +1088,21 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, assert(card != NULL && data != NULL && out != NULL); ctx = card->ctx; + priv = (cardos_data_t*)card->drv_data; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); + /* sec_env has algorithm_flags set from sc_get_encoding_flags sec_flags + * If flags are set correctly we don't need to test anything + * TODO this assumes RSA is PSS, PKCS1 or RAW and we are passing + * the correct data. Should work for ECDSA too. + * use for V5 cards and TODO should for older cards too + */ + if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + + r = do_compute_signature(card, data, datalen, out, outlen); + LOG_FUNC_RETURN(ctx, r); + } + /* There are two ways to create a signature, depending on the way, * the key was created: RSA_SIG and RSA_PURE_SIG. * We can use the following reasoning, to determine the correct operation: @@ -914,8 +1119,8 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, */ /* check the the algorithmIDs from the AlgorithmInfo */ - for (i = 0; i < algorithm_ids_in_tokeninfo_count; ++i) { - unsigned int id = algorithm_ids_in_tokeninfo[i]; + for (i = 0; i < priv->algorithm_ids_in_tokeninfo_count; ++i) { + unsigned int id = priv->algorithm_ids_in_tokeninfo[i]; if (id == 0x86 || id == 0x88) { do_rsa_sig = 1; } else if (id == 0x8C || id == 0x8A) { @@ -986,10 +1191,41 @@ cardos_decipher(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) { + cardos_data_t* priv = (cardos_data_t*)card->drv_data; int r; size_t card_max_send_size = card->max_send_size; size_t reader_max_send_size = card->reader->max_send_size; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* 5.3 supports command chaining. Others may also + * card_max_send_size for 5.3 is already based on reader max_send_size */ + + if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + + r = iso_ops->decipher(card, crgram, crgram_len, out, outlen); + /* + * 5.3 supports RAW as well as PKCS1 and PSS + * decription may strip padding if card supports it + * with cards that support RAW, it always appears to + * drop first 00 that is start of padding. + */ + + if (r > 0 && priv->sec_env->algorithm_flags & SC_ALGORITHM_RSA_RAW) { + size_t rsize = r; + /* RSA RAW crgram_len == modlen */ + /* removed padding is always > 1 byte */ + /* add back missing leading zero if card dropped it */ + if (rsize == crgram_len - 1 && rsize < outlen) { + memmove(out+1, out, rsize); + out[0] =0x00; + r++; + } + } + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); + } + if (sc_get_max_send_size(card) < crgram_len + 1) { /* CardOS doesn't support chaining for PSO:DEC, so we just _hope_ * that both, the reader and the card are able to send enough data. @@ -1004,7 +1240,7 @@ cardos_decipher(struct sc_card *card, card->max_send_size = card_max_send_size; card->reader->max_send_size = reader_max_send_size; - return r; + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } static int @@ -1189,7 +1425,7 @@ static int cardos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return SC_ERROR_INTERNAL; - if ((apdu.resplen == 8) && (card->type == SC_CARD_TYPE_CARDOS_V5_0)) { + if ((apdu.resplen == 8) && (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3)) { /* cache serial number */ memcpy(card->serialnr.value, rbuf, 8); card->serialnr.len = 8; @@ -1224,6 +1460,9 @@ cardos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) case SC_CARDCTL_CARDOS_GENERATE_KEY: return cardos_generate_key(card, (struct sc_cardctl_cardos_genkey_info *) ptr); + case SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS: + return cardos_pass_algo_flags(card, + (struct sc_cardctl_cardos_pass_algo_flags *) ptr); case SC_CARDCTL_LIFECYCLE_GET: return cardos_lifecycle_get(card, (int *) ptr); case SC_CARDCTL_LIFECYCLE_SET: @@ -1280,7 +1519,8 @@ cardos_logout(sc_card_t *card) || card->type == SC_CARD_TYPE_CARDOS_M4_2C || card->type == SC_CARD_TYPE_CARDOS_M4_3 || card->type == SC_CARD_TYPE_CARDOS_M4_4 - || card->type == SC_CARD_TYPE_CARDOS_V5_0) { + || card->type == SC_CARD_TYPE_CARDOS_V5_0 + || card->type == SC_CARD_TYPE_CARDOS_V5_3) { sc_apdu_t apdu; int r; sc_path_t path; @@ -1310,6 +1550,7 @@ static struct sc_card_driver * sc_get_driver(void) cardos_ops = *iso_ops; cardos_ops.match_card = cardos_match_card; cardos_ops.init = cardos_init; + cardos_ops.finish = cardos_finish; cardos_ops.select_file = cardos_select_file; cardos_ops.create_file = cardos_create_file; cardos_ops.set_security_env = cardos_set_security_env; diff --git a/src/libopensc/card-coolkey.c b/src/libopensc/card-coolkey.c index 19c17f68..c99ef429 100644 --- a/src/libopensc/card-coolkey.c +++ b/src/libopensc/card-coolkey.c @@ -1382,6 +1382,9 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj) priv->nonce, sizeof(priv->nonce)); if (r != (int)buf_len) { free(new_obj_data); + if (r < 0) { + LOG_FUNC_RETURN(card->ctx, r); + } LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA); } obj_entry = coolkey_find_object_by_id(&priv->objects_list, obj->id); @@ -2059,17 +2062,28 @@ coolkey_process_combined_object(sc_card_t *card, coolkey_private_data_t *priv, u } memcpy(priv->token_name, &decompressed_header->token_name[0], decompressed_header->token_name_length); - priv->token_name[decompressed_header->token_name_length] = 0; + priv->token_name[decompressed_header->token_name_length] = '\0'; priv->token_name_length = decompressed_header->token_name_length; - for (i=0; i < object_count && object_offset < decompressed_object_len; i++ ) { - u8 *current_object = &decompressed_object[object_offset]; - coolkey_combined_object_header_t *object_header = - (coolkey_combined_object_header_t *)current_object; - unsigned long object_id = bebytes2ulong(object_header->object_id); + for (i=0; i < object_count; i++) { + u8 *current_object = NULL; + coolkey_combined_object_header_t *object_header = NULL; + unsigned long object_id; int current_object_len; + /* Can we read the object header at all? */ + if ((object_offset + sizeof(coolkey_combined_object_header_t)) > decompressed_object_len) { + r = SC_ERROR_CORRUPTED_DATA; + goto done; + } + + current_object = &decompressed_object[object_offset]; + object_header = (coolkey_combined_object_header_t *)current_object; + + /* Parse object ID */ + object_id = bebytes2ulong(object_header->object_id); + /* figure out how big it is */ r = coolkey_v1_get_object_length(current_object, decompressed_object_len-object_offset); if (r < 0) { @@ -2152,7 +2166,7 @@ static int coolkey_initialize(sc_card_t *card) r = coolkey_list_object(card, COOLKEY_LIST_RESET, &object_info); while (r >= 0) { unsigned long object_id; - unsigned short object_len; + unsigned long object_len; /* The card did not return what we expected: Lets try other objects */ if ((size_t)r < (sizeof(object_info))) @@ -2162,7 +2176,11 @@ static int coolkey_initialize(sc_card_t *card) object_id = bebytes2ulong(object_info.object_id); object_len = bebytes2ulong(object_info.object_length); - + /* Avoid insanely large data */ + if (object_len > MAX_FILE_SIZE) { + r = SC_ERROR_CORRUPTED_DATA; + goto cleanup; + } /* the combined object is a single object that can store the other objects. * most coolkeys provisioned by TPS has a single combined object that is @@ -2189,7 +2207,7 @@ static int coolkey_initialize(sc_card_t *card) } combined_processed = 1; } else { - sc_log(card->ctx, "Add new object id=%ld, len=%u", object_id, object_len); + sc_log(card->ctx, "Add new object id=%ld, len=%lu", object_id, object_len); r = coolkey_add_object(priv, object_id, NULL, object_len, 0); if (r != SC_SUCCESS) sc_log(card->ctx, "coolkey_add_object() returned %d", r); diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c index ce0bc33a..4788f59e 100644 --- a/src/libopensc/card-dnie.c +++ b/src/libopensc/card-dnie.c @@ -903,22 +903,6 @@ static int dnie_finish(struct sc_card *card) /* ISO 7816-4 functions */ -/** - * Convert little-endian data into unsigned long. - * - * @param pt pointer to little-endian data - * @return equivalent long - */ -static unsigned long le2ulong(u8 * pt) -{ - unsigned long res = 0L; - if (pt==NULL) return res; - res = (0xff & *(pt + 0)) + - ((0xff & *(pt + 1)) << 8) + - ((0xff & *(pt + 2)) << 16) + ((0xff & *(pt + 3)) << 24); - return res; -} - /** * Uncompress data if in compressed format. * @@ -944,14 +928,17 @@ static u8 *dnie_uncompress(sc_card_t * card, u8 * from, size_t *len) if (*len < 8) goto compress_exit; /* evaluate compressed an uncompressed sizes (little endian format) */ - uncompressed = le2ulong(from); - compressed = le2ulong(from + 4); + uncompressed = lebytes2ulong(from); + compressed = lebytes2ulong(from + 4); /* if compressed size doesn't match data length assume not compressed */ if (compressed != (*len) - 8) goto compress_exit; /* if compressed size greater than uncompressed, assume uncompressed data */ if (uncompressed < compressed) goto compress_exit; + /* Do not try to allocate insane size if we receive bogus data */ + if (uncompressed > MAX_FILE_SIZE) + goto compress_exit; sc_log(card->ctx, "Data seems to be compressed. calling uncompress"); /* ok: data seems to be compressed */ @@ -960,16 +947,15 @@ static u8 *dnie_uncompress(sc_card_t * card, u8 * from, size_t *len) sc_log(card->ctx, "alloc() for uncompressed buffer failed"); return NULL; } + *len = uncompressed; res = sc_decompress(upt, /* try to uncompress by calling sc_xx routine */ - (size_t *) & uncompressed, + len, from + 8, (size_t) compressed, COMPRESSION_ZLIB); - /* TODO: check that returned uncompressed size matches expected */ if (res != SC_SUCCESS) { sc_log(card->ctx, "Uncompress() failed or data not compressed"); goto compress_exit; /* assume not need uncompression */ } /* Done; update buffer len and return pt to uncompressed data */ - *len = uncompressed; sc_log_hex(card->ctx, "Compressed data", from + 8, compressed); sc_log_hex(card->ctx, "Uncompressed data", upt, uncompressed); compress_exit: @@ -1161,8 +1147,6 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa int res = 0; sc_apdu_t apdu; u8 rbuf[MAX_RESP_BUFFER_SIZE]; - sc_file_t *file = NULL; - sc_context_t *ctx = NULL; if (!card || !card->ctx) @@ -1199,14 +1183,15 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } - /* finally process FCI response */ - file = sc_file_new(); - if (file == NULL) { - LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + if (file_out) { + /* finally process FCI response */ + sc_file_free(*file_out); + *file_out = sc_file_new(); + if (*file_out == NULL) { + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + } + res = card->ops->process_fci(card, *file_out, apdu.resp + 2, apdu.resp[1]); } - res = card->ops->process_fci(card, file, apdu.resp + 2, apdu.resp[1]); - sc_file_free(*file_out); - *file_out = file; LOG_FUNC_RETURN(ctx, res); } @@ -1907,8 +1892,8 @@ static int dnie_read_header(struct sc_card *card) /* check response */ if (apdu.resplen != 8) goto header_notcompressed; - uncompressed = le2ulong(apdu.resp); - compressed = le2ulong(apdu.resp + 4); + uncompressed = lebytes2ulong(apdu.resp); + compressed = lebytes2ulong(apdu.resp + 4); if (uncompressed < compressed) goto header_notcompressed; if (uncompressed > 32767) diff --git a/src/libopensc/card-epass2003.c b/src/libopensc/card-epass2003.c index 26b9d79f..9621f647 100644 --- a/src/libopensc/card-epass2003.c +++ b/src/libopensc/card-epass2003.c @@ -1157,6 +1157,7 @@ epass2003_init(struct sc_card *card) unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; size_t datalen = SC_MAX_APDU_BUFFER_SIZE; epass2003_exdata *exdata = NULL; + void *old_drv_data = card->drv_data; LOG_FUNC_CALLED(card->ctx); @@ -1171,8 +1172,11 @@ epass2003_init(struct sc_card *card) exdata->sm = SM_SCP01; /* decide FIPS/Non-FIPS mode */ - if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) + if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) { + free(exdata); + card->drv_data = old_drv_data; return SC_ERROR_INVALID_CARD; + } if (0x01 == data[2]) exdata->smtype = KEY_TYPE_AES; @@ -1365,7 +1369,7 @@ epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_l sc_file_t ** file_out) { int r; - sc_file_t *file = 0; + sc_file_t *file = NULL; sc_path_t path; memset(&path, 0, sizeof(path)); @@ -1392,8 +1396,11 @@ epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_l } } - if (file_out) + if (file_out) { *file_out = file; + } else { + sc_file_free(file); + } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } diff --git a/src/libopensc/card-gids.c b/src/libopensc/card-gids.c index d775175d..e434d347 100644 --- a/src/libopensc/card-gids.c +++ b/src/libopensc/card-gids.c @@ -255,11 +255,13 @@ static int gids_get_DO(sc_card_t* card, int fileIdentifier, int dataObjectIdenti if (!p) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_FILE_NOT_FOUND); } - if (datasize > *responselen) { - LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); + if (response && responselen) { + if (datasize > *responselen) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); + } + memcpy(response, p, datasize); + *responselen = datasize; } - memcpy(response, p, datasize); - *responselen = datasize; return SC_SUCCESS; } diff --git a/src/libopensc/card-gpk.c b/src/libopensc/card-gpk.c index 4144057c..2bfcdde1 100644 --- a/src/libopensc/card-gpk.c +++ b/src/libopensc/card-gpk.c @@ -749,8 +749,10 @@ gpk_compute_crycks(sc_card_t *card, sc_apdu_t *apdu, block[len++] = apdu->p1; block[len++] = apdu->p2; block[len++] = apdu->lc + 3; - if ((i = apdu->datalen) + len > sizeof(block)) + if (apdu->datalen + len > sizeof(block)) i = sizeof(block) - len; + else + i = apdu->datalen; memcpy(block+len, apdu->data, i); len += i; diff --git a/src/libopensc/card-iasecc.c b/src/libopensc/card-iasecc.c index 9f801189..b0349357 100644 --- a/src/libopensc/card-iasecc.c +++ b/src/libopensc/card-iasecc.c @@ -580,6 +580,7 @@ iasecc_init(struct sc_card *card) struct sc_context *ctx = card->ctx; struct iasecc_private_data *private_data = NULL; int rv = SC_ERROR_NO_CARD_SUPPORT; + void *old_drv_data = card->drv_data; LOG_FUNC_CALLED(ctx); private_data = (struct iasecc_private_data *) calloc(1, sizeof(struct iasecc_private_data)); @@ -599,8 +600,9 @@ iasecc_init(struct sc_card *card) rv = iasecc_init_amos_or_sagem(card); else if (card->type == SC_CARD_TYPE_IASECC_MI) rv = iasecc_init_amos_or_sagem(card); - else - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_CARD); + else { + LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_CARD, ""); + } if (!rv) { @@ -614,7 +616,7 @@ iasecc_init(struct sc_card *card) rv = iasecc_select_file(card, &path, NULL); sc_log(ctx, "Select ECC ROOT with the AID from EF.ATR: rv %i", rv); - LOG_TEST_RET(ctx, rv, "Select EF.ATR AID failed"); + LOG_TEST_GOTO_ERR(ctx, rv, "Select EF.ATR AID failed"); } iasecc_get_serialnr(card, NULL); @@ -628,6 +630,15 @@ iasecc_init(struct sc_card *card) if (!rv && card->ef_atr && card->ef_atr->aid.len) { sc_log(ctx, "EF.ATR(aid:'%s')", sc_dump_hex(card->ef_atr->aid.value, card->ef_atr->aid.len)); } + +err: + if (rv < 0) { + free(private_data); + card->drv_data = old_drv_data; + } else { + free(old_drv_data); + } + LOG_FUNC_RETURN(ctx, rv); } @@ -859,12 +870,14 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, df_from_cache = 1; rv = iasecc_select_file(card, &ppath, &file); - LOG_TEST_RET(ctx, rv, "select AID path failed"); + LOG_TEST_GOTO_ERR(ctx, rv, "select AID path failed"); - if (file_out) + if (file_out) { + sc_file_free(*file_out); *file_out = file; - else - sc_file_free(file); + } else { + sc_file_free(file); + } if (lpath.type == SC_PATH_TYPE_DF_NAME) lpath.type = SC_PATH_TYPE_FROM_CURRENT; @@ -873,8 +886,13 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, if (lpath.type == SC_PATH_TYPE_PATH) lpath.type = SC_PATH_TYPE_FROM_CURRENT; - if (!lpath.len) + if (!lpath.len) { + if (file_out) { + sc_file_free(*file_out); + *file_out = NULL; + } LOG_FUNC_RETURN(ctx, SC_SUCCESS); + } sc_print_cache(card); @@ -882,7 +900,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, && card->cache.current_df->path.len == lpath.len && !memcmp(card->cache.current_df->path.value, lpath.value, lpath.len)) { sc_log(ctx, "returns current DF path %s", sc_print_path(&card->cache.current_df->path)); - if (file_out) { + if (file_out) { sc_file_free(*file_out); sc_file_dup(file_out, card->cache.current_df); } @@ -904,8 +922,10 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, && card->type != SC_CARD_TYPE_IASECC_SAGEM && card->type != SC_CARD_TYPE_IASECC_AMOS && card->type != SC_CARD_TYPE_IASECC_MI - && card->type != SC_CARD_TYPE_IASECC_MI2) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported card"); + && card->type != SC_CARD_TYPE_IASECC_MI2) { + rv = SC_ERROR_NOT_SUPPORTED; + LOG_TEST_GOTO_ERR(ctx, rv, "Unsupported card"); + } if (lpath.type == SC_PATH_TYPE_FILE_ID) { apdu.p1 = 0x02; @@ -945,7 +965,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, } else { sc_log(ctx, "Invalid PATH type: 0x%X", lpath.type); - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "iasecc_select_file() invalid PATH type"); + rv = SC_ERROR_NOT_SUPPORTED; + LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_select_file() invalid PATH type"); } for (ii=0; ii<2; ii++) { @@ -958,7 +979,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, apdu.le = 256; rv = sc_transmit_apdu(card, &apdu); - LOG_TEST_RET(ctx, rv, "APDU transmit failed"); + LOG_TEST_GOTO_ERR(ctx, rv, "APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); if (rv == SC_ERROR_INCORRECT_PARAMETERS && lpath.type == SC_PATH_TYPE_DF_NAME && apdu.p2 == 0x00) { @@ -970,7 +991,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, /* 'SELECT AID' do not returned FCP. Try to emulate. */ apdu.resplen = sizeof(rbuf); rv = iasecc_emulate_fcp(ctx, &apdu); - LOG_TEST_RET(ctx, rv, "Failed to emulate DF FCP"); + LOG_TEST_GOTO_ERR(ctx, rv, "Failed to emulate DF FCP"); } break; @@ -984,7 +1005,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, if (rv == SC_ERROR_FILE_NOT_FOUND && cache_valid && df_from_cache) { sc_invalidate_cache(card); sc_log(ctx, "iasecc_select_file() file not found, retry without cached DF"); - if (file_out) { + if (file_out) { sc_file_free(*file_out); *file_out = NULL; } @@ -992,7 +1013,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, LOG_FUNC_RETURN(ctx, rv); } - LOG_TEST_RET(ctx, rv, "iasecc_select_file() check SW failed"); + LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_select_file() check SW failed"); sc_log(ctx, "iasecc_select_file() apdu.resp %"SC_FORMAT_LEN_SIZE_T"u", @@ -1004,15 +1025,30 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, case 0x62: case 0x6F: file = sc_file_new(); - if (file == NULL) + if (file == NULL) { + if (file_out) { + sc_file_free(*file_out); + *file_out = NULL; + } LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + } file->path = lpath; rv = iasecc_process_fci(card, file, apdu.resp, apdu.resplen); - if (rv) + if (rv) { + sc_file_free(file); + if (file_out) { + sc_file_free(*file_out); + *file_out = NULL; + } LOG_FUNC_RETURN(ctx, rv); + } break; default: + if (file_out) { + sc_file_free(*file_out); + *file_out = NULL; + } LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } @@ -1060,6 +1096,12 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path, sc_print_cache(card); LOG_FUNC_RETURN(ctx, SC_SUCCESS); +err: + if (file_out) { + sc_file_free(*file_out); + *file_out = NULL; + } + return rv; } diff --git a/src/libopensc/card-idprime.c b/src/libopensc/card-idprime.c new file mode 100644 index 00000000..e805da15 --- /dev/null +++ b/src/libopensc/card-idprime.c @@ -0,0 +1,804 @@ +/* + * card-idprime.c: Support for Gemalto IDPrime smart cards + * + * Copyright (c) 2019 Red Hat, Inc. + * + * Author: Jakub Jelen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#include +#include +#include +#ifdef ENABLE_ZLIB +#include "compression.h" +#endif + +#include "cardctl.h" +#include "pkcs15.h" + +static const struct sc_card_operations *iso_ops = NULL; + +static struct sc_card_operations idprime_ops; +static struct sc_card_driver idprime_drv = { + "Gemalto IDPrime", + "idprime", + &idprime_ops, + NULL, 0, NULL +}; + +/* This ATR says, there is no EF.DIR nor EF.ATR so ISO discovery mechanisms + * are not useful here */ +static const struct sc_atr_table idprime_atrs[] = { + { "3b:7f:96:00:00:80:31:80:65:b0:84:41:3d:f6:12:0f:fe:82:90:00", + "ff:ff:00:ff:ff:ff:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff", + "Gemalto IDPrime MD 8840, 3840, 3810, 840 and 830 Cards", + SC_CARD_TYPE_IDPRIME_GENERIC, 0, NULL }, + { NULL, NULL, NULL, 0, 0, NULL } +}; + +static const sc_path_t idprime_path = { + "", 0, + 0, 0, SC_PATH_TYPE_DF_NAME, + { "\xA0\x00\x00\x00\x18\x80\x00\x00\x00\x06\x62", 11 } +}; + +/* data structures to store meta data about IDPrime objects */ +typedef struct idprime_object { + int fd; + unsigned char key_reference; + u8 df[2]; + unsigned short length; +} idprime_object_t; + +/* + * IDPrime private data per card state + */ +typedef struct idprime_private_data { + u8 *cache_buf; /* cached version of the currently selected file */ + size_t cache_buf_len; /* length of the cached selected file */ + int cached; /* is the cached selected file valid */ + size_t file_size; /* this is real file size since IDPrime is quite strict about lengths */ + list_t pki_list; /* list of pki containers */ + idprime_object_t *pki_current; /* current pki object _ctl function */ + int tinfo_present; /* Token Info Label object is present*/ + u8 tinfo_df[2]; /* DF of object with Token Info Label */ +} idprime_private_data_t; + +/* For SimCList autocopy, we need to know the size of the data elements */ +static size_t idprime_list_meter(const void *el) { + return sizeof(idprime_object_t); +} + +void idprime_free_private_data(idprime_private_data_t *priv) +{ + free(priv->cache_buf); + list_destroy(&priv->pki_list); + free(priv); + return; +} + +idprime_private_data_t *idprime_new_private_data(void) +{ + idprime_private_data_t *priv; + + priv = calloc(1, sizeof(idprime_private_data_t)); + if (priv == NULL) + return NULL; + + /* Initialize PKI Applets list */ + if (list_init(&priv->pki_list) != 0 || + list_attributes_copy(&priv->pki_list, idprime_list_meter, 1) != 0) { + idprime_free_private_data(priv); + return NULL; + } + + return priv; +} + +int idprime_add_object_to_list(list_t *list, const idprime_object_t *object) +{ + if (list_append(list, object) < 0) + return SC_ERROR_INTERNAL; + return SC_SUCCESS; +} + +/* This selects main IDPrime AID which is used for communication with + * the card */ +static int idprime_select_idprime(sc_card_t *card) +{ + return iso_ops->select_file(card, &idprime_path, NULL); +} + +/* This select some index file, which is useful for enumerating other files + * on the card */ +static int idprime_select_index(sc_card_t *card) +{ + int r; + sc_file_t *file = NULL; + sc_path_t index_path; + + /* First, we need to make sure the IDPrime AID is selected */ + r = idprime_select_idprime(card); + if (r != SC_SUCCESS) { + LOG_FUNC_RETURN(card->ctx, r); + } + + /* Returns FCI with expected length of data */ + sc_format_path("0101", &index_path); + r = iso_ops->select_file(card, &index_path, &file); + if (r == SC_SUCCESS) { + r = file->size; + } + sc_file_free(file); + /* Ignore too large files */ + if (r <= 0 || r > MAX_FILE_SIZE) { + r = SC_ERROR_INVALID_DATA; + } + return r; +} + +static int idprime_process_index(sc_card_t *card, idprime_private_data_t *priv, int length) +{ + u8 *buf = NULL; + int r = SC_ERROR_OUT_OF_MEMORY; + int i, num_entries; + idprime_object_t new_object; + + buf = malloc(length); + if (buf == NULL) { + goto done; + } + + r = iso_ops->read_binary(card, 0, buf, length, 0); + if (r < 1) { + r = SC_ERROR_WRONG_LENGTH; + goto done; + } + + /* First byte shows the number of entries, each of them 21 bytes long */ + num_entries = buf[0]; + if (r < num_entries*21 + 1) { + r = SC_ERROR_INVALID_DATA; + goto done; + } + new_object.fd = 0; + for (i = 0; i < num_entries; i++) { + u8 *start = &buf[i*21+1]; + + /* First two bytes specify the object DF */ + new_object.df[0] = start[0]; + new_object.df[1] = start[1]; + /* Second two bytes refer to the object size */ + new_object.length = bebytes2ushort(&start[2]); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "df=%s, len=%u", + sc_dump_hex(new_object.df, sizeof(new_object.df)), new_object.length); + /* in minidriver, mscp/kxcNN or kscNN lists certificates */ + if (((memcmp(&start[4], "ksc", 3) == 0) || memcmp(&start[4], "kxc", 3) == 0) + && (memcmp(&start[12], "mscp", 5) == 0)) { + new_object.fd++; + if (card->type == SC_CARD_TYPE_IDPRIME_V2) { + /* The key reference starts from 0x11 */ + new_object.key_reference = 0x10 + new_object.fd; + } else { + /* The key reference is one bigger than the value found here for some reason */ + new_object.key_reference = start[8] + 1; + } + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found certificate with fd=%d, key_ref=%d", + new_object.fd, new_object.key_reference); + idprime_add_object_to_list(&priv->pki_list, &new_object); + + /* This looks like non-standard extension listing pkcs11 token info label in my card */ + } else if ((memcmp(&start[4], "tinfo", 6) == 0) && (memcmp(&start[12], "p11", 4) == 0)) { + memcpy(priv->tinfo_df, new_object.df, sizeof(priv->tinfo_df)); + priv->tinfo_present = 1; + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found p11/tinfo object"); + } + } + r = SC_SUCCESS; +done: + free(buf); + LOG_FUNC_RETURN(card->ctx, r); +} + +/* CPLC has 42 bytes, but we get it with 3B header */ +#define CPLC_LENGTH 45 +static int idprime_init(sc_card_t *card) +{ + int r; + unsigned long flags; + idprime_private_data_t *priv = NULL; + struct sc_apdu apdu; + u8 rbuf[CPLC_LENGTH]; + size_t rbuflen = sizeof(rbuf); + + /* We need to differentiate the OS version since they behave slightly differently */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xCA, 0x9F, 0x7F); + apdu.resp = rbuf; + apdu.resplen = rbuflen; + apdu.le = rbuflen; + r = sc_transmit_apdu(card, &apdu); + card->type = SC_CARD_TYPE_IDPRIME_GENERIC; + if (r == SC_SUCCESS && apdu.resplen == CPLC_LENGTH) { + /* We are interested in the OS release level here */ + switch (rbuf[11]) { + case 0x01: + card->type = SC_CARD_TYPE_IDPRIME_V1; + sc_log(card->ctx, "Detected IDPrime applet version 1"); + break; + case 0x02: + card->type = SC_CARD_TYPE_IDPRIME_V2; + sc_log(card->ctx, "Detected IDPrime applet version 2"); + break; + default: + sc_log(card->ctx, "Unknown OS version received: %d", rbuf[11]); + break; + } + } else { + sc_log(card->ctx, "Failed to get CPLC data or invalid length returned, " + "err=%d, len=%"SC_FORMAT_LEN_SIZE_T"u", + r, apdu.resplen); + } + + /* Now, select and process the index file */ + r = idprime_select_index(card); + if (r <= 0) { + LOG_FUNC_RETURN(card->ctx, r); + } + + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Index file found"); + + priv = idprime_new_private_data(); + if (!priv) { + return SC_ERROR_OUT_OF_MEMORY; + } + + r = idprime_process_index(card, priv, r); + if (r != SC_SUCCESS) { + idprime_free_private_data(priv); + LOG_FUNC_RETURN(card->ctx, r); + } + + card->drv_data = priv; + + switch (card->type) { + case SC_CARD_TYPE_IDPRIME_V1: + card->name = "Gemalto IDPrime (OSv1)"; + break; + case SC_CARD_TYPE_IDPRIME_V2: + card->name = "Gemalto IDPrime (OSv2)"; + break; + case SC_CARD_TYPE_IDPRIME_GENERIC: + default: + card->name = "Gemalto IDPrime (generic)"; + break; + } + card->cla = 0x00; + + /* Set up algorithm info. */ + flags = SC_ALGORITHM_RSA_PAD_PKCS1 + | SC_ALGORITHM_RSA_PAD_PSS + | SC_ALGORITHM_RSA_PAD_OAEP + /* SHA-1 mechanisms are not allowed in the card I have */ + | (SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512) + | (SC_ALGORITHM_MGF1_SHA256 | SC_ALGORITHM_MGF1_SHA384 | SC_ALGORITHM_MGF1_SHA512) + ; + + _sc_card_add_rsa_alg(card, 1024, flags, 0); + _sc_card_add_rsa_alg(card, 2048, flags, 0); + + card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; + + LOG_FUNC_RETURN(card->ctx, 0); +} + +static int idprime_finish(sc_card_t *card) +{ + idprime_private_data_t * priv = card->drv_data; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + if (priv) { + idprime_free_private_data(priv); + } + return SC_SUCCESS; +} + +static int idprime_match_card(sc_card_t *card) +{ + int i, r; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + i = _sc_match_atr(card, idprime_atrs, &card->type); + if (i < 0) + return 0; + + r = idprime_select_index(card); + return (r > 0); +} + +/* initialize getting a list and return the number of elements in the list */ +static int idprime_get_init_and_get_count(list_t *list, idprime_object_t **entry, int *countp) +{ + if (countp == NULL || entry == NULL) { + return SC_ERROR_INVALID_ARGUMENTS; + } + *countp = list_size(list); + list_iterator_start(list); + *entry = list_iterator_next(list); + return SC_SUCCESS; +} + +/* finalize the list iterator */ +static int idprime_final_iterator(list_t *list) +{ + list_iterator_stop(list); + return SC_SUCCESS; +} + +/* fill in the prkey_info for the current object on the list and advance to the next object */ +static int idprime_fill_prkey_info(list_t *list, idprime_object_t **entry, sc_pkcs15_prkey_info_t *prkey_info) +{ + memset(prkey_info, 0, sizeof(sc_pkcs15_prkey_info_t)); + if (*entry == NULL) { + return SC_ERROR_FILE_END_REACHED; + } + + prkey_info->path.len = sizeof((*entry)->df); + memcpy(prkey_info->path.value, (*entry)->df, sizeof((*entry)->df)); + prkey_info->path.type = SC_PATH_TYPE_FILE_ID; + /* Do not specify the length -- it will be read from the FCI */ + prkey_info->path.count = -1; + + /* TODO figure out the IDs as the original driver? */ + prkey_info->id.value[0] = ((*entry)->fd >> 8) & 0xff; + prkey_info->id.value[1] = (*entry)->fd & 0xff; + prkey_info->id.len = 2; + prkey_info->key_reference = (*entry)->key_reference; + *entry = list_iterator_next(list); + return SC_SUCCESS; +} + +#define IDPRIME_CARDID_LEN 16 + +static int idprime_get_serial(sc_card_t* card, sc_serial_number_t* serial) +{ + sc_path_t cardid_path; + sc_file_t *file = NULL; + u8 buf[IDPRIME_CARDID_LEN]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + /* XXX this is assumed to be cardid for windows. It can be read from the index file */ + sc_format_path("0201", &cardid_path); + r = iso_ops->select_file(card, &cardid_path, &file); + if (r != SC_SUCCESS || file->size != IDPRIME_CARDID_LEN) { /* The cardid is always 16 B */ + sc_file_free(file); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH); + } + + r = iso_ops->read_binary(card, 0, buf, file->size, 0); + sc_file_free(file); + if (r < 1) { + LOG_FUNC_RETURN(card->ctx, r); + } else if (r != IDPRIME_CARDID_LEN) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); + } + + serial->len = MIN(IDPRIME_CARDID_LEN, SC_MAX_SERIALNR); + memcpy(serial->value, buf, serial->len); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static int idprime_get_token_name(sc_card_t* card, char** tname) +{ + idprime_private_data_t * priv = card->drv_data; + sc_path_t tinfo_path = {"\x00\x00", 2, 0, 0, SC_PATH_TYPE_PATH, {"", 0}}; + sc_file_t *file = NULL; + u8 buf[2]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + if (tname == NULL) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } + + if (!priv->tinfo_present) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + } + + memcpy(tinfo_path.value, priv->tinfo_df, 2); + r = iso_ops->select_file(card, &tinfo_path, &file); + if (r != SC_SUCCESS || file->size == 0) { + sc_file_free(file); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + } + + /* First two bytes lists 0x01, the second indicates length */ + r = iso_ops->read_binary(card, 0, buf, 2, 0); + if (r < 2 || buf[1] > file->size) { /* make sure we do not overrun */ + sc_file_free(file); + LOG_FUNC_RETURN(card->ctx, r); + } + sc_file_free(file); + + *tname = malloc(buf[1]); + if (*tname == NULL) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + } + + r = iso_ops->read_binary(card, 2, (unsigned char *)*tname, buf[1], 0); + if (r < 1) { + free(*tname); + LOG_FUNC_RETURN(card->ctx, r); + } + + if ((*tname)[r-1] != '\0') { + (*tname)[r-1] = '\0'; + } + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +static int idprime_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) +{ + idprime_private_data_t * priv = card->drv_data; + + LOG_FUNC_CALLED(card->ctx); + sc_log(card->ctx, "cmd=%ld ptr=%p", cmd, ptr); + + if (priv == NULL) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + switch (cmd) { + case SC_CARDCTL_GET_SERIALNR: + return idprime_get_serial(card, (sc_serial_number_t *) ptr); + case SC_CARDCTL_IDPRIME_GET_TOKEN_NAME: + return idprime_get_token_name(card, (char **) ptr); + case SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS: + return idprime_get_init_and_get_count(&priv->pki_list, &priv->pki_current, + (int *)ptr); + case SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT: + return idprime_fill_prkey_info(&priv->pki_list, &priv->pki_current, + (sc_pkcs15_prkey_info_t *)ptr); + case SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS: + return idprime_final_iterator(&priv->pki_list); + } + + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); +} + +#define HEADER_LEN 4 + +static int idprime_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) +{ + int r, len; + idprime_private_data_t * priv = card->drv_data; + u8 data[HEADER_LEN]; + size_t data_len = HEADER_LEN; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* forget any old cached values */ + if (priv->cache_buf) { + free(priv->cache_buf); + priv->cache_buf = NULL; + } + priv->cache_buf_len = 0; + priv->cached = 0; + + r = iso_ops->select_file(card, in_path, file_out); + if (r == SC_SUCCESS && file_out != NULL) { + /* Try to read first bytes of the file to fix FCI in case of + * compressed certififcate */ + len = iso_ops->read_binary(card, 0, data, data_len, 0); + if (len == HEADER_LEN && data[0] == 0x01 && data[1] == 0x00) { + /* Cache the real file size for the caching read_binary() */ + priv->file_size = (*file_out)->size; + /* Fix the information in the file structure to not confuse upper layers */ + (*file_out)->size = (data[3]<<8) | data[2]; + } + } + /* Return the exit code of the select command */ + return r; +} + +// used to read existing certificates +static int idprime_read_binary(sc_card_t *card, unsigned int offset, + unsigned char *buf, size_t count, unsigned long flags) +{ + struct idprime_private_data *priv = card->drv_data; + int r; + int size; + + sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at offset %d", + count, offset); + + if (!priv->cached && offset == 0) { + // this function is called to read and uncompress the certificate + u8 buffer[SC_MAX_EXT_APDU_BUFFER_SIZE]; + if (sizeof(buffer) < count) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + /* Read what was reported by FCI from select command */ + r = iso_ops->read_binary(card, 0, buffer, priv->file_size, flags); + if (r < 0) { + LOG_FUNC_RETURN(card->ctx, r); + } + if (r < 4) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); + } + if (buffer[0] == 1 && buffer[1] == 0) { +#ifdef ENABLE_ZLIB + size_t expectedsize = buffer[2] + buffer[3] * 0x100; + r = sc_decompress_alloc(&priv->cache_buf, &(priv->cache_buf_len), + buffer+4, priv->file_size-4, COMPRESSION_AUTO); + if (r != SC_SUCCESS) { + sc_log(card->ctx, "Zlib error: %d", r); + LOG_FUNC_RETURN(card->ctx, r); + } + if (priv->cache_buf_len != expectedsize) { + sc_log(card->ctx, + "expected size: %"SC_FORMAT_LEN_SIZE_T"u real size: %"SC_FORMAT_LEN_SIZE_T"u", + expectedsize, priv->cache_buf_len); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); + } +#else + sc_log(card->ctx, "compression not supported, no zlib"); + return SC_ERROR_NOT_SUPPORTED; +#endif /* ENABLE_ZLIB */ + } else { + /* assuming uncompressed certificate */ + priv->cache_buf = malloc(r); + if (priv->cache_buf == NULL) { + return SC_ERROR_OUT_OF_MEMORY; + } + memcpy(priv->cache_buf, buffer, r); + priv->cache_buf_len = r; + } + priv->cached = 1; + } + if (offset >= priv->cache_buf_len) { + return 0; + } + size = (int) MIN((priv->cache_buf_len - offset), count); + memcpy(buf, priv->cache_buf + offset, size); + return size; +} + +static int +idprime_set_security_env(struct sc_card *card, + const struct sc_security_env *env, int se_num) +{ + int r; + struct sc_security_env new_env; + + if (card == NULL || env == NULL) { + return SC_ERROR_INVALID_ARGUMENTS; + } + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* The card requires algorithm reference here */ + new_env = *env; + new_env.flags |= SC_SEC_ENV_ALG_REF_PRESENT; + /* SHA-1 mechanisms are not allowed in the card I have available */ + switch (env->operation) { + case SC_SEC_OPERATION_DECIPHER: + if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_OAEP) { + if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) { + new_env.algorithm_ref = 0x1D; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) { + new_env.algorithm_ref = 0x4D; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) { + new_env.algorithm_ref = 0x5D; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) { + new_env.algorithm_ref = 0x6D; + } + } else { /* RSA-PKCS without hashing */ + new_env.algorithm_ref = 0x1A; + } + break; + case SC_SEC_OPERATION_SIGN: + if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) { + if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) { + new_env.algorithm_ref = 0x45; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) { + new_env.algorithm_ref = 0x55; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) { + new_env.algorithm_ref = 0x65; + } + } else { /* RSA-PKCS */ + if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) { + new_env.algorithm_ref = 0x42; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) { + new_env.algorithm_ref = 0x52; + } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) { + new_env.algorithm_ref = 0x62; + } else { /* RSA-PKCS without hashing */ + new_env.algorithm_ref = 0x02; + } + } + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; + } + r = iso_ops->set_security_env(card, + (const struct sc_security_env *) &new_env, se_num); + + LOG_FUNC_RETURN(card->ctx, r); +} + +/* These are mostly ISO versions updated to IDPrime specifics */ +static int +idprime_compute_signature(struct sc_card *card, + const u8 * data, size_t datalen, u8 * out, size_t outlen) +{ + int r; + struct sc_apdu apdu; + u8 *p; + u8 sbuf[128]; /* For SHA-512 we need 64 + 2 bytes */ + u8 rbuf[4096]; /* needs work. for 3072 keys, needs 384+2 or so */ + size_t rbuflen = sizeof(rbuf); + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* We should be signing hashes only so we should not reach this limit */ + if (datalen + 2 > sizeof(sbuf)) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + + p = sbuf; + *(p++) = 0x90; + *(p++) = datalen; + memcpy(p, data, datalen); + p += datalen; + + /* INS: 0x2A PERFORM SECURITY OPERATION + * P1: 0x90 Hash code + * P2: 0xA0 Input template for the computation of a hash-code (the template is hashed) */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x90, 0xA0); + apdu.resp = rbuf; + apdu.resplen = rbuflen; + apdu.le = datalen; + + apdu.data = sbuf; + apdu.lc = p - sbuf; + apdu.datalen = p - sbuf; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + /* This just returns the passed data (hash code) (for verification?) */ + if (apdu.resplen != datalen || memcmp(rbuf, data, datalen) != 0) { + sc_log(card->ctx, "The initial APDU did not return the same data"); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + /* INS: 0x2A PERFORM SECURITY OPERATION + * P1: 0x9E Resp: Digital Signature + * P2: 0x9A Cmd: Input for Digital Signature */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x2A, 0x9E, 0x9A); + apdu.resp = out; + apdu.resplen = outlen; + apdu.le = outlen; + if (apdu.le > sc_get_max_recv_size(card)) { + /* The lower layers will automatically do a GET RESPONSE, if possible. + * All other workarounds must be carried out by the upper layers. */ + apdu.le = sc_get_max_recv_size(card); + } + + apdu.data = NULL; + apdu.datalen = 0; + apdu.lc = 0; + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + LOG_FUNC_RETURN(card->ctx, apdu.resplen); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + LOG_FUNC_RETURN(card->ctx, r); +} + +/* These are mostly ISO versions updated to IDPrime specifics */ +static int +idprime_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) +{ + int r; + struct sc_apdu apdu; + u8 *sbuf = NULL; + + if (card == NULL || crgram == NULL || out == NULL) { + return SC_ERROR_INVALID_ARGUMENTS; + } + LOG_FUNC_CALLED(card->ctx); + sc_log(card->ctx, + "IDPrime decipher: in-len %"SC_FORMAT_LEN_SIZE_T"u, out-len %"SC_FORMAT_LEN_SIZE_T"u", + crgram_len, outlen); + + sbuf = malloc(crgram_len + 1); + if (sbuf == NULL) + return SC_ERROR_OUT_OF_MEMORY; + + /* INS: 0x2A PERFORM SECURITY OPERATION + * P1: 0x80 Resp: Plain value + * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86); + apdu.resp = out; + apdu.resplen = outlen; + apdu.le = outlen; + + sbuf[0] = 0x81; /* padding indicator byte, 0x81 = Proprietary */ + memcpy(sbuf + 1, crgram, crgram_len); + apdu.data = sbuf; + apdu.lc = crgram_len + 1; + if (apdu.lc > sc_get_max_send_size(card)) { + /* The lower layers will automatically do chaining */ + apdu.flags |= SC_APDU_FLAGS_CHAINING; + } + if (apdu.le > sc_get_max_recv_size(card)) { + /* The lower layers will automatically do a GET RESPONSE, if possible. + * All other workarounds must be carried out by the upper layers. */ + apdu.le = sc_get_max_recv_size(card); + } + apdu.datalen = crgram_len + 1; + + r = sc_transmit_apdu(card, &apdu); + sc_mem_clear(sbuf, crgram_len + 1); + free(sbuf); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + LOG_FUNC_RETURN(card->ctx, apdu.resplen); + else + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); +} + + +static struct sc_card_driver * sc_get_driver(void) +{ + if (iso_ops == NULL) { + iso_ops = sc_get_iso7816_driver()->ops; + } + + idprime_ops = *iso_ops; + idprime_ops.match_card = idprime_match_card; + idprime_ops.init = idprime_init; + idprime_ops.finish = idprime_finish; + + idprime_ops.read_binary = idprime_read_binary; + idprime_ops.select_file = idprime_select_file; + idprime_ops.card_ctl = idprime_card_ctl; + idprime_ops.set_security_env = idprime_set_security_env; + idprime_ops.compute_signature = idprime_compute_signature; + idprime_ops.decipher = idprime_decipher; + + return &idprime_drv; +} + +struct sc_card_driver * sc_get_idprime_driver(void) +{ + return sc_get_driver(); +} diff --git a/src/libopensc/card-oberthur.c b/src/libopensc/card-oberthur.c index 0d4103de..530421a4 100644 --- a/src/libopensc/card-oberthur.c +++ b/src/libopensc/card-oberthur.c @@ -182,10 +182,14 @@ auth_select_aid(struct sc_card *card) LOG_TEST_RET(card->ctx, rv, "select parent failed"); sc_format_path("3F00", &tmp_path); + sc_file_free(auth_current_df); + auth_current_df = NULL; rv = iso_ops->select_file(card, &tmp_path, &auth_current_df); LOG_TEST_RET(card->ctx, rv, "select parent failed"); sc_format_path("3F00", &card->cache.current_path); + sc_file_free(auth_current_ef); + auth_current_ef = NULL; sc_file_dup(&auth_current_ef, auth_current_df); memcpy(data->aid, aidAuthentIC_V5, lenAidAuthentIC_V5); @@ -478,6 +482,7 @@ auth_select_file(struct sc_card *card, const struct sc_path *in_path, tmp_file->path.len -= 2; sc_file_free(auth_current_df); + auth_current_df = NULL; sc_file_dup(&auth_current_df, tmp_file); } else { @@ -485,10 +490,12 @@ auth_select_file(struct sc_card *card, const struct sc_path *in_path, sc_concatenate_path(&tmp_file->path, &auth_current_df->path, &path); sc_file_free(auth_current_df); + auth_current_df = NULL; sc_file_dup(&auth_current_df, tmp_file); } else { sc_file_free(auth_current_ef); + auth_current_ef = NULL; sc_file_dup(&auth_current_ef, tmp_file); sc_concatenate_path(&auth_current_ef->path, &auth_current_df->path, &path); @@ -970,6 +977,7 @@ auth_create_file(struct sc_card *card, struct sc_file *file) } sc_file_free(auth_current_ef); + auth_current_ef = NULL; sc_file_dup(&auth_current_ef, file); LOG_FUNC_RETURN(card->ctx, rv); @@ -1843,8 +1851,15 @@ auth_pin_reset_oberthur_style(struct sc_card *card, unsigned int type, "%s: PIN CMD 'VERIFY' with pinpad failed", sc_strerror(rvv)); - if (auth_current_ef) - rv = iso_ops->select_file(card, &auth_current_ef->path, &auth_current_ef); + if (auth_current_ef) { + struct sc_file *ef = NULL; + rv = iso_ops->select_file(card, &auth_current_ef->path, &ef); + if (rv == SC_SUCCESS) { + sc_file_free(auth_current_ef); + auth_current_ef = ef; + } else + sc_file_free(ef); + } if (rv > 0) rv = 0; @@ -2051,6 +2066,10 @@ auth_update_binary(struct sc_card *card, unsigned int offset, int rv = 0; LOG_FUNC_CALLED(card->ctx); + + if (!auth_current_ef) + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid auth_current_ef"); + sc_log(card->ctx, "offset %i; count %"SC_FORMAT_LEN_SIZE_T"u", offset, count); sc_log(card->ctx, "last selected : magic %X; ef %X", diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index cf486efa..bf8ab51e 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -52,11 +52,15 @@ #include #endif /* ENABLE_OPENSSL */ +#include "card-openpgp.h" + + static const char default_cardname[] = "OpenPGP card"; static const char default_cardname_v1[] = "OpenPGP card v1.x"; static const char default_cardname_v2[] = "OpenPGP card v2.x"; static const char default_cardname_v3[] = "OpenPGP card v3.x"; + static const struct sc_atr_table pgp_atrs[] = { { "3b:fa:13:00:ff:81:31:80:45:00:31:c1:73:c0:01:00:00:90:00:b1", NULL, default_cardname_v1, SC_CARD_TYPE_OPENPGP_V1, 0, NULL }, { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, default_cardname_v2, SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, @@ -72,6 +76,7 @@ static const struct sc_atr_table pgp_atrs[] = { { NULL, NULL, NULL, 0, 0, NULL } }; + static struct sc_card_operations *iso_ops; static struct sc_card_operations pgp_ops; static struct sc_card_driver pgp_drv = { @@ -81,6 +86,26 @@ static struct sc_card_driver pgp_drv = { NULL, 0, NULL }; + +static pgp_ec_curves_t ec_curves[] = { + {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */ + {{{1, 3, 132, 0, 34, -1}}, 384}, /* ansiX9p384r1 */ + {{{1, 3, 132, 0, 35, -1}}, 521}, /* ansiX9p521r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256}, /* brainpoolP256r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384}, /* brainpoolP384r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512}, /* brainpoolP512r1 */ + {{{-1}}, 0} /* This entry must not be touched. */ +}; + +static pgp_ec_curves_t ec_curves_gnuk[] = { + {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */ + {{{1, 3, 132, 0, 10, -1}}, 256}, /* secp256k1 */ + /*{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, //cv25519 + {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, // ed25519 */ + {{{-1}}, 0} /* This entry must not be touched. */ +}; + + /* * The OpenPGP card doesn't have a file system, instead everything * is stored in data objects that are accessed through GET/PUT. @@ -93,181 +118,19 @@ static struct sc_card_driver pgp_drv = { * Everything else is mapped to "file" IDs. */ -enum _type { /* DO type */ - SIMPLE = SC_FILE_TYPE_WORKING_EF, - CONSTRUCTED = SC_FILE_TYPE_DF -}; - -enum _version { /* 2-byte BCD-alike encoded version number */ - OPENPGP_CARD_1_0 = 0x0100, - OPENPGP_CARD_1_1 = 0x0101, - OPENPGP_CARD_2_0 = 0x0200, - OPENPGP_CARD_2_1 = 0x0201, - OPENPGP_CARD_2_2 = 0x0202, - OPENPGP_CARD_3_0 = 0x0300, - OPENPGP_CARD_3_1 = 0x0301, - OPENPGP_CARD_3_2 = 0x0302, - OPENPGP_CARD_3_3 = 0x0303, - OPENPGP_CARD_3_4 = 0x0304, -}; - -enum _access { /* access flags for the respective DO/file */ - READ_NEVER = 0x0010, - READ_PIN1 = 0x0011, - READ_PIN2 = 0x0012, - READ_PIN3 = 0x0014, - READ_ALWAYS = 0x0018, - READ_MASK = 0x00FF, - WRITE_NEVER = 0x1000, - WRITE_PIN1 = 0x1100, - WRITE_PIN2 = 0x1200, - WRITE_PIN3 = 0x1400, - WRITE_ALWAYS = 0x1800, - WRITE_MASK = 0x1F00 -}; - -enum _ext_caps { /* extended capabilities/features: bit flags */ - EXT_CAP_ALG_ATTR_CHANGEABLE = 0x0004, - EXT_CAP_PRIVATE_DO = 0x0008, - EXT_CAP_C4_CHANGEABLE = 0x0010, - EXT_CAP_KEY_IMPORT = 0x0020, - EXT_CAP_GET_CHALLENGE = 0x0040, - EXT_CAP_SM = 0x0080, - EXT_CAP_LCS = 0x0100, - EXT_CAP_CHAINING = 0x1000, - EXT_CAP_APDU_EXT = 0x2000, - EXT_CAP_MSE = 0x4000 -}; - -enum _card_state { - CARD_STATE_UNKNOWN = 0x00, - CARD_STATE_INITIALIZATION = 0x03, - CARD_STATE_ACTIVATED = 0x05 -}; - -enum _sm_algo { - SM_ALGO_NONE = 0, /* SM not supported */ - SM_ALGO_AES128 = 1, - SM_ALGO_AES256 = 2, - SM_ALGO_SCP11b = 3, - SM_ALGO_3DES = 256, /* 2.x: coded as 0 in DO C0 */ - SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */ -}; - -static struct pgp_supported_ec_curves { - struct sc_object_id oid; - size_t size; - struct sc_object_id oid_binary; -} ec_curves[] = { - {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, - {{0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, -1}}}, /* ansiX9p256r1 */ - {{{1, 3, 132, 0, 34, -1}}, 384, - {{0x2b, 0x81, 0x04, 0x00, 0x22, -1}}}, /* ansiX9p384r1 */ - {{{1, 3, 132, 0, 35, -1}}, 521, - {{0x2b, 0x81, 0x04, 0x00, 0x23, -1}}}, /* ansiX9p521r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256, - {{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07, -1}}}, /* brainpoolP256r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384, - {{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b, -1}}}, /* brainpoolP384r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512, - {{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d, -1}}}, /* brainpoolP512r1 */ - {{{-1}}, 0, {{0x0}}} /* This entry must not be touched. */ -}; - -static struct pgp_supported_ec_curves_gnuk { - struct sc_object_id oid; - size_t size; - struct sc_object_id oid_binary; -} ec_curves_gnuk[] = { - {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, - {{0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, -1}}}, /* ansiX9p256r1 */ - {{{1, 3, 132, 0, 10, -1}}, 256, - {{0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A, -1}}}, /* secp256k1 */ - /*{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256, - {{0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01, -1}}}, //cv25519 - {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256, - {{0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01, -1}}}, // ed25519 */ - {{{-1}}, 0, {{0x0}}} /* This entry must not be touched. */ -}; - -typedef struct pgp_blob { - struct pgp_blob * next; /* pointer to next sibling */ - struct pgp_blob * parent; /* pointer to parent */ - struct do_info *info; - - sc_file_t * file; - unsigned int id; - int status; - - unsigned char * data; - unsigned int len; - struct pgp_blob * files; /* pointer to 1st child */ -} pgp_blob_t; - -struct do_info { - unsigned int id; /* ID of the DO in question */ - - enum _type type; /* constructed DO or not */ - enum _access access; /* R/W access levels for the DO */ - - /* function to get the DO from the card: - * only != NULL is DO if readable and not only a part of a constructed DO */ - int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t); - /* function to write the DO to the card: - * only != NULL if DO is writeable under some conditions */ - int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t); -}; - static int pgp_get_card_features(sc_card_t *card); static int pgp_finish(sc_card_t *card); static void pgp_iterate_blobs(pgp_blob_t *, int, void (*func)()); static int pgp_get_blob(sc_card_t *card, pgp_blob_t *blob, unsigned int id, pgp_blob_t **ret); -static pgp_blob_t * pgp_new_blob(sc_card_t *, pgp_blob_t *, unsigned int, sc_file_t *); +static pgp_blob_t *pgp_new_blob(sc_card_t *, pgp_blob_t *, unsigned int, sc_file_t *); static void pgp_free_blob(pgp_blob_t *); -static int pgp_get_pubkey(sc_card_t *, unsigned int, - u8 *, size_t); -static int pgp_get_pubkey_pem(sc_card_t *, unsigned int, - u8 *, size_t); - -/* The DO holding X.509 certificate is constructed but does not contain a child DO. - * We should notice this when building fake file system later. */ -#define DO_CERT 0x7f21 -/* Control Reference Template of private keys. Ref: Section 4.3.3.7 of OpenPGP card v2 spec. - * Here we treat them as DOs just for convenience */ -#define DO_SIGN 0xb600 -#define DO_ENCR 0xb800 -#define DO_AUTH 0xa400 -/* These DOs do not exist. They are defined and used just for ease of implementation */ -#define DO_SIGN_SYM 0xb601 -#define DO_ENCR_SYM 0xb801 -#define DO_AUTH_SYM 0xa401 -/* Private DOs */ -#define DO_PRIV1 0x0101 -#define DO_PRIV2 0x0102 -#define DO_PRIV3 0x0103 -#define DO_PRIV4 0x0104 -/* Cardholder information DOs */ -#define DO_CARDHOLDER 0x65 -#define DO_NAME 0x5b -#define DO_LANG_PREF 0x5f2d -#define DO_SEX 0x5f35 +static int pgp_get_pubkey(sc_card_t *, unsigned int, u8 *, size_t); +static int pgp_get_pubkey_pem(sc_card_t *, unsigned int, u8 *, size_t); -/* Maximum length for response buffer when reading pubkey. - * This value is calculated with 4096-bit key length */ -#define MAXLEN_RESP_PUBKEY 527 -/* Gnuk only supports 1 key length (2048 bit) */ -#define MAXLEN_RESP_PUBKEY_GNUK 271 - -/* Maximal size of a DO: - * v2.0+: max. certificate size it at bytes 5-6 of Extended Capabilities DO 00C0 - * v3.0+: max. special DO size is at bytes 7-8 of Extended Capabilities DO 00C0 - * Theoretically we should have the 64k, but we currently limit to 8k. */ -#define MAX_OPENPGP_DO_SIZE 8192 - -static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ +static pgp_do_info_t pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ { 0x004f, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL }, { 0x005b, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x005e, SIMPLE, READ_ALWAYS | WRITE_PIN3, sc_get_data, sc_put_data }, @@ -316,7 +179,7 @@ static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ { 0, 0, 0, NULL, NULL }, }; -static struct do_info pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ +static pgp_do_info_t pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ { 0x00d9, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x00da, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x00db, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, @@ -400,31 +263,10 @@ static struct do_info pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ { 0, 0, 0, NULL, NULL }, }; -static struct do_info *pgp33_objects = pgp34_objects + 9; -static struct do_info *pgp30_objects = pgp34_objects + 10; -static struct do_info *pgp21_objects = pgp34_objects + 15; -static struct do_info *pgp20_objects = pgp34_objects + 16; - - -#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) - -struct pgp_priv_data { - pgp_blob_t *mf; - pgp_blob_t *current; /* currently selected file */ - - enum _version bcd_version; - struct do_info *pgp_objects; - - enum _card_state state; /* card state */ - enum _ext_caps ext_caps; /* extended capabilities */ - - enum _sm_algo sm_algo; /* Secure Messaging algorithm */ - - size_t max_challenge_size; - size_t max_cert_size; - - sc_security_env_t sec_env; -}; +static pgp_do_info_t *pgp33_objects = pgp34_objects + 9; +static pgp_do_info_t *pgp30_objects = pgp34_objects + 10; +static pgp_do_info_t *pgp21_objects = pgp34_objects + 15; +static pgp_do_info_t *pgp20_objects = pgp34_objects + 16; /** @@ -445,8 +287,6 @@ get_full_pgp_aid(sc_card_t *card, sc_file_t *file) } -#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) - /** * ABI: check if card's ATR matches one of driver's * or if the OpenPGP application is present on the card. @@ -515,7 +355,7 @@ pgp_init(sc_card_t *card) struct pgp_priv_data *priv; sc_path_t path; sc_file_t *file = NULL; - struct do_info *info; + pgp_do_info_t *info; int r, i; LOG_FUNC_CALLED(card->ctx); @@ -728,7 +568,7 @@ static int pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_t *key_info) { struct sc_object_id oid; - unsigned int j; + unsigned int j, r; if (blob == NULL || blob->data == NULL || blob->len == 0 || blob->id < 0x00c1 || blob->id > 0x00c3 || key_info == NULL) @@ -755,20 +595,37 @@ pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_ /* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA */ key_info->algorithm = blob->data[0]; - sc_init_oid(&oid); - /* Create copy of oid from blob */ - for (j=0; j < (blob->len-1) && j < SC_MAX_OBJECT_ID_OCTETS; j++) { - oid.value[j] = blob->data[j+1]; /* ignore first byte of blob (algo ID) */ + /* last byte is only set if pubkey import is supported, empty otherwise*/ + if (blob->data[blob->len-1] == SC_OPENPGP_KEYFORMAT_EC_STDPUB){ + if (blob->len < 3) + return SC_ERROR_INCORRECT_PARAMETERS; + key_info->u.ec.oid_len = blob->len - 2; + key_info->u.ec.keyformat = SC_OPENPGP_KEYFORMAT_EC_STDPUB; + } + else { + if (blob->len < 2) + return SC_ERROR_INCORRECT_PARAMETERS; + key_info->u.ec.oid_len = blob->len - 1; + key_info->u.ec.keyformat = SC_OPENPGP_KEYFORMAT_EC_STD; } + /* Create copy of oid from blob */ + sc_init_oid(&oid); + r = sc_asn1_decode_object_id(&blob->data[1], key_info->u.ec.oid_len, &oid); + + /* decoding failed, return sc_asn1_decode_object_id error code */ + if (r > 0){ + return r; + } /* compare with list of supported ec_curves */ for (j=0; ec_curves[j].oid.value[0] >= 0; j++){ - if (sc_compare_oid(&ec_curves[j].oid_binary, &oid)){ + if (sc_compare_oid(&ec_curves[j].oid, &oid)){ key_info->u.ec.oid = ec_curves[j].oid; key_info->u.ec.key_length = ec_curves[j].size; break; } } + break; default: return SC_ERROR_NOT_IMPLEMENTED; @@ -838,6 +695,9 @@ pgp_get_card_features(sc_card_t *card) card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; } + /* v1.1 & v2.x: special DOs are limited to 254 bytes */ + priv->max_specialDO_size = 254; + if ((pgp_get_blob(card, priv->mf, 0x006e, &blob6e) >= 0) && (pgp_get_blob(card, blob6e, 0x0073, &blob73) >= 0)) { @@ -888,6 +748,9 @@ pgp_get_card_features(sc_card_t *card) priv->sm_algo = blob->data[1]; if ((priv->sm_algo == SM_ALGO_NONE) && (priv->ext_caps & EXT_CAP_SM)) priv->sm_algo = SM_ALGO_UNKNOWN; + + /* v3.0+: max. size of special DOs is at bytes 7-8 */ + priv->max_specialDO_size = bebytes2ushort(blob->data + 6); } if (priv->bcd_version >= OPENPGP_CARD_3_3 && (blob->len >= 10)) { /* v3.3+: MSE for key numbers 2(DEC) and 3(AUT) supported */ @@ -1019,7 +882,7 @@ pgp_set_blob(pgp_blob_t *blob, const u8 *data, size_t len) * The Access Control is derived from the DO access permission. **/ static void -pgp_attach_acl(sc_card_t *card, sc_file_t *file, struct do_info *info) +pgp_attach_acl(sc_card_t *card, sc_file_t *file, pgp_do_info_t *info) { unsigned int method = SC_AC_NONE; unsigned long key_ref = SC_AC_KEY_REF_NONE; @@ -1096,7 +959,7 @@ pgp_new_blob(sc_card_t *card, pgp_blob_t *parent, unsigned int file_id, if ((blob = calloc(1, sizeof(pgp_blob_t))) != NULL) { struct pgp_priv_data *priv = DRVDATA(card); - struct do_info *info; + pgp_do_info_t *info; blob->file = file; @@ -1406,11 +1269,11 @@ pgp_find_blob(sc_card_t *card, unsigned int tag) /** * Internal: get info for a specific tag. */ -static struct do_info * +static pgp_do_info_t * pgp_get_info_by_tag(sc_card_t *card, unsigned int tag) { struct pgp_priv_data *priv = DRVDATA(card); - struct do_info *info; + pgp_do_info_t *info; for (info = priv->pgp_objects; (info != NULL) && (info->id > 0); info++) if (tag == info->id) @@ -1656,13 +1519,16 @@ static int pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) { struct pgp_priv_data *priv = DRVDATA(card); - pgp_blob_t *blob, *mod_blob, *exp_blob, *pubkey_blob; - sc_pkcs15_pubkey_t pubkey; - u8 *data; - size_t len; + pgp_blob_t *blob, *mod_blob, *exp_blob, *pubkey_blob, *blob6e, *blob73, *aa_blob; + sc_pkcs15_pubkey_t p15pubkey; + sc_cardctl_openpgp_keygen_info_t key_info; + unsigned int aa_tag = 0; + u8 *data = NULL; + size_t len = 0; int r; sc_log(card->ctx, "called, tag=%04x\n", tag); + memset(&p15pubkey, 0, sizeof(p15pubkey)); if ((r = pgp_get_blob(card, priv->mf, tag & 0xFFFE, &blob)) < 0 || (r = pgp_get_blob(card, blob, 0x7F49, &blob)) < 0) @@ -1674,28 +1540,61 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) && (r = pgp_read_blob(card, mod_blob)) >= 0 && (r = pgp_read_blob(card, exp_blob)) >= 0) { - memset(&pubkey, 0, sizeof(pubkey)); - - pubkey.algorithm = SC_ALGORITHM_RSA; - pubkey.u.rsa.modulus.data = mod_blob->data; - pubkey.u.rsa.modulus.len = mod_blob->len; - pubkey.u.rsa.exponent.data = exp_blob->data; - pubkey.u.rsa.exponent.len = exp_blob->len; + p15pubkey.algorithm = SC_ALGORITHM_RSA; + p15pubkey.u.rsa.modulus.data = mod_blob->data; + p15pubkey.u.rsa.modulus.len = mod_blob->len; + p15pubkey.u.rsa.exponent.data = exp_blob->data; + p15pubkey.u.rsa.exponent.len = exp_blob->len; + r = sc_pkcs15_encode_pubkey(card->ctx, &p15pubkey, &data, &len); } /* ECC */ else if ((r = pgp_get_blob(card, blob, 0x0086, &pubkey_blob)) >= 0 && (r = pgp_read_blob(card, pubkey_blob)) >= 0) { - memset(&pubkey, 0, sizeof(pubkey)); + p15pubkey.algorithm = SC_ALGORITHM_EC; + p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data; + p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len; - pubkey.algorithm = SC_ALGORITHM_EC; - pubkey.u.ec.ecpointQ.value = pubkey_blob->data; - pubkey.u.ec.ecpointQ.len = pubkey_blob->len; + switch(tag & 0xFFFE) { + case DO_SIGN: aa_tag = 0x00C1; break; + case DO_ENCR: aa_tag = 0x00C2; break; + case DO_AUTH: aa_tag = 0x00C3; break; + default: r = SC_ERROR_INCORRECT_PARAMETERS; + } + + /* Get EC parameters from Algorithm Attribute if present */ + + if (aa_tag && ((r = pgp_get_blob(card, priv->mf, 0x006e, &blob6e)) >= 0) && + ((r = pgp_get_blob(card, blob6e, 0x0073, &blob73)) >= 0) && + ((r = pgp_get_blob(card, blob73, aa_tag, &aa_blob)) >= 0) && + ((r = pgp_parse_algo_attr_blob(aa_blob, &key_info)) >= 0)) { + + if ((r = sc_encode_oid(card->ctx, &key_info.u.ec.oid, + &p15pubkey.u.ec.params.der.value, + &p15pubkey.u.ec.params.der.len)) == 0) { + p15pubkey.u.ec.params.type = 1; + r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len); + } + } else + sc_log(card->ctx, "Unable to find Algorithm Attribute for EC curve OID"); } else LOG_TEST_RET(card->ctx, r, "error getting elements"); - r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len); + /* clean up anything we may have set in p15pubkey that can not be freed */ + if (p15pubkey.algorithm == SC_ALGORITHM_RSA) { + p15pubkey.u.rsa.modulus.data = NULL; + p15pubkey.u.rsa.modulus.len = 0; + p15pubkey.u.rsa.exponent.data = NULL; + p15pubkey.u.rsa.exponent.len = 0; + } else + if (p15pubkey.algorithm == SC_ALGORITHM_EC) { + p15pubkey.u.ec.ecpointQ.value = NULL; + p15pubkey.u.ec.ecpointQ.len = 0; + /* p15pubkey.u.ec.params.der and named_curve will be freed by sc_pkcs15_erase_pubkey */ + } + sc_pkcs15_erase_pubkey(&p15pubkey); + LOG_TEST_RET(card->ctx, r, "public key encoding failed"); if (len > buf_len) @@ -1865,7 +1764,7 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len) { struct pgp_priv_data *priv = DRVDATA(card); pgp_blob_t *affected_blob = NULL; - struct do_info *dinfo = NULL; + pgp_do_info_t *dinfo = NULL; int r; LOG_FUNC_CALLED(card->ctx); @@ -2611,7 +2510,7 @@ pgp_update_pubkey_blob(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in struct pgp_priv_data *priv = DRVDATA(card); pgp_blob_t *pk_blob; unsigned int blob_id = 0; - sc_pkcs15_pubkey_t pubkey; + sc_pkcs15_pubkey_t p15pubkey; u8 *data = NULL; size_t len; int r; @@ -2636,25 +2535,25 @@ pgp_update_pubkey_blob(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in /* encode pubkey */ /* RSA */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){ - memset(&pubkey, 0, sizeof(pubkey)); - pubkey.algorithm = SC_ALGORITHM_RSA; - pubkey.u.rsa.modulus.data = key_info->u.rsa.modulus; - pubkey.u.rsa.modulus.len = BYTES4BITS(key_info->u.rsa.modulus_len); - pubkey.u.rsa.exponent.data = key_info->u.rsa.exponent; - pubkey.u.rsa.exponent.len = BYTES4BITS(key_info->u.rsa.exponent_len); + memset(&p15pubkey, 0, sizeof(p15pubkey)); + p15pubkey.algorithm = SC_ALGORITHM_RSA; + p15pubkey.u.rsa.modulus.data = key_info->u.rsa.modulus; + p15pubkey.u.rsa.modulus.len = BYTES4BITS(key_info->u.rsa.modulus_len); + p15pubkey.u.rsa.exponent.data = key_info->u.rsa.exponent; + p15pubkey.u.rsa.exponent.len = BYTES4BITS(key_info->u.rsa.exponent_len); } /* ECC */ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){ - memset(&pubkey, 0, sizeof(pubkey)); - pubkey.algorithm = SC_ALGORITHM_EC; - pubkey.u.ec.ecpointQ.value = key_info->u.ec.ecpoint; - pubkey.u.ec.ecpointQ.len = key_info->u.ec.ecpoint_len; + memset(&p15pubkey, 0, sizeof(p15pubkey)); + p15pubkey.algorithm = SC_ALGORITHM_EC; + p15pubkey.u.ec.ecpointQ.value = key_info->u.ec.ecpoint; + p15pubkey.u.ec.ecpointQ.len = key_info->u.ec.ecpoint_len; } else LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len); + r = sc_pkcs15_encode_pubkey(card->ctx, &p15pubkey, &data, &len); LOG_TEST_RET(card->ctx, r, "Cannot encode pubkey"); sc_log(card->ctx, "Updating blob %04X's content.", blob_id); @@ -3076,11 +2975,18 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info componentnames[0] = "private key"; comp_to_add = 1; - /* TODO ECC import with public key, if necessary as denoted in algorithm caps*/ + /* import public key as well */ + if (key_info->u.ec.keyformat == SC_OPENPGP_KEYFORMAT_EC_STDPUB){ + components[1] = key_info->u.ec.ecpointQ; + componentlens[1] = key_info->u.ec.ecpointQ_len; + componenttags[1] = 0x99; + componentnames[1] = "public key"; + comp_to_add = 2; + } /* validate */ - if ((key_info->u.ec.ecpoint == NULL || key_info->u.ec.ecpoint_len == 0)){ - sc_log(ctx, "Error: ecpoint required!"); + if ((key_info->u.ec.ecpointQ == NULL || key_info->u.ec.ecpointQ_len == 0)){ + sc_log(ctx, "Error: ecpointQ required!"); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); } @@ -3184,23 +3090,23 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid key ID; must be 1, 2, or 3"); - /* we just support standard key format */ - switch (key_info->u.rsa.keyformat) { - case SC_OPENPGP_KEYFORMAT_RSA_STD: - case SC_OPENPGP_KEYFORMAT_RSA_STDN: - break; - - case SC_OPENPGP_KEYFORMAT_RSA_CRT: - case SC_OPENPGP_KEYFORMAT_RSA_CRTN: - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); - - default: - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - } - /* set algorithm attributes */ /* RSA */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){ + /* we just support standard key format */ + switch (key_info->u.rsa.keyformat) { + case SC_OPENPGP_KEYFORMAT_RSA_STD: + case SC_OPENPGP_KEYFORMAT_RSA_STDN: + break; + + case SC_OPENPGP_KEYFORMAT_RSA_CRT: + case SC_OPENPGP_KEYFORMAT_RSA_CRTN: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + + default: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } + /* we only support exponent of maximum 32 bits */ if (key_info->u.rsa.e_len > SC_OPENPGP_MAX_EXP_BITS) { sc_log(card->ctx, @@ -3228,9 +3134,11 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info) memset(&pubkey, 0, sizeof(pubkey)); pubkey.key_id = key_info->key_id; pubkey.algorithm = key_info->algorithm; - if (key_info->u.ec.ecpoint && key_info->u.ec.ecpoint_len){ - pubkey.u.ec.ecpoint = key_info->u.ec.ecpoint; - pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpoint_len; + if (key_info->u.ec.ecpointQ && key_info->u.ec.ecpointQ_len){ + pubkey.u.ec.ecpoint = key_info->u.ec.ecpointQ; + pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpointQ_len; + pubkey.u.ec.oid = key_info->u.ec.oid; + pubkey.u.ec.oid_len = key_info->u.ec.oid_len; } else LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS); diff --git a/src/libopensc/card-openpgp.h b/src/libopensc/card-openpgp.h new file mode 100644 index 00000000..00c2f90a --- /dev/null +++ b/src/libopensc/card-openpgp.h @@ -0,0 +1,192 @@ +/* + * card-openpgp.h: Support for OpenPGP card + * + * Copyright (C) 2020 Peter Marschall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CARD_OPENPGP_H +#define _CARD_OPENPGP_H + +/* + * The OpenPGP card doesn't have a file system, instead everything + * is stored in data objects that are accessed through GET/PUT. + * + * However, much inside OpenSC's pkcs15 implementation is based on + * the assumption that we have a file system. So we fake one here. + * + * Selecting the MF causes us to select the OpenPGP AID. + * + * Everything else is mapped to "file" IDs. + */ + +typedef enum _pgp_do_type { /* DO type */ + SIMPLE = SC_FILE_TYPE_WORKING_EF, + CONSTRUCTED = SC_FILE_TYPE_DF +} pgp_do_type_t; + +typedef enum _pgp_version { /* 2-byte BCD-alike encoded version number */ + OPENPGP_CARD_1_0 = 0x0100, + OPENPGP_CARD_1_1 = 0x0101, + OPENPGP_CARD_2_0 = 0x0200, + OPENPGP_CARD_2_1 = 0x0201, + OPENPGP_CARD_2_2 = 0x0202, + OPENPGP_CARD_3_0 = 0x0300, + OPENPGP_CARD_3_1 = 0x0301, + OPENPGP_CARD_3_2 = 0x0302, + OPENPGP_CARD_3_3 = 0x0303, + OPENPGP_CARD_3_4 = 0x0304, +} pgp_version_t; + +typedef enum _pgp_access { /* access flags for the respective DO/file */ + READ_NEVER = 0x0010, + READ_PIN1 = 0x0011, + READ_PIN2 = 0x0012, + READ_PIN3 = 0x0014, + READ_ALWAYS = 0x0018, + READ_MASK = 0x00FF, + WRITE_NEVER = 0x1000, + WRITE_PIN1 = 0x1100, + WRITE_PIN2 = 0x1200, + WRITE_PIN3 = 0x1400, + WRITE_ALWAYS = 0x1800, + WRITE_MASK = 0x1F00 +} pgp_access_t; + +typedef enum _pgp_ext_caps { /* extended capabilities/features: bit flags */ + EXT_CAP_ALG_ATTR_CHANGEABLE = 0x0004, + EXT_CAP_PRIVATE_DO = 0x0008, + EXT_CAP_C4_CHANGEABLE = 0x0010, + EXT_CAP_KEY_IMPORT = 0x0020, + EXT_CAP_GET_CHALLENGE = 0x0040, + EXT_CAP_SM = 0x0080, + EXT_CAP_LCS = 0x0100, + EXT_CAP_CHAINING = 0x1000, + EXT_CAP_APDU_EXT = 0x2000, + EXT_CAP_MSE = 0x4000 +} pgp_ext_caps_t; + +typedef enum _pgp_card_state { + CARD_STATE_UNKNOWN = 0x00, + CARD_STATE_INITIALIZATION = 0x03, + CARD_STATE_ACTIVATED = 0x05 +} pgp_card_state_t; + +typedef enum _pgp_sm_algo { + SM_ALGO_NONE = 0, /* SM not supported */ + SM_ALGO_AES128 = 1, + SM_ALGO_AES256 = 2, + SM_ALGO_SCP11b = 3, + SM_ALGO_3DES = 256, /* 2.x: coded as 0 in DO C0 */ + SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */ +} pgp_sm_algo_t; + +typedef struct _pgp_do_info { + unsigned int id; /* ID of the DO in question */ + + pgp_do_type_t type; /* constructed DO or not */ + pgp_access_t access; /* R/W access levels for the DO */ + + /* function to get the DO from the card: + * only != NULL is DO if readable and not only a part of a constructed DO */ + int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t); + /* function to write the DO to the card: + * only != NULL if DO is writeable under some conditions */ + int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t); +} pgp_do_info_t; + +typedef struct pgp_blob { + struct pgp_blob *next; /* pointer to next sibling */ + struct pgp_blob *parent; /* pointer to parent */ + pgp_do_info_t *info; + + sc_file_t *file; + unsigned int id; + int status; + + unsigned char *data; + unsigned int len; + struct pgp_blob *files; /* pointer to 1st child */ +} pgp_blob_t; + + +/* The DO holding X.509 certificate is constructed but does not contain a child DO. + * We should notice this when building fake file system later. */ +#define DO_CERT 0x7f21 +/* Control Reference Template of private keys. Ref: Section 4.3.3.7 of OpenPGP card v2 spec. + * Here we treat them as DOs just for convenience */ +#define DO_SIGN 0xb600 +#define DO_ENCR 0xb800 +#define DO_AUTH 0xa400 +/* These DOs do not exist. They are defined and used just for ease of implementation */ +#define DO_SIGN_SYM 0xb601 +#define DO_ENCR_SYM 0xb801 +#define DO_AUTH_SYM 0xa401 +/* Private DOs */ +#define DO_PRIV1 0x0101 +#define DO_PRIV2 0x0102 +#define DO_PRIV3 0x0103 +#define DO_PRIV4 0x0104 +/* Cardholder information DOs */ +#define DO_CARDHOLDER 0x65 +#define DO_NAME 0x5b +#define DO_LANG_PREF 0x5f2d +#define DO_SEX 0x5f35 + + +/* Maximum length for response buffer when reading pubkey. + * This value is calculated with 4096-bit key length */ +#define MAXLEN_RESP_PUBKEY 527 +/* Gnuk only supports 1 key length (2048 bit) */ +#define MAXLEN_RESP_PUBKEY_GNUK 271 + +/* Maximal size of a DO: + * v2.0+: max. certificate size it at bytes 5-6 of Extended Capabilities DO 00C0 + * v3.0+: max. special DO size is at bytes 7-8 of Extended Capabilities DO 00C0 + * Theoretically we should have the 64k, but we currently limit to 8k. */ +#define MAX_OPENPGP_DO_SIZE 8192 + + +typedef struct _pgp_ec_curves { + struct sc_object_id oid; + size_t size; +} pgp_ec_curves_t; + + +#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) + +struct pgp_priv_data { + pgp_blob_t *mf; + pgp_blob_t *current; /* currently selected file */ + + pgp_version_t bcd_version; + pgp_do_info_t *pgp_objects; + + pgp_card_state_t state; /* card state */ + pgp_ext_caps_t ext_caps; /* extended capabilities */ + + pgp_sm_algo_t sm_algo; /* Secure Messaging algorithm */ + + size_t max_challenge_size; + size_t max_cert_size; + size_t max_specialDO_size; + + sc_security_env_t sec_env; +}; + +#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) + +#endif diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 6e5e1166..4c885a78 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -465,49 +465,6 @@ piv_find_obj_by_containerid(sc_card_t *card, const u8 * str) LOG_FUNC_RETURN(card->ctx, -1); } -/* - * If ptr == NULL, just return the size of the tag and length and data - * otherwise, store tag and length at **ptr, and increment - */ - -static size_t -put_tag_and_len(unsigned int tag, size_t len, u8 **ptr) -{ - int i; - u8 *p; - - if (len < 128) { - i = 2; - } else if (len < 256) { - i = 3; - } else { - i = 4; - } - - if (ptr) { - p = *ptr; - *p++ = (u8)tag; - switch (i) { - case 2: - *p++ = len; - break; - case 3: - *p++ = 0x81; - *p++ = len; - break; - case 4: - *p++ = 0x82; - *p++ = (u8) (len >> 8); - *p++ = (u8) (len & 0xff); - break; - } - *ptr = p; - } else { - i += len; - } - return i; -} - /* * Send a command and receive data. There is always something to send. * Used by GET DATA, PUT DATA, GENERAL AUTHENTICATE @@ -618,10 +575,11 @@ static int piv_generate_key(sc_card_t *card, p = tagbuf; - put_tag_and_len(0xAC, out_len, &p); - - memcpy(p, outdata, out_len); - p+=out_len; + r = sc_asn1_put_tag(0xAC, outdata, out_len, tagbuf, sizeof(tagbuf), &p); + if (r != SC_SUCCESS) { + sc_log(card->ctx, "Failed to encode ASN1 tag"); + goto err; + } r = piv_general_io(card, 0x47, 0x00, keydata->key_num, tagbuf, p - tagbuf, rbuf, sizeof rbuf); @@ -889,9 +847,11 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) tag_len = piv_objects[enumtag].tag_len; p = tagbuf; - put_tag_and_len(0x5c, tag_len, &p); - memcpy(p, piv_objects[enumtag].tag_value, tag_len); - p += tag_len; + r = sc_asn1_put_tag(0x5c, piv_objects[enumtag].tag_value, tag_len, tagbuf, sizeof(tagbuf), &p); + if (r != SC_SUCCESS) { + sc_log(card->ctx, "Failed to encode ASN1 tag"); + goto err; + } if (*buf_len == 1 && *buf == NULL) { /* we need to get the length */ u8 rbufinitbuf[8]; /* tag of 53 with 82 xx xx will fit in 4 */ @@ -1222,15 +1182,22 @@ piv_put_data(sc_card_t *card, int tag, const u8 *buf, size_t buf_len) SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); tag_len = piv_objects[tag].tag_len; - sbuflen = put_tag_and_len(0x5c, tag_len, NULL) + buf_len; - if (!(sbuf = malloc(sbuflen))) + sbuflen = sc_asn1_put_tag(0x5c, piv_objects[tag].tag_value, tag_len, NULL, 0, NULL); + if (sbuflen <= 0) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + sbuflen += buf_len; + if (!(sbuf = malloc(sbuflen))) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + } p = sbuf; - put_tag_and_len(0x5c, tag_len, &p); - memcpy(p, piv_objects[tag].tag_value, tag_len); - p += tag_len; + r = sc_asn1_put_tag(0x5c, piv_objects[tag].tag_value, tag_len, sbuf, sbuflen, &p); + if (r != SC_SUCCESS) { + LOG_FUNC_RETURN(card->ctx, r); + } + /* This is safe as we calculated the size of buffer above */ memcpy(p, buf, buf_len); p += buf_len; @@ -1253,31 +1220,39 @@ piv_write_certificate(sc_card_t *card, const u8* buf, size_t count, unsigned lon size_t sbuflen; size_t taglen; - taglen = put_tag_and_len(0x70, count, NULL) - + put_tag_and_len(0x71, 1, NULL) - + put_tag_and_len(0xFE, 0, NULL); + taglen = sc_asn1_put_tag(0x70, buf, count, NULL, 0, NULL) + + sc_asn1_put_tag(0x71, NULL, 1, NULL, 0, NULL) + + sc_asn1_put_tag(0xFE, NULL, 0, NULL, 0, NULL); + if (taglen <= 0) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } - sbuflen = put_tag_and_len(0x53, taglen, NULL); + sbuflen = sc_asn1_put_tag(0x53, NULL, taglen, NULL, 0, NULL); + if (sbuflen <= 0) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } sbuf = malloc(sbuflen); if (sbuf == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); p = sbuf; - put_tag_and_len(0x53, taglen, &p); - - put_tag_and_len(0x70, count, &p); - memcpy(p, buf, count); - p += count; - put_tag_and_len(0x71, 1, &p); + if ((r = sc_asn1_put_tag(0x53, NULL, taglen, sbuf, sbuflen, &p)) != SC_SUCCESS || + (r = sc_asn1_put_tag(0x70, buf, count, p, sbuflen - (p - sbuf), &p)) != SC_SUCCESS || + (r = sc_asn1_put_tag(0x71, NULL, 1, p, sbuflen - (p - sbuf), &p)) != SC_SUCCESS) { + goto out; + } /* Use 01 as per NIST 800-73-3 */ - *p++ = (flags)? 0x01:0x00; /* certinfo, i.e. gzipped? */ - put_tag_and_len(0xFE,0,&p); /* LRC tag */ + *p++ = (flags) ? 0x01 : 0x00; /* certinfo, i.e. gzipped? */ + r = sc_asn1_put_tag(0xFE, NULL, 0, p, sbuflen - (p - sbuf), &p); + if (r != SC_SUCCESS) { + goto out; + } enumtag = piv_objects[priv->selected_obj].enumtag; r = piv_put_data(card, enumtag, sbuf, sbuflen); - if (sbuf) - free(sbuf); +out: + free(sbuf); LOG_FUNC_RETURN(card->ctx, r); } @@ -1610,7 +1585,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card, /* get the encrypted nonce */ r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, rbuf, sizeof rbuf); - if (r < 0) goto err; + if (r < 0) goto err; /* Remove the encompassing outer TLV of 0x7C and get the data */ body = sc_asn1_find_tag(card->ctx, rbuf, @@ -1695,14 +1670,26 @@ static int piv_general_mutual_authenticate(sc_card_t *card, } /* nonce for challenge */ - tmplen = put_tag_and_len(0x81, witness_len, NULL); + tmplen = sc_asn1_put_tag(0x81, NULL, witness_len, NULL, 0, NULL); + if (tmplen <= 0) { + r = SC_ERROR_INTERNAL; + goto err; + } /* plain text witness keep a length separate for the 0x7C tag */ - tmplen += put_tag_and_len(0x80, witness_len, NULL); - tmplen2 = tmplen; + tmplen2 = sc_asn1_put_tag(0x80, NULL, witness_len, NULL, 0, NULL); + if (tmplen2 <= 0) { + r = SC_ERROR_INTERNAL; + goto err; + } + tmplen2 += tmplen; /* outside 7C tag with 81:80 as innards */ - tmplen = put_tag_and_len(0x7C, tmplen, NULL); + tmplen = sc_asn1_put_tag(0x7C, NULL, tmplen, NULL, 0, NULL); + if (tmplen <= 0) { + r = SC_ERROR_INTERNAL; + goto err; + } built_len = tmplen; @@ -1717,20 +1704,28 @@ static int piv_general_mutual_authenticate(sc_card_t *card, p = built; /* Start with the 7C Tag */ - put_tag_and_len(0x7C, tmplen2, &p); + r = sc_asn1_put_tag(0x7C, NULL, tmplen2, p, built_len, &p); + if (r != SC_SUCCESS) { + goto err; + } /* Add the DECRYPTED witness, tag 0x80 */ - put_tag_and_len(0x80, witness_len, &p); - memcpy(p, plain_text, witness_len); - p += witness_len; + r = sc_asn1_put_tag(0x80, plain_text, witness_len, p, built_len - (p - built), &p); + if (r != SC_SUCCESS) { + goto err; + } /* Add the challenge, tag 0x81 */ - put_tag_and_len(0x81, witness_len, &p); - memcpy(p, nonce, witness_len); + r = sc_asn1_put_tag(0x81, nonce, witness_len, p, built_len - (p - built), &p); + if (r != SC_SUCCESS) { + goto err; + } /* Send constructed data */ - r = piv_general_io(card, 0x87, alg_id, key_ref, built,built_len, rbuf, sizeof rbuf); - if (r < 0) goto err; + r = piv_general_io(card, 0x87, alg_id, key_ref, built, built_len, rbuf, sizeof rbuf); + if (r < 0) { + goto err; + } /* Remove the encompassing outer TLV of 0x7C and get the data */ body = sc_asn1_find_tag(card->ctx, rbuf, @@ -1974,19 +1969,27 @@ static int piv_general_external_authenticate(sc_card_t *card, * memcopy the body past the 7C portion * Transmit */ - tmplen = put_tag_and_len(0x82, cypher_text_len, NULL); + tmplen = sc_asn1_put_tag(0x82, NULL, cypher_text_len, NULL, 0, NULL); + if (tmplen <= 0) { + r = SC_ERROR_INTERNAL; + goto err; + } - tmplen = put_tag_and_len(0x7C, tmplen, &p); + r = sc_asn1_put_tag(0x7C, NULL, tmplen, p, output_len, &p); + if (r != SC_SUCCESS) { + goto err; + } /* Build the 0x82 TLV and append to the 7C tag */ - tmplen += put_tag_and_len(0x82, cypher_text_len, &p); - - memcpy(p, cypher_text, cypher_text_len); - p += cypher_text_len; - tmplen += cypher_text_len; + r = sc_asn1_put_tag(0x82, cypher_text, cypher_text_len, p, output_len - (p - output_buf), &p); + if (r != SC_SUCCESS) { + goto err; + } /* Sanity check the lengths again */ - if(output_len != (size_t)tmplen) { + tmplen = sc_asn1_put_tag(0x7C, NULL, tmplen, NULL, 0, NULL) + + sc_asn1_put_tag(0x82, NULL, cypher_text_len, NULL, 0, NULL); + if (output_len != (size_t)tmplen) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Allocated and computed lengths do not match! " "Expected %"SC_FORMAT_LEN_SIZE_T"d, found: %d\n", output_len, tmplen); r = SC_ERROR_INTERNAL; @@ -2283,31 +2286,42 @@ static int piv_validate_general_authentication(sc_card_t *card, u8 * out, size_t outlen) { piv_private_data_t * priv = PIV_DATA(card); - int r; + int r, tmplen, tmplen2; u8 *p; const u8 *tag; size_t taglen; const u8 *body; size_t bodylen; - unsigned int real_alg_id; + unsigned int real_alg_id, op_tag; u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */ + size_t sbuflen = sizeof(sbuf); u8 rbuf[4096]; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); /* should assume large send data */ p = sbuf; - put_tag_and_len(0x7c, (2 + put_tag_and_len(0, datalen, NULL)) , &p); - put_tag_and_len(0x82, 0, &p); + tmplen = sc_asn1_put_tag(0xff, NULL, datalen, NULL, 0, NULL); + tmplen2 = sc_asn1_put_tag(0x82, NULL, 0, NULL, 0, NULL); + if (tmplen <= 0 || tmplen2 <= 0) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + tmplen += tmplen2; + if ((r = sc_asn1_put_tag(0x7c, NULL, tmplen, p, sbuflen, &p)) != SC_SUCCESS || + (r = sc_asn1_put_tag(0x82, NULL, 0, p, sbuflen - (p - sbuf), &p)) != SC_SUCCESS) { + LOG_FUNC_RETURN(card->ctx, r); + } if (priv->operation == SC_SEC_OPERATION_DERIVE - && priv->algorithm == SC_ALGORITHM_EC) - put_tag_and_len(0x85, datalen, &p); - else - put_tag_and_len(0x81, datalen, &p); - - memcpy(p, data, datalen); - p += datalen; + && priv->algorithm == SC_ALGORITHM_EC) { + op_tag = 0x85; + } else { + op_tag = 0x81; + } + r = sc_asn1_put_tag(op_tag, data, datalen, p, sbuflen - (p - sbuf), &p); + if (r != SC_SUCCESS) { + LOG_FUNC_RETURN(card->ctx, r); + } /* * alg_id=06 is a place holder for all RSA keys. @@ -2897,11 +2911,14 @@ piv_process_history(sc_card_t *card) enumtag = PIV_OBJ_RETIRED_X509_1 + *keyref - 0x82; /* now add the cert like another object */ - i2 = put_tag_and_len(0x70,certlen, NULL) - + put_tag_and_len(0x71, 1, NULL) - + put_tag_and_len(0xFE, 0, NULL); - - certobjlen = put_tag_and_len(0x53, i2, NULL); + i2 = sc_asn1_put_tag(0x70, NULL, certlen, NULL, 0, NULL) + + sc_asn1_put_tag(0x71, NULL, 1, NULL, 0, NULL) + + sc_asn1_put_tag(0xFE, NULL, 0, NULL, 0, NULL); + certobjlen = sc_asn1_put_tag(0x53, NULL, i2, NULL, 0, NULL); + if (i2 <= 0 || certobjlen <= 0) { + r = SC_ERROR_INTERNAL; + goto err; + } certobj = malloc(certobjlen); if (certobj == NULL) { @@ -2909,13 +2926,16 @@ piv_process_history(sc_card_t *card) goto err; } cp = certobj; - put_tag_and_len(0x53, i2, &cp); - put_tag_and_len(0x70,certlen, &cp); - memcpy(cp, cert, certlen); - cp += certlen; - put_tag_and_len(0x71, 1,&cp); + if ((r = sc_asn1_put_tag(0x53, NULL, i2, cp, certobjlen, &cp)) != SC_SUCCESS || + (r = sc_asn1_put_tag(0x70, cert, certlen, cp, certobjlen - (cp - certobj), &cp)) != SC_SUCCESS || + (r = sc_asn1_put_tag(0x71, NULL, 1, cp, certobjlen - (cp - certobj), &cp)) != SC_SUCCESS) { + goto err; + } *cp++ = 0x00; - put_tag_and_len(0xFE, 0, &cp); + r = sc_asn1_put_tag(0xFE, NULL, 0, cp, certobjlen - (cp - certobj), &cp); + if (r != SC_SUCCESS) { + goto err; + } priv->obj_cache[enumtag].obj_data = certobj; priv->obj_cache[enumtag].obj_len = certobjlen; diff --git a/src/libopensc/card-setcos.c b/src/libopensc/card-setcos.c index 2d3692cc..859f72fd 100644 --- a/src/libopensc/card-setcos.c +++ b/src/libopensc/card-setcos.c @@ -476,7 +476,7 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file) sc_log(card->ctx, "SetCOS 4.4 PIN refs can only be 1..7\n"); return SC_ERROR_INVALID_ARGUMENTS; } - bCommands_pin[setcos_pin_index_44(pins, sizeof(pins), (int) bNumber)] |= 1 << i; + bCommands_pin[setcos_pin_index_44(pins, sizeof(pins)/sizeof(pins[0]), (int) bNumber)] |= 1 << i; break; case SC_AC_TERM: /* key */ bKeyNumber = bNumber; /* There should be only 1 key */ diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index ac196925..10ddfa05 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -83,6 +83,7 @@ enum { SC_CARDCTL_CARDOS_PUT_DATA_OCI, SC_CARDCTL_CARDOS_PUT_DATA_SECI, SC_CARDCTL_CARDOS_GENERATE_KEY, + SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, /* * Starcos SPK 2.3 specific calls @@ -303,6 +304,16 @@ enum { SC_CARDCTL_GIDS_INITIALIZE, SC_CARDCTL_GIDS_SET_ADMIN_KEY, SC_CARDCTL_GIDS_AUTHENTICATE_ADMIN, + + /* + * IDPrime specific calls + */ + SC_CARDCTL_IDPRIME_BASE = _CTL_PREFIX('I', 'D', 'P'), + SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, + SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, + SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, + SC_CARDCTL_IDPRIME_GET_TOKEN_NAME, + }; enum { @@ -340,6 +351,14 @@ typedef struct sc_cardctl_pkcs11_init_pin { size_t pin_len; } sc_cardctl_pkcs11_init_pin_t; +/* + * Generic cardctl - card driver can examine token info + */ +struct sc_cardctl_parsed_token_info { + unsigned int flags; + struct sc_pkcs15_tokeninfo * tokeninfo; +}; + /* * GPK lock file. * Parent DF of file must be selected. @@ -409,6 +428,15 @@ struct sc_cardctl_cardos_genkey_info { unsigned short fid; }; +struct sc_cardctl_cardos_pass_algo_flags { + unsigned int pass; + unsigned long card_flags; /* from card->flags i.e. user set */ + unsigned long used_flags; /* as set by default */ + unsigned long new_flags; /* set in pkcs15-cardos.c */ + unsigned long ec_flags; /* for EC keys */ + unsigned long ext_flags; /* for EC keys */ +}; + /* * Incrypto34 PIN info */ @@ -952,6 +980,9 @@ typedef struct sc_cardctl_piv_genkey_info_st { #define SC_OPENPGP_KEYFORMAT_RSA_CRT 2 #define SC_OPENPGP_KEYFORMAT_RSA_CRTN 3 +#define SC_OPENPGP_KEYFORMAT_EC_STD 0 +#define SC_OPENPGP_KEYFORMAT_EC_STDPUB 0xFF + #define SC_OPENPGP_MAX_EXP_BITS 0x20 /* maximum exponent length supported in bits */ typedef struct sc_cardctl_openpgp_keygen_info { @@ -959,13 +990,14 @@ typedef struct sc_cardctl_openpgp_keygen_info { u8 algorithm; /* SC_OPENPGP_KEYALGO_... */ union { struct { + u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */ u8 *modulus; /* New-generated pubkey info responded from the card */ size_t modulus_len; /* Length of modulus in bit */ u8 *exponent; size_t exponent_len; /* Length of exponent in bit */ - u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */ } rsa; struct { + u8 keyformat; /* SC_OPENPGP_KEYFORMAT_EC_... */ u8 *ecpoint; size_t ecpoint_len; struct sc_object_id oid; @@ -991,10 +1023,13 @@ typedef struct sc_cardctl_openpgp_keystore_info { size_t n_len; } rsa; struct { + u8 keyformat; /* SC_OPENPGP_KEYFORMAT_EC_... */ u8 *privateD; size_t privateD_len; - u8 *ecpoint; - size_t ecpoint_len; + u8 *ecpointQ; + size_t ecpointQ_len; + struct sc_object_id oid; + u8 oid_len; } ec; } u; time_t creationtime; diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index 24d73c09..8d58fb93 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -47,6 +47,7 @@ enum { SC_CARD_TYPE_CARDOS_CIE_V1, /* Italian CIE (eID) v1 */ SC_CARD_TYPE_CARDOS_M4_4, SC_CARD_TYPE_CARDOS_V5_0, + SC_CARD_TYPE_CARDOS_V5_3, /* flex/cyberflex drivers */ SC_CARD_TYPE_FLEX_BASE = 2000, @@ -234,6 +235,7 @@ enum { /* JPKI cards */ SC_CARD_TYPE_JPKI_BASE = 31000, + /* Coolkey cards */ SC_CARD_TYPE_COOLKEY_BASE = 32000, SC_CARD_TYPE_COOLKEY_GENERIC, @@ -258,6 +260,12 @@ enum { SC_CARD_TYPE_RUTOKEN_ECP_SC, SC_CARD_TYPE_RUTOKEN_LITE, SC_CARD_TYPE_RUTOKEN_LITE_SC, + + /* IDPrime cards */ + SC_CARD_TYPE_IDPRIME_BASE = 37000, + SC_CARD_TYPE_IDPRIME_V1, + SC_CARD_TYPE_IDPRIME_V2, + SC_CARD_TYPE_IDPRIME_GENERIC, }; extern sc_card_driver_t *sc_get_default_driver(void); @@ -301,6 +309,7 @@ extern sc_card_driver_t *sc_get_cac_driver(void); extern sc_card_driver_t *sc_get_cac1_driver(void); extern sc_card_driver_t *sc_get_npa_driver(void); extern sc_card_driver_t *sc_get_esteid2018_driver(void); +extern sc_card_driver_t *sc_get_idprime_driver(void); #ifdef __cplusplus } diff --git a/src/libopensc/compression.c b/src/libopensc/compression.c index 00c7f707..19d1a984 100644 --- a/src/libopensc/compression.c +++ b/src/libopensc/compression.c @@ -51,17 +51,31 @@ static int zerr_to_opensc(int err) { } } static int detect_method(const u8* in, size_t inLen) { - if(inLen > 2 && in[0] == 0x1f && in[1] == 0x8b) { /* GZIP */ - return COMPRESSION_GZIP; - } else if(inLen > 1 /*&& (in[0] & 0x10) == Z_DEFLATED*/) { - /* REALLY SIMPLE ZLIB TEST -- - * Check for the compression method to be set to 8... - * many things can spoof this, but this is ok for now - * */ - return COMPRESSION_ZLIB; - } else { - return COMPRESSION_UNKNOWN; + if (in != NULL && inLen > 1) { + if (in[0] == 0x1f && in[1] == 0x8b) + return COMPRESSION_GZIP; + /* + * A zlib stream has the following structure: + * 0 1 + * +---+---+ + * |CMF|FLG| (more-->) + * +---+---+ + * + * FLG (FLaGs) + * This flag byte is divided as follows: + * + * bits 0 to 4 FCHECK (check bits for CMF and FLG) + * bit 5 FDICT (preset dictionary) + * bits 6 to 7 FLEVEL (compression level) + * + * The FCHECK value must be such that CMF and FLG, when viewed as + * a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), + * is a multiple of 31. + */ + if ((((uint16_t) in[0])*256 + in[1]) % 31 == 0) + return COMPRESSION_ZLIB; } + return COMPRESSION_UNKNOWN; } static int sc_compress_gzip(u8* out, size_t* outLen, const u8* in, size_t inLen) { @@ -101,8 +115,10 @@ static int sc_decompress_gzip(u8* out, size_t* outLen, const u8* in, size_t inLe gz.next_out = out; gz.avail_out = *outLen; + *outLen = 0; + err = inflateInit2(&gz, window_size); - if(err != Z_OK) return zerr_to_opensc(err); + if (err != Z_OK) return zerr_to_opensc(err); err = inflate(&gz, Z_FINISH); if(err != Z_STREAM_END) { inflateEnd(&gz); @@ -134,17 +150,23 @@ int sc_compress(u8* out, size_t* outLen, const u8* in, size_t inLen, int method) } } -int sc_decompress(u8* out, size_t* outLen, const u8* in, size_t inLen, int method) { +int sc_decompress(u8* out, size_t* outLen, const u8* in, size_t inLen, int method) +{ unsigned long zlib_outlen; int rc; - if(method == COMPRESSION_AUTO) { + if (in == NULL || out == NULL) { + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + } + + if (method == COMPRESSION_AUTO) { method = detect_method(in, inLen); - if(method == COMPRESSION_UNKNOWN) { + if (method == COMPRESSION_UNKNOWN) { + *outLen = 0; return SC_ERROR_UNKNOWN_DATA_RECEIVED; } } - switch(method) { + switch (method) { case COMPRESSION_ZLIB: zlib_outlen = *outLen; rc = zerr_to_opensc(uncompress(out, &zlib_outlen, in, inLen)); @@ -224,14 +246,20 @@ static int sc_decompress_zlib_alloc(u8** out, size_t* outLen, const u8* in, size return zerr_to_opensc(err); } -int sc_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method) { - if(method == COMPRESSION_AUTO) { +int sc_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method) +{ + if (in == NULL || out == NULL) { + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + } + + if (method == COMPRESSION_AUTO) { method = detect_method(in, inLen); - if(method == COMPRESSION_UNKNOWN) { + if (method == COMPRESSION_UNKNOWN) { return SC_ERROR_UNKNOWN_DATA_RECEIVED; } } - switch(method) { + + switch (method) { case COMPRESSION_ZLIB: return sc_decompress_zlib_alloc(out, outLen, in, inLen, 0); case COMPRESSION_GZIP: diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index 40f573ed..4c5adc6e 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -128,6 +128,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = { { "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver }, { "westcos", (void *(*)(void)) sc_get_westcos_driver }, { "esteid2018", (void *(*)(void)) sc_get_esteid2018_driver }, + { "idprime", (void *(*)(void)) sc_get_idprime_driver }, /* Here should be placed drivers that need some APDU transactions in the * driver's `match_card()` function. */ diff --git a/src/libopensc/cwa14890.c b/src/libopensc/cwa14890.c index a8b0664d..d28242d0 100644 --- a/src/libopensc/cwa14890.c +++ b/src/libopensc/cwa14890.c @@ -647,23 +647,22 @@ static int cwa_prepare_external_auth(sc_card_t * card, if (bnsub) BN_free(bnsub); if (buf1) { - memset(buf1, 0, 128); + sc_mem_clear(buf1, 128); free(buf1); } if (buf2) { - memset(buf2, 0, 128); + sc_mem_clear(buf2, 128); free(buf2); } if (buf3) { - memset(buf3, 0, 128); + sc_mem_clear(buf3, 128); free(buf3); } if (sha_buf) { - memset(sha_buf, 0, 74 + 32 + 8 + 1 + 7); + sc_mem_clear(sha_buf, 74 + 32 + 8 + 1 + 7); free(sha_buf); } if (sha_data) { - memset(sha_data, 0, SHA_DIGEST_LENGTH); free(sha_data); } @@ -770,15 +769,14 @@ static int cwa_compute_session_keys(sc_card_t * card) compute_session_keys_end: if (kseed) { - memset(kseed, 0, 32); + sc_mem_clear(kseed, 32); free(kseed); } if (data) { - memset(data, 0, 32 + 4); + sc_mem_clear(data, 32 + 4); free(data); } if (sha_data) { - memset(sha_data, 0, SHA_DIGEST_LENGTH); free(sha_data); } if (res != SC_SUCCESS) diff --git a/src/libopensc/dir.c b/src/libopensc/dir.c index 5a8914d9..6e27293d 100644 --- a/src/libopensc/dir.c +++ b/src/libopensc/dir.c @@ -171,6 +171,8 @@ int sc_enum_apps(sc_card_t *card) sc_format_path("3F002F00", &path); r = sc_select_file(card, &path, &ef_dir); + if (r < 0) + sc_file_free(ef_dir); LOG_TEST_RET(ctx, r, "Cannot select EF.DIR file"); if (ef_dir->type != SC_FILE_TYPE_WORKING_EF) { diff --git a/src/libopensc/ef-atr.c b/src/libopensc/ef-atr.c index c03473d3..1a20c8d2 100644 --- a/src/libopensc/ef-atr.c +++ b/src/libopensc/ef-atr.c @@ -139,7 +139,7 @@ int sc_parse_ef_atr(struct sc_card *card) { struct sc_context *ctx = card->ctx; struct sc_path path; - struct sc_file *file; + struct sc_file *file = NULL; int rv; unsigned char *buf = NULL; size_t size; @@ -148,7 +148,7 @@ int sc_parse_ef_atr(struct sc_card *card) sc_format_path("3F002F01", &path); rv = sc_select_file(card, &path, &file); - LOG_TEST_RET(ctx, rv, "Cannot select EF(ATR) file"); + LOG_TEST_GOTO_ERR(ctx, rv, "Cannot select EF(ATR) file"); if (file->size) { size = file->size; @@ -156,18 +156,22 @@ int sc_parse_ef_atr(struct sc_card *card) size = 1024; } buf = malloc(size); - if (!buf) - LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Memory allocation error"); + if (!buf) { + rv = SC_ERROR_OUT_OF_MEMORY; + LOG_TEST_GOTO_ERR(ctx, rv, "Memory allocation error"); + } rv = sc_read_binary(card, 0, buf, size, 0); - LOG_TEST_RET(ctx, rv, "Cannot read EF(ATR) file"); + LOG_TEST_GOTO_ERR(ctx, rv, "Cannot read EF(ATR) file"); rv = sc_parse_ef_atr_content(card, buf, rv); - LOG_TEST_RET(ctx, rv, "EF(ATR) parse error"); + LOG_TEST_GOTO_ERR(ctx, rv, "EF(ATR) parse error"); - free(buf); + rv = SC_SUCCESS; + +err: sc_file_free(file); - - LOG_FUNC_RETURN(ctx, SC_SUCCESS); + free(buf); + LOG_FUNC_RETURN(ctx, rv); } void sc_free_ef_atr(sc_card_t *card) diff --git a/src/libopensc/errors.c b/src/libopensc/errors.c index 5b58b7ea..03cb79dd 100644 --- a/src/libopensc/errors.c +++ b/src/libopensc/errors.c @@ -45,8 +45,8 @@ const char *sc_strerror(int error) "Message too long (keypad)", "Timeout while waiting for event from card reader", "Unresponsive card (correctly inserted?)", - "Reader detached (hotplug device?)", - "Reader reattached (hotplug device?)", + "Reader detached", + "Reader reattached", "Reader in use by another application" }; const int rdr_base = -SC_ERROR_READER; diff --git a/src/libopensc/internal-winscard.h b/src/libopensc/internal-winscard.h index edc315ca..6b2a21c5 100644 --- a/src/libopensc/internal-winscard.h +++ b/src/libopensc/internal-winscard.h @@ -100,6 +100,7 @@ typedef unsigned __int8 uint8_t; #define SCARD_E_NOT_TRANSACTED 0x80100016 /**< An attempt was made to end a non-existent transaction. */ #define SCARD_E_READER_UNAVAILABLE 0x80100017 /**< The specified reader is not currently available for use. */ #define SCARD_E_NO_SERVICE 0x8010001D /**< The Smart card resource manager is not running. */ +#define SCARD_E_SERVICE_STOPPED 0x8010001E /**< The smart card resource manager has shut down. */ #define SCARD_E_NO_READERS_AVAILABLE 0x8010002E /**< Cannot find a smart card reader. */ #define SCARD_W_UNRESPONSIVE_CARD 0x80100066 /**< The smart card is not responding to a reset. */ #define SCARD_W_UNPOWERED_CARD 0x80100067 /**< Power has been removed from the smart card, so that further communication is not possible. */ diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h index 5fd9c185..3aa86a00 100644 --- a/src/libopensc/internal.h +++ b/src/libopensc/internal.h @@ -117,6 +117,12 @@ unsigned short bebytes2ushort(const u8 *buf); * @return the converted value */ unsigned short lebytes2ushort(const u8 *buf); +/** + * Convert 4 bytes in little endian order into an unsigned long + * @param buf the byte array of 4 bytes + * @return the converted value + */ +unsigned long lebytes2ulong(const u8 *buf); #define BYTES4BITS(num) (((num) + 7) / 8) /* number of bytes necessary to hold 'num' bits */ diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 2f989b44..7f155b0e 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -374,13 +374,36 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file, file->type = SC_FILE_TYPE_DF; break; default: + file->type = SC_FILE_TYPE_UNKNOWN; type = "unknown"; break; } sc_log(ctx, " type: %s", type); sc_log(ctx, " EF structure: %d", byte & 0x07); sc_log(ctx, " tag 0x82: 0x%02x", byte); - if (SC_SUCCESS != sc_file_set_type_attr(file, &byte, 1)) + + /* if possible, get additional information for non-DFs */ + if (file->type != SC_FILE_TYPE_DF) { + /* record length for fixed size records */ + if (length > 2 && byte & 0x02) { + file->record_length = (length > 3) + ? bebytes2ushort(p+2) + : p[2]; + sc_log(ctx, " record length: %"SC_FORMAT_LEN_SIZE_T"u", + file->record_length); + } + + /* number of records */ + if (length > 4) { + file->record_count = (length > 5) + ? bebytes2ushort(p+4) + : p[4]; + sc_log(ctx, " records: %"SC_FORMAT_LEN_SIZE_T"u", + file->record_count); + } + } + + if (SC_SUCCESS != sc_file_set_type_attr(file, p, length)) sc_log(ctx, "Warning: Could not set file attributes"); } break; diff --git a/src/libopensc/log.h b/src/libopensc/log.h index 527281f2..4648643d 100644 --- a/src/libopensc/log.h +++ b/src/libopensc/log.h @@ -37,6 +37,7 @@ enum { SC_LOG_DEBUG_SM, /* secure messaging */ SC_LOG_DEBUG_ASN1, /* asn1.c */ SC_LOG_DEBUG_MATCH, /* card matching */ + SC_LOG_DEBUG_PIN, /* PIN commands */ }; #define SC_COLOR_FG_RED 0x0001 diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index fab47975..c2e7dcda 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -107,12 +107,13 @@ extern "C" { * must support at least one of them, and exactly one of them must be selected * for a given operation. */ #define SC_ALGORITHM_RSA_RAW 0x00000001 -#define SC_ALGORITHM_RSA_PADS 0x0000001F +#define SC_ALGORITHM_RSA_PADS 0x0000003F #define SC_ALGORITHM_RSA_PAD_NONE 0x00000001 #define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 /* PKCS#1 v1.5 padding */ #define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004 #define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008 #define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* PKCS#1 v2.0 PSS */ +#define SC_ALGORITHM_RSA_PAD_OAEP 0x00000020 /* PKCS#1 v2.0 OAEP */ /* If the card is willing to produce a cryptogram with the following * hash values, set these flags accordingly. The interpretation of the hash @@ -212,17 +213,17 @@ extern "C" { /* Event masks for sc_wait_for_event() */ #define SC_EVENT_CARD_INSERTED 0x0001 #define SC_EVENT_CARD_REMOVED 0x0002 -#define SC_EVENT_CARD_EVENTS SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED +#define SC_EVENT_CARD_EVENTS (SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED) #define SC_EVENT_READER_ATTACHED 0x0004 #define SC_EVENT_READER_DETACHED 0x0008 -#define SC_EVENT_READER_EVENTS SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED +#define SC_EVENT_READER_EVENTS (SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED) #define MAX_FILE_SIZE 65535 struct sc_supported_algo_info { unsigned int reference; unsigned int mechanism; - struct sc_object_id *parameters; /* OID for ECC, NULL for RSA */ + struct sc_object_id parameters; /* OID for ECC */ unsigned int operations; struct sc_object_id algo_id; unsigned int algo_ref; @@ -1085,18 +1086,25 @@ int sc_disconnect_card(struct sc_card *card); int sc_detect_card_presence(sc_reader_t *reader); /** - * Waits for an event on readers. Note: only the event is detected, - * there is no update of any card or other info. - * NOTE: Only PC/SC backend implements this. - * @param ctx pointer to a Context structure - * @param event_mask The types of events to wait for; this should - * be ORed from one of the following - * SC_EVENT_CARD_REMOVED - * SC_EVENT_CARD_INSERTED - * SC_EVENT_READER_ATTACHED - * @param event_reader (OUT) the reader on which the event was detected, or NULL if new reader + * Waits for an event on readers. + * + * In case of a reader event (attached/detached), the list of reader is + * adjusted accordingly. This means that a subsequent call to + * `sc_ctx_detect_readers()` is not needed. + * + * @note Only PC/SC backend implements this. An infinite timeout on macOS does + * not detect reader events (use a limited timeout instead if needed). + * + * @param ctx (IN) pointer to a Context structure + * @param event_mask (IN) The types of events to wait for; this should + * be ORed from one of the following: + * - SC_EVENT_CARD_REMOVED + * - SC_EVENT_CARD_INSERTED + * - SC_EVENT_READER_ATTACHED + * - SC_EVENT_READER_DETACHED + * @param event_reader (OUT) the reader on which the event was detected * @param event (OUT) the events that occurred. This is also ORed - * from the SC_EVENT_CARD_* constants listed above. + * from the constants listed above. * @param timeout Amount of millisecs to wait; -1 means forever * @retval < 0 if an error occurred * @retval = 0 if a an event happened diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c index 4a8fc17b..5bcb2bb8 100644 --- a/src/libopensc/padding.c +++ b/src/libopensc/padding.c @@ -499,6 +499,7 @@ int sc_get_encoding_flags(sc_context_t *ctx, /* Use the card's raw RSA capability on the padded input */ *sflags = SC_ALGORITHM_RSA_PAD_NONE; *pflags = iflags; + /* TODO emulate the OAEP decryption */ } else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) { diff --git a/src/libopensc/pkcs15-actalis.c b/src/libopensc/pkcs15-actalis.c index 9ded751e..201d40f8 100644 --- a/src/libopensc/pkcs15-actalis.c +++ b/src/libopensc/pkcs15-actalis.c @@ -252,7 +252,13 @@ static int sc_pkcs15emu_actalis_init(sc_pkcs15_card_t * p15card) j++; cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE; - sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); + r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); + if (r < 0) { + sc_log(card->ctx, "Failed to add cert obj r=%d", r); + free(cert); + free(compCert); + continue; + } free(cert); free(compCert); diff --git a/src/libopensc/pkcs15-atrust-acos.c b/src/libopensc/pkcs15-atrust-acos.c index c4b19e80..09a80fa0 100644 --- a/src/libopensc/pkcs15-atrust-acos.c +++ b/src/libopensc/pkcs15-atrust-acos.c @@ -253,8 +253,7 @@ static int sc_pkcs15emu_atrust_acos_init(sc_pkcs15_card_t *p15card) if (r != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ - if (p15card->file_app) - free(p15card->file_app); + sc_file_free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; diff --git a/src/libopensc/pkcs15-cac.c b/src/libopensc/pkcs15-cac.c index d637dedf..e8c13d5f 100644 --- a/src/libopensc/pkcs15-cac.c +++ b/src/libopensc/pkcs15-cac.c @@ -84,89 +84,6 @@ static const char * cac_get_name(int type) return ("CAC"); } -/* - * These could move to a helper file for other cards that wish to use usage as a way of getting flags - */ - -/* Only certain usages are valid for a given algorithm, return all the usages that the algorithm supports so we - * can use it as a filter for all the public and private key usages */ -static unsigned int -cac_alg_flags_from_algorithm(int algorithm) -{ - switch (algorithm) { - case SC_ALGORITHM_RSA: - return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP | - SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER | - SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP | - SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | - SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; - case SC_ALGORITHM_DSA: - return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN | - SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; -#ifdef SC_ALGORITHM_DH - case SC_ALGORITHM_DH: - return SC_PKCS15_PRKEY_USAGE_DERIVE ; -#endif - case SC_ALGORITHM_EC: - return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| - SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; - case SC_ALGORITHM_GOSTR3410: - return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| - SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; - } - return 0; -} - -/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */ -#define CAC_X509_USAGE_SIGNATURE \ - (SC_X509_DIGITAL_SIGNATURE | \ - SC_X509_NON_REPUDIATION | \ - SC_X509_KEY_CERT_SIGN | \ - SC_X509_CRL_SIGN) -#define CAC_X509_USAGE_DERIVE \ - SC_X509_KEY_AGREEMENT -#define CAC_X509_USAGE_UNWRAP \ - (SC_X509_KEY_ENCIPHERMENT | \ - SC_X509_KEY_AGREEMENT) -#define CAC_X509_USAGE_DECRYPT \ - (SC_X509_DATA_ENCIPHERMENT | \ - SC_X509_ENCIPHER_ONLY) -#define CAC_X509_USAGE_NONREPUDIATION \ - SC_X509_NON_REPUDIATION - -/* map a cert usage and algorithm to public and private key usages */ -static int -cac_map_usage(unsigned int cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation) -{ - unsigned int pub_usage = 0, pr_usage = 0; - unsigned int alg_flags = cac_alg_flags_from_algorithm(algorithm); - - if (cert_usage & CAC_X509_USAGE_SIGNATURE) { - pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; - pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; - } - if (cert_usage & CAC_X509_USAGE_DERIVE) { - pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; - pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; - } - if (cert_usage & (CAC_X509_USAGE_DECRYPT|CAC_X509_USAGE_UNWRAP)) { - pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; - pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT; - } - if (allow_nonrepudiation && (cert_usage & CAC_X509_USAGE_NONREPUDIATION)) { - pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; - pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; - } - /* filter usages algorithm */ - if (pub_usage_ptr) { - *pub_usage_ptr = pub_usage & alg_flags; - } - if (pr_usage_ptr) { - *pr_usage_ptr = pr_usage & alg_flags; - } - return SC_SUCCESS; -} - static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card) { static const pindata pins[] = { @@ -407,9 +324,9 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card) r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL); if (r < 0) { - usage = 0xd9ULL; /* basic default usage */ + usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */ } - cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); + sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n", sc_dump_hex(cert_info.id.value, cert_info.id.len), usage, pubkey_info.usage, prkey_info.usage); diff --git a/src/libopensc/pkcs15-cardos.c b/src/libopensc/pkcs15-cardos.c new file mode 100644 index 00000000..752631ce --- /dev/null +++ b/src/libopensc/pkcs15-cardos.c @@ -0,0 +1,177 @@ +/* + * PKCS15 emulation layer for CardOS cards + * Adapted from PKCS15 emulation layer for IAS/ECC card. + * + * Copyright (C) 2020, Douglas E. Engert + * Copyright (C) 2016, Viktor Tarasov + * Copyright (C) 2004, Bud P. Bruegger + * Copyright (C) 2004, Antonino Iacono + * Copyright (C) 2003, Olaf Kirch + * + * 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 + +#include "internal.h" +#include "pkcs15.h" + + +/* + * Called after sc_pkcs15_bind_internal + * Create new flags based on supported_algos. + */ +static int cardos_fix_token_info(sc_pkcs15_card_t *p15card) +{ + sc_card_t *card; + struct sc_supported_algo_info (*saa)[SC_MAX_SUPPORTED_ALGORITHMS]; + struct sc_supported_algo_info *sa; + struct sc_cardctl_cardos_pass_algo_flags *passed = NULL; + int r = 0; + int i; + + card = p15card->card; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + passed = calloc(1, sizeof(struct sc_cardctl_cardos_pass_algo_flags)); + if (!passed) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + + passed->pass = 1; /* get used_flags and card_flags from card */ + r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); + if (r < 0) { + free(passed); + LOG_FUNC_RETURN(card->ctx, r); + } + + saa = &(p15card->tokeninfo->supported_algos); + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Original Flags: 0x%8.8lx card->flags:0x%8.8lx", passed->used_flags, passed->card_flags); + + if (passed->card_flags) { /* user forced the flags, use them */ + passed->new_flags = passed->card_flags; /* from card_atr flags */ + } else { + + for (i = 0, sa = saa[0]; i < SC_MAX_SUPPORTED_ALGORITHMS; i++, sa++) { + + if (sa->reference == 0 && sa->reference == 0 && sa->mechanism == 0 + && sa->operations == 0 && sa->algo_ref == 0) + break; + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "supported_algos[%d] mechamism:0x%8.8x", i, sa->mechanism); + switch(sa->mechanism) { + case 0x01 : + /* + * Card appears to use lower 4 bits of reference as key, and upper + * 4 bits as mech for card. + * Also has a bug if mechanism = 1 (CKM_RSA_PKCS1) and reference 0x10 + * bit is set mechanism should be 3 (CKM_RSA_X_509) + * correct the mechanism in tokenInfo + */ + if (sa->reference & 0x10) { + sc_log(card->ctx, "Changeing mechanism to CKM_RSA_X_509 based on reference"); + passed->new_flags |= SC_ALGORITHM_RSA_RAW + | SC_ALGORITHM_RSA_PAD_NONE; + sa->mechanism = 0x03; + } else + passed->new_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; + break; + case 0x03 : + passed->new_flags |= SC_ALGORITHM_RSA_RAW + | SC_ALGORITHM_RSA_PAD_NONE; + break; + case 0x06 : + passed->new_flags |= SC_ALGORITHM_RSA_HASH_SHA1; + break; + case 0x1041: + passed->ec_flags |= SC_ALGORITHM_ECDSA_RAW; + /* no old_ec_flags */ + /* TODO turn on sizes from ec curves OIDS */ + break; + default: + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "UNKNOWN MECH: 0x%8.8x", sa->mechanism); + } + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", + passed->new_flags, passed->ec_flags); + } + + if (passed->new_flags == 0) { + if (p15card->tokeninfo && p15card->tokeninfo->flags & SC_PKCS15_TOKEN_EID_COMPLIANT) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EID_COMPLIANT flag found"); + passed->new_flags = (passed->used_flags & ~SC_ALGORITHM_SPECIFIC_FLAGS) | SC_ALGORITHM_RSA_PAD_PKCS1; + } else + passed->new_flags = passed->used_flags; /* from default cardos_init */ + } + } + + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Final New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", passed->new_flags, passed->ec_flags); + + passed->pass = 2; /* tell card driver to use the new flags */ + r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); + + free(passed); + LOG_FUNC_RETURN(card->ctx, r); +} + +static int +cardos_pkcs15emu_detect_card(sc_pkcs15_card_t *p15card) +{ + if (p15card->card->type < SC_CARD_TYPE_CARDOS_BASE) + return SC_ERROR_WRONG_CARD; + + if (p15card->card->type >= SC_CARD_TYPE_CARDOS_BASE + 1000) + return SC_ERROR_WRONG_CARD; + + return SC_SUCCESS; +} + + +static int +sc_pkcs15emu_cardos_init(struct sc_pkcs15_card *p15card, struct sc_aid *aid) +{ + sc_card_t *card = p15card->card; + int r; + + LOG_FUNC_CALLED(card->ctx); + + r = sc_pkcs15_bind_internal(p15card, aid); + LOG_TEST_RET(card->ctx, r, "sc_pkcs15_bind_internal failed"); + + /* If card has created algorithms, return */ + sc_log(card->ctx, " card->algorithms:%p card->algorithm_count:%d", card->algorithms, card->algorithm_count); + if (!card->algorithms && card->algorithm_count == 0) { + r = cardos_fix_token_info(p15card); + } + + LOG_FUNC_RETURN(card->ctx, r); +} + + +int +sc_pkcs15emu_cardos_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid) +{ + if (cardos_pkcs15emu_detect_card(p15card)) + return SC_ERROR_WRONG_CARD; + + return sc_pkcs15emu_cardos_init(p15card, aid); +} diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c index 8606d14a..7850fad8 100644 --- a/src/libopensc/pkcs15-cert.c +++ b/src/libopensc/pkcs15-cert.c @@ -257,6 +257,8 @@ sc_pkcs15_get_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, { NULL, 0, 0, 0, NULL, NULL } }; + LOG_FUNC_CALLED(ctx); + for (next_ext = cert->extensions, next_ext_len = cert->extensions_len; next_ext_len; ) { /* unwrap the set and point to the next ava */ ext = sc_asn1_skip_tag(ctx, &next_ext, &next_ext_len, @@ -324,6 +326,8 @@ sc_pkcs15_get_bitstring_extension(struct sc_context *ctx, { NULL, 0, 0, 0, NULL, NULL } }; + LOG_FUNC_CALLED(ctx); + r = sc_pkcs15_get_extension(ctx, cert, type, &bit_string, &bit_string_len, is_critical); LOG_TEST_RET(ctx, r, "Get extension error"); @@ -550,6 +554,88 @@ sc_pkcs15_encode_cdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj return r; } +/* Only certain usages are valid for a given algorithm, return all the usages + * that the algorithm supports so we can use it as a filter for all + * the public and private key usages + */ +static unsigned int +sc_pkcs15_alg_flags_from_algorithm(int algorithm) +{ + switch (algorithm) { + case SC_ALGORITHM_RSA: + return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP | + SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER | + SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP | + SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | + SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + case SC_ALGORITHM_DSA: + return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN | + SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; +#ifdef SC_ALGORITHM_DH + case SC_ALGORITHM_DH: + return SC_PKCS15_PRKEY_USAGE_DERIVE ; +#endif + case SC_ALGORITHM_EC: + return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| + SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + case SC_ALGORITHM_GOSTR3410: + return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| + SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + } + return 0; +} + +/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */ +#define SC_PKCS15_X509_USAGE_SIGNATURE \ + (SC_X509_DIGITAL_SIGNATURE | \ + SC_X509_NON_REPUDIATION | \ + SC_X509_KEY_CERT_SIGN | \ + SC_X509_CRL_SIGN) +#define SC_PKCS15_X509_USAGE_DERIVE \ + SC_X509_KEY_AGREEMENT +#define SC_PKCS15_X509_USAGE_UNWRAP \ + (SC_X509_KEY_ENCIPHERMENT | \ + SC_X509_KEY_AGREEMENT) +#define SC_PKCS15_X509_USAGE_DECRYPT \ + (SC_X509_DATA_ENCIPHERMENT | \ + SC_X509_ENCIPHER_ONLY) +#define SC_PKCS15_X509_USAGE_NONREPUDIATION \ + SC_X509_NON_REPUDIATION + +/* map a cert usage and algorithm to public and private key usages */ +int +sc_pkcs15_map_usage(unsigned int cert_usage, int algorithm, + unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, + int allow_nonrepudiation) +{ + unsigned int pub_usage = 0, pr_usage = 0; + unsigned int alg_flags = sc_pkcs15_alg_flags_from_algorithm(algorithm); + + if (cert_usage & SC_PKCS15_X509_USAGE_SIGNATURE) { + pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; + pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; + } + if (cert_usage & SC_PKCS15_X509_USAGE_DERIVE) { + pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; + pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; + } + if (cert_usage & (SC_PKCS15_X509_USAGE_DECRYPT|SC_PKCS15_X509_USAGE_UNWRAP)) { + pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; + pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT; + } + if (allow_nonrepudiation && (cert_usage & SC_PKCS15_X509_USAGE_NONREPUDIATION)) { + pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + } + /* filter usages algorithm */ + if (pub_usage_ptr) { + *pub_usage_ptr = pub_usage & alg_flags; + } + if (pr_usage_ptr) { + *pr_usage_ptr = pr_usage & alg_flags; + } + return SC_SUCCESS; +} void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert) diff --git a/src/libopensc/pkcs15-coolkey.c b/src/libopensc/pkcs15-coolkey.c index a182eca0..414ab2f2 100644 --- a/src/libopensc/pkcs15-coolkey.c +++ b/src/libopensc/pkcs15-coolkey.c @@ -670,9 +670,6 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card) sc_log(card->ctx, "Unknown object type %lu, skipping", obj_class); continue; } - if (obj_info == NULL) { - continue; - } r = sc_pkcs15emu_object_add(p15card, obj_type, &obj_obj, obj_info); if (r != SC_SUCCESS) diff --git a/src/libopensc/pkcs15-dnie.c b/src/libopensc/pkcs15-dnie.c index f4b144e4..92a602c5 100644 --- a/src/libopensc/pkcs15-dnie.c +++ b/src/libopensc/pkcs15-dnie.c @@ -169,7 +169,10 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) } /* Set root path of this application */ + sc_file_free(p15card->file_app); p15card->file_app = sc_file_new(); + if (NULL == p15card->file_app) + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); sc_format_path("3F00", &p15card->file_app->path); /* Load TokenInfo */ diff --git a/src/libopensc/pkcs15-gemsafeGPK.c b/src/libopensc/pkcs15-gemsafeGPK.c index c8d35dad..e13f3b87 100644 --- a/src/libopensc/pkcs15-gemsafeGPK.c +++ b/src/libopensc/pkcs15-gemsafeGPK.c @@ -205,7 +205,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card) u8 sysrec[7]; int num_keyinfo = 0; - keyinfo kinfo[8]; /* will loook for 8 keys */ + keyinfo kinfo[8]; /* will look for 8 keys */ u8 modulus_buf[ 1 + 1024 / 8]; /* tag+modulus */ u8 *cp; char buf[256]; @@ -360,14 +360,14 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card) } if ( gsdata[idx1] == 0x30 && - is_seq(gsdata + idx1, &seq_size1, &seq_len1) && - is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) && - gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 && - gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 && - gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 && - gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 && - gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 && - idx1 + 4 + seq_len1 < file->size) { + is_seq(gsdata + idx1, &seq_size1, &seq_len1) && + is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) && + gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 && + gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 && + gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 && + gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 && + gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 && + idx1 + 4 + seq_len1 < file->size) { /* we have a cert (I hope) */ /* read in rest if needed */ idxlen = idx1 + seq_len1 + 4 - idx2; @@ -386,7 +386,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card) return SC_ERROR_OUT_OF_MEMORY; memcpy(cert_info.value.value, gsdata + idx1, cert_info.value.len); - idx1 = idx1 + cert_info.value.len; + idx1 = idx1 + cert_info.value.len; break; } idx1++; diff --git a/src/libopensc/pkcs15-gemsafeV1.c b/src/libopensc/pkcs15-gemsafeV1.c index 074fedd3..d4280bb0 100644 --- a/src/libopensc/pkcs15-gemsafeV1.c +++ b/src/libopensc/pkcs15-gemsafeV1.c @@ -173,6 +173,7 @@ static int gemsafe_get_cert_len(sc_card_t *card) r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; + sc_file_free(file); /* Initial read */ r = sc_read_binary(card, 0, ibuf, GEMSAFE_READ_QUANTUM, 0); @@ -425,8 +426,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) if (r != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ - if (p15card->file_app) - free(p15card->file_app); + sc_file_free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; diff --git a/src/libopensc/pkcs15-idprime.c b/src/libopensc/pkcs15-idprime.c new file mode 100644 index 00000000..d8826969 --- /dev/null +++ b/src/libopensc/pkcs15-idprime.c @@ -0,0 +1,286 @@ +/* + * partial PKCS15 emulation for IDPrime cards. + * + * We can not use the ISO code, since the EF.DIR and EF.ATR for + * object discovery are missing + * + * Copyright (C) 2019, Red Hat, Inc. + * + * Author: Jakub Jelen + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "internal.h" +#include "cardctl.h" +#include "pkcs15.h" + +#define CERT_LABEL_TEMPLATE "Certificate %d" +#define PUBKEY_LABEL_TEMPLATE "Public key %d" +#define PRIVKEY_LABEL_TEMPLATE "Private key %d" + +static int idprime_detect_card(sc_pkcs15_card_t *p15card) +{ + sc_card_t *card = p15card->card; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + if (card->type < SC_CARD_TYPE_IDPRIME_BASE + || card->type >= SC_CARD_TYPE_IDPRIME_BASE+1000) + return SC_ERROR_INVALID_CARD; + return SC_SUCCESS; +} + +static int sc_pkcs15emu_idprime_init(sc_pkcs15_card_t *p15card) +{ + int r, i; + sc_card_t *card = p15card->card; + sc_serial_number_t serial; + char buf[SC_MAX_SERIALNR * 2 + 1]; + int count; + char *token_name = NULL; + struct sc_pkcs15_auth_info pin_info; + struct sc_pkcs15_object pin_obj; + const char pin_label[] = "PIN"; + const char *pin_id = "11"; + + /* oid for key usage */ + static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }}; + unsigned int usage; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* could read this off card if needed */ + p15card->tokeninfo->label = strdup("IDPrime"); + p15card->tokeninfo->manufacturer_id = strdup("Gemalto"); + + /* + * get serial number + */ + memset(&serial, 0, sizeof(serial)); + r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); + if (r < 0) { + sc_log(card->ctx, "sc_card_ctl rc=%d", r); + p15card->tokeninfo->serial_number = strdup("00000000"); + } else { + sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); + p15card->tokeninfo->serial_number = strdup(buf); + } + /* set pin */ + sc_log(card->ctx, "IDPrime adding pin..."); + memset(&pin_info, 0, sizeof(pin_info)); + memset(&pin_obj, 0, sizeof(pin_obj)); + + pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; + sc_pkcs15_format_id(pin_id, &pin_info.auth_id); + pin_info.attrs.pin.reference = 0x11; + pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED; + pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; + pin_info.attrs.pin.min_length = 4; + pin_info.attrs.pin.stored_length = 0; + pin_info.attrs.pin.max_length = 16; + pin_info.tries_left = -1; + + sc_log(card->ctx, "IDPrime Adding pin with label=%s", pin_label); + strncpy(pin_obj.label, pin_label, SC_PKCS15_MAX_LABEL_SIZE - 1); + pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; + + r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); + if (r < 0) + LOG_FUNC_RETURN(card->ctx, r); + + /* + * get token name if provided + */ + r = sc_card_ctl(card, SC_CARDCTL_IDPRIME_GET_TOKEN_NAME, &token_name); + if (r < 0) { + /* On failure we will get the token name from certificates later */ + sc_log(card->ctx, "sc_card_ctl rc=%d", r); + } else { + free(p15card->tokeninfo->label); + p15card->tokeninfo->label = token_name; + sc_log(card->ctx, "IDPrime setting token label = %s", token_name); + } + /* + * certs, pubkeys and priv keys are related and we assume + * they are in order + * We need to read the cert, get modulus and keylen + * We use those for the pubkey, and priv key objects. + */ + sc_log(card->ctx, "IDPrime adding certs, pub and priv keys..."); + r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects."); + + for (i = 0; i < count; i++) { + struct sc_pkcs15_prkey_info prkey_info; + struct sc_pkcs15_cert_info cert_info; + struct sc_pkcs15_pubkey_info pubkey_info; + struct sc_pkcs15_object cert_obj; + struct sc_pkcs15_object pubkey_obj; + struct sc_pkcs15_object prkey_obj; + sc_pkcs15_der_t cert_der; + sc_pkcs15_cert_t *cert_out = NULL; + + r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, &prkey_info); + LOG_TEST_RET(card->ctx, r, "Can not get next object"); + + memset(&cert_info, 0, sizeof(cert_info)); + memset(&pubkey_info, 0, sizeof(pubkey_info)); + /* prkey_info cleaned by the card_ctl call */ + memset(&cert_obj, 0, sizeof(cert_obj)); + memset(&pubkey_obj, 0, sizeof(pubkey_obj)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + + cert_info.id = prkey_info.id; + pubkey_info.id = prkey_info.id; + cert_info.path = prkey_info.path; + /* For private keys, we no longer care for the path, just + * the key reference later used in the security environment */ + prkey_info.path.len = 0; + prkey_info.path.aid.len = 0; + pubkey_info.key_reference = prkey_info.key_reference; + sc_log(card->ctx, "Key ref r=%x", prkey_info.key_reference); + + pubkey_info.native = 1; + prkey_info.native = 1; + + snprintf(cert_obj.label, SC_PKCS15_MAX_LABEL_SIZE, CERT_LABEL_TEMPLATE, i+1); + snprintf(pubkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PUBKEY_LABEL_TEMPLATE, i+1); + snprintf(prkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PRIVKEY_LABEL_TEMPLATE, i+1); + prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; + sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id); + + r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len); + + if (r) { + sc_log(card->ctx, "No cert found,i=%d", i); + continue; + } + cert_info.path.count = cert_der.len; + + sc_log(card->ctx, + "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n", + cert_der.len, cert_info.path.count, r); + sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len); + + /* 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 */ + } + + /* 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) { + sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r); + if (cert_out != NULL) + sc_pkcs15_free_certificate(cert_out); + free(cert_der.value); + continue; + } + + r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); + if (r < 0) { + sc_log(card->ctx, " Failed to add cert obj r=%d",r); + sc_pkcs15_free_certificate(cert_out); + free(cert_der.value); + continue; + } + /* set the token name to the name of the CN of the first certificate */ + if (!token_name) { + u8 * cn_name = NULL; + size_t cn_len = 0; + static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; + r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject, + cert_out->subject_len, &cn_oid, &cn_name, &cn_len); + if (r == SC_SUCCESS) { + token_name = malloc (cn_len+1); + if (!token_name) { + free(cn_name); + r = SC_ERROR_OUT_OF_MEMORY; + goto fail; + } + memcpy(token_name, cn_name, cn_len); + free(cn_name); + token_name[cn_len] = '\0'; + free(p15card->tokeninfo->label); + p15card->tokeninfo->label = token_name; + } + } + + + r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key, + &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); + if (r < 0) + goto fail; + pubkey_obj.emulated = cert_out->key; + + r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL); + if (r < 0) { + usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */ + } + sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); + sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n", + sc_dump_hex(cert_info.id.value, cert_info.id.len), + usage, pubkey_info.usage, prkey_info.usage); + if (cert_out->key->algorithm != SC_ALGORITHM_RSA) { + sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm); + sc_pkcs15_free_certificate(cert_out); + continue; + } else { + pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; + prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; + sc_log(card->ctx, "adding rsa public key r=%d usage=%x",r, pubkey_info.usage); + r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); + if (r < 0) + goto fail; + sc_log(card->ctx, "adding rsa private key r=%d usage=%x",r, prkey_info.usage); + r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); + if (r < 0) + goto fail; + } + + cert_out->key = NULL; +fail: + sc_pkcs15_free_certificate(cert_out); + if (r < 0) + LOG_FUNC_RETURN(card->ctx, r); /* should not fail */ + + } + r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count); + LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects."); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + +int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card, + struct sc_aid *aid) +{ + sc_card_t *card = p15card->card; + sc_context_t *ctx = card->ctx; + + LOG_FUNC_CALLED(ctx); + + if (idprime_detect_card(p15card)) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_idprime_init(p15card); +} diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c index 28b2b70f..e775e3b4 100644 --- a/src/libopensc/pkcs15-openpgp.c +++ b/src/libopensc/pkcs15-openpgp.c @@ -105,25 +105,30 @@ typedef struct _pgp_manuf_map { } pgp_manuf_map_t; static const pgp_manuf_map_t manuf_map[] = { - { 0x0001, "PPC Card Systems" }, - { 0x0002, "Prism" }, - { 0x0003, "OpenFortress" }, - { 0x0004, "Wewid AB" }, - { 0x0005, "ZeitControl" }, - { 0x0006, "Yubico" }, - { 0x0007, "OpenKMS" }, - { 0x0008, "LogoEmail" }, - { 0x0009, "Fidesmo" }, - { 0x000A, "Dangerous Things" }, - { 0x002A, "Magrathea" }, - { 0x0042, "GnuPG e.V." }, - { 0x1337, "Warsaw Hackerspace" }, - { 0x2342, "warpzone" }, - { 0x63AF, "Trustica" }, - { 0xBD0E, "Paranoidlabs" }, - { 0xF517, "FSIJ" }, - { 0x0000, "test card" }, - { 0xffff, "test card" }, + { 0x0001, "PPC Card Systems" }, + { 0x0002, "Prism" }, + { 0x0003, "OpenFortress" }, + { 0x0004, "Wewid AB" }, + { 0x0005, "ZeitControl" }, + { 0x0006, "Yubico" }, + { 0x0007, "OpenKMS" }, + { 0x0008, "LogoEmail" }, + { 0x0009, "Fidesmo" }, + { 0x000A, "Dangerous Things" }, + { 0x000B, "Feitian Technologies" }, + { 0x002A, "Magrathea" }, + { 0x0042, "GnuPG e.V." }, + { 0x1337, "Warsaw Hackerspace" }, + { 0x2342, "warpzone" }, + { 0x4354, "Confidential Technologies" }, + { 0x5443, "TIF-IT e.V." }, + { 0x63AF, "Trustica" }, + { 0xBA53, "c-base e.V." }, + { 0xBD0E, "Paranoidlabs" }, + { 0xF517, "FSIJ" }, + { 0xF5EC, "F-Secure" }, + { 0x0000, "test card" }, + { 0xffff, "test card" }, { 0, NULL } }; diff --git a/src/libopensc/pkcs15-piv.c b/src/libopensc/pkcs15-piv.c index 5a031f12..c0b873c7 100644 --- a/src/libopensc/pkcs15-piv.c +++ b/src/libopensc/pkcs15-piv.c @@ -1104,7 +1104,7 @@ sc_log(card->ctx, "DEE Adding pin %d label=%s",i, label); if (ckis[i].cert_keyUsage_present) { pubkey_info.usage = ckis[i].pub_usage; } else { - pubkey_info.usage = pubkeys[i].usage_ec; + pubkey_info.usage = pubkeys[i].usage_ec; } pubkey_info.field_length = ckis[i].pubkey_len; diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index ed008ede..a6c05415 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -48,10 +48,18 @@ #include "aux-data.h" /* - * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 + * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 */ #define C_ASN1_SUPPORTED_ALGORITHMS_SIZE (SC_MAX_SUPPORTED_ALGORITHMS + 1) static const struct sc_asn1_entry c_asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE] = { + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, diff --git a/src/libopensc/pkcs15-pteid.c b/src/libopensc/pkcs15-pteid.c index 483fc402..e1ca787f 100644 --- a/src/libopensc/pkcs15-pteid.c +++ b/src/libopensc/pkcs15-pteid.c @@ -163,8 +163,7 @@ static int sc_pkcs15emu_pteid_init(sc_pkcs15_card_t * p15card) if (rv != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ - if (p15card->file_app) - free(p15card->file_app); + sc_file_free(p15card->file_app); p15card->file_app = file; /* Load TokenInfo */ diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 01efb02b..f3f01692 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -851,6 +851,8 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk } 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; + /* This could have been already allocated: avoid memory leak */ + sc_asn1_clear_algorithm_id(pubkey->alg_id); pubkey->alg_id->params = ec_params; } break; diff --git a/src/libopensc/pkcs15-skey.c b/src/libopensc/pkcs15-skey.c index b22e6197..4e58355a 100644 --- a/src/libopensc/pkcs15-skey.c +++ b/src/libopensc/pkcs15-skey.c @@ -28,10 +28,18 @@ #include /* - * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 + * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 */ #define C_ASN1_SUPPORTED_ALGORITHMS_SIZE (SC_MAX_SUPPORTED_ALGORITHMS + 1) static const struct sc_asn1_entry c_asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE] = { + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, diff --git a/src/libopensc/pkcs15-starcert.c b/src/libopensc/pkcs15-starcert.c index f6394faa..e8c670ca 100644 --- a/src/libopensc/pkcs15-starcert.c +++ b/src/libopensc/pkcs15-starcert.c @@ -261,8 +261,7 @@ static int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *p15card) if (r != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ - if (p15card->file_app) - free(p15card->file_app); + sc_file_free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index 31af1260..ecd06b13 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -43,22 +43,24 @@ struct sc_pkcs15_emulator_handler builtin_emulators[] = { { "itacns", sc_pkcs15emu_itacns_init_ex }, { "PIV-II", sc_pkcs15emu_piv_init_ex }, { "cac", sc_pkcs15emu_cac_init_ex }, + { "idprime", sc_pkcs15emu_idprime_init_ex }, { "gemsafeGPK", sc_pkcs15emu_gemsafeGPK_init_ex }, { "gemsafeV1", sc_pkcs15emu_gemsafeV1_init_ex }, { "actalis", sc_pkcs15emu_actalis_init_ex }, { "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex}, { "tccardos", sc_pkcs15emu_tccardos_init_ex }, - { "entersafe", sc_pkcs15emu_entersafe_init_ex }, + { "entersafe", sc_pkcs15emu_entersafe_init_ex }, { "pteid", sc_pkcs15emu_pteid_init_ex }, { "oberthur", sc_pkcs15emu_oberthur_init_ex }, { "sc-hsm", sc_pkcs15emu_sc_hsm_init_ex }, - { "dnie", sc_pkcs15emu_dnie_init_ex }, - { "gids", sc_pkcs15emu_gids_init_ex }, - { "iasecc", sc_pkcs15emu_iasecc_init_ex }, - { "jpki", sc_pkcs15emu_jpki_init_ex }, + { "dnie", sc_pkcs15emu_dnie_init_ex }, + { "gids", sc_pkcs15emu_gids_init_ex }, + { "iasecc", sc_pkcs15emu_iasecc_init_ex }, + { "jpki", sc_pkcs15emu_jpki_init_ex }, { "coolkey", sc_pkcs15emu_coolkey_init_ex }, - { "din66291", sc_pkcs15emu_din_66291_init_ex }, - { "esteid2018", sc_pkcs15emu_esteid2018_init_ex }, + { "din66291", sc_pkcs15emu_din_66291_init_ex }, + { "esteid2018", sc_pkcs15emu_esteid2018_init_ex }, + { "cardos", sc_pkcs15emu_cardos_init_ex }, { NULL, NULL } }; @@ -94,6 +96,8 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card) case SC_CARD_TYPE_PIV_II_NEO: case SC_CARD_TYPE_PIV_II_YUBIKEY4: case SC_CARD_TYPE_ESTEID_2018: + case SC_CARD_TYPE_CARDOS_V5_0: + case SC_CARD_TYPE_CARDOS_V5_3: return 1; default: diff --git a/src/libopensc/pkcs15-syn.h b/src/libopensc/pkcs15-syn.h index 6811b3da..a15e0d95 100644 --- a/src/libopensc/pkcs15-syn.h +++ b/src/libopensc/pkcs15-syn.h @@ -53,6 +53,8 @@ int sc_pkcs15emu_iasecc_init_ex(sc_pkcs15_card_t *, struct sc_aid *); int sc_pkcs15emu_jpki_init_ex(sc_pkcs15_card_t *, struct sc_aid *); int sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); +int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); +int sc_pkcs15emu_cardos_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); struct sc_pkcs15_emulator_handler { const char *name; diff --git a/src/libopensc/pkcs15-tccardos.c b/src/libopensc/pkcs15-tccardos.c index c9a643ae..67692230 100644 --- a/src/libopensc/pkcs15-tccardos.c +++ b/src/libopensc/pkcs15-tccardos.c @@ -50,12 +50,14 @@ static int read_file(struct sc_card *card, const char *file, u8 *buf, sc_format_path(file, &path); r = sc_select_file(card, &path, &fid); - if (r != SC_SUCCESS || !fid) + if (r != SC_SUCCESS) return r; + if (!fid) + return SC_ERROR_INTERNAL; if (fid->size < *len) *len = fid->size; r = sc_read_binary(card, 0, buf, *len, 0); - free(fid); + sc_file_free(fid); if ((size_t)r < *len) return SC_ERROR_INTERNAL; @@ -343,8 +345,7 @@ static int sc_pkcs15_tccardos_init_func(sc_pkcs15_card_t *p15card) if (r != SC_SUCCESS || file == NULL) return SC_ERROR_INTERNAL; /* set the application DF */ - if (p15card->file_app) - free(p15card->file_app); + sc_file_free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index aa541264..c58c34fd 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -64,9 +64,17 @@ static const struct sc_asn1_entry c_asn1_algorithm_info_parameters[3] = { }; /* - * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 + * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 */ static const struct sc_asn1_entry c_asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1] = { + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, @@ -310,7 +318,7 @@ sc_pkcs15_encode_tokeninfo(sc_context_t *ctx, sc_pkcs15_tokeninfo_t *ti, sc_format_asn1_entry(asn1_algo_infos[ii] + 1, &ti->supported_algos[ii].mechanism, &mechanism_len, 1); sc_format_asn1_entry(asn1_algo_infos[ii] + 2, asn1_algo_infos_parameters[ii], NULL, 1); - if (!ti->supported_algos[ii].parameters) { + if (!sc_valid_oid(&ti->supported_algos[ii].parameters)) { sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 0, NULL, NULL, 1); } @@ -966,6 +974,7 @@ sc_pkcs15_bind_internal(struct sc_pkcs15_card *p15card, struct sc_aid *aid) if (err != SC_SUCCESS) sc_log(ctx, "unable to enumerate apps: %s", sc_strerror(err)); } + sc_file_free(p15card->file_app); p15card->file_app = sc_file_new(); if (p15card->file_app == NULL) { err = SC_ERROR_OUT_OF_MEMORY; @@ -1894,6 +1903,11 @@ sc_pkcs15_free_object(struct sc_pkcs15_object *obj) sc_pkcs15_free_prkey_info((sc_pkcs15_prkey_info_t *)obj->data); break; case SC_PKCS15_TYPE_PUBKEY: + /* This is normally passed to framework-pkcs15, + * but if something fails on the way, it would not get freed */ + if (obj->emulated) { + sc_pkcs15_free_pubkey(obj->emulated); + } sc_pkcs15_free_pubkey_info((sc_pkcs15_pubkey_info_t *)obj->data); break; case SC_PKCS15_TYPE_CERT: diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index f2ccc42a..df1435ce 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -754,6 +754,9 @@ int sc_pkcs15_get_name_from_dn(struct sc_context *ctx, const u8 *dn, size_t dn_len, const struct sc_object_id *type, u8 **name, size_t *name_len); +int sc_pkcs15_map_usage(unsigned int cert_usage, int algorithm, + unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, + int allow_nonrepudiation); int sc_pkcs15_get_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, const struct sc_object_id *type, diff --git a/src/libopensc/reader-cryptotokenkit.m b/src/libopensc/reader-cryptotokenkit.m index 7bee8278..3a2b579d 100644 --- a/src/libopensc/reader-cryptotokenkit.m +++ b/src/libopensc/reader-cryptotokenkit.m @@ -577,6 +577,7 @@ static int cryptotokenkit_detect_readers(sc_context_t *ctx) if (j < [slotNames count]) { /* existing reader found; remove it from the list */ [slotNames removeObjectAtIndex:j]; + reader->flags &= ~SC_READER_REMOVED; } else { /* existing reader not found */ reader->flags |= SC_READER_REMOVED; diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index bcba4964..b3da6fc8 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -127,6 +127,9 @@ struct pcsc_global_private_data { SCardTransmit_t SCardTransmit; SCardListReaders_t SCardListReaders; SCardGetAttrib_t SCardGetAttrib; + + sc_reader_t *attached_reader; + sc_reader_t *removed_reader; }; struct pcsc_private_data { @@ -181,7 +184,11 @@ static int pcsc_to_opensc_error(LONG rv) return SC_ERROR_READER_LOCKED; case SCARD_E_NO_READERS_AVAILABLE: return SC_ERROR_NO_READERS_FOUND; + case SCARD_E_UNKNOWN_READER: + return SC_ERROR_READER_DETACHED; + case SCARD_E_NO_SERVICE: + case SCARD_E_SERVICE_STOPPED: /* If the service is (auto)started, there could be readers later */ return SC_ERROR_NO_READERS_FOUND; case SCARD_E_NO_SMARTCARD: @@ -355,7 +362,7 @@ static int refresh_attributes(sc_reader_t *reader) if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) return SC_ERROR_NOT_ALLOWED; - if (priv->reader_state.szReader == NULL) { + if (priv->reader_state.szReader == NULL || reader->ctx->flags & SC_READER_REMOVED) { priv->reader_state.szReader = reader->name; priv->reader_state.dwCurrentState = SCARD_STATE_UNAWARE; priv->reader_state.dwEventState = SCARD_STATE_UNAWARE; @@ -379,12 +386,11 @@ static int refresh_attributes(sc_reader_t *reader) } /* the system could not detect the reader. It means, the prevoiusly attached reader is disconnected. */ - if ( + if (rv == (LONG)SCARD_E_UNKNOWN_READER #ifdef SCARD_E_NO_READERS_AVAILABLE - (rv == (LONG)SCARD_E_NO_READERS_AVAILABLE) || + || rv == (LONG)SCARD_E_NO_READERS_AVAILABLE #endif - (rv == (LONG)SCARD_E_UNKNOWN_READER) || (rv == (LONG)SCARD_E_SERVICE_STOPPED)) { - + || rv == (LONG)SCARD_E_SERVICE_STOPPED) { if (old_flags & SC_READER_CARD_PRESENT) { reader->flags |= SC_READER_CARD_CHANGED; } @@ -1140,7 +1146,7 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) return; rv = gpriv->SCardControl(card_handle, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, feature_buf, sizeof(feature_buf), &feature_len); - if (rv != (LONG)SCARD_S_SUCCESS) { + if (rv != SCARD_S_SUCCESS) { PCSC_TRACE(reader, "SCardControl failed", rv); return; } @@ -1379,6 +1385,8 @@ static int pcsc_detect_readers(sc_context_t *ctx) } sc_log(ctx, "Probing PC/SC readers"); + gpriv->attached_reader = NULL; + gpriv->removed_reader = NULL; do { if (gpriv->pcsc_ctx == (SCARDCONTEXT)-1) { @@ -1396,12 +1404,11 @@ static int pcsc_detect_readers(sc_context_t *ctx) * All readers have disappeared, so mark them as * such so we don't keep polling them over and over. */ - if ( + if (rv == (LONG)SCARD_E_NO_SERVICE #ifdef SCARD_E_NO_READERS_AVAILABLE - (rv == (LONG)SCARD_E_NO_READERS_AVAILABLE) || + || rv == (LONG)SCARD_E_NO_READERS_AVAILABLE #endif - (rv == (LONG)SCARD_E_NO_SERVICE) || (rv == (LONG)SCARD_E_SERVICE_STOPPED)) { - + || rv == (LONG)SCARD_E_SERVICE_STOPPED) { for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) { sc_reader_t *reader = sc_ctx_get_reader(ctx, i); @@ -1411,6 +1418,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) } reader->flags |= SC_READER_REMOVED; + gpriv->removed_reader = reader; } } @@ -1467,8 +1475,14 @@ static int pcsc_detect_readers(sc_context_t *ctx) for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen(reader_name) + 1) { - if (!strcmp(reader->name, reader_name)) + if (!strcmp(reader->name, reader_name)) { + if (reader->flags & SC_READER_REMOVED) { + reader->flags &= ~SC_READER_REMOVED; + gpriv->attached_reader = reader; + refresh_attributes(reader); + } break; + } } if (*reader_name != '\x0') { @@ -1479,8 +1493,11 @@ static int pcsc_detect_readers(sc_context_t *ctx) (reader_buf + reader_buf_size) - next_reader_name); reader_buf_size -= (next_reader_name - reader_name); } else { - /* existing reader not found */ - reader->flags |= SC_READER_REMOVED; + if (!(reader->flags & SC_READER_REMOVED)) { + /* existing reader not found */ + reader->flags |= SC_READER_REMOVED; + gpriv->removed_reader = reader; + } } } @@ -1495,6 +1512,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) _sc_delete_reader(ctx, reader); continue; } + gpriv->attached_reader = reader; /* check for pinpad support early, to allow opensc-tool -l display accurate information */ priv = reader->drv_data; @@ -1546,8 +1564,8 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re LONG rv; SCARD_READERSTATE *rgReaderStates; size_t i; - unsigned int num_watch; - int r = SC_ERROR_INTERNAL; + unsigned int num_watch, count; + int r = SC_ERROR_INTERNAL, detect_readers = 0, detected_hotplug = 0; DWORD dwtimeout; LOG_FUNC_CALLED(ctx); @@ -1565,22 +1583,41 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); /* Find out the current status */ - num_watch = sc_ctx_get_reader_count(ctx); - sc_log(ctx, "Trying to watch %d readers", num_watch); - for (i = 0; i < num_watch; i++) { - rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; - } -#ifndef __APPLE__ - /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ - if (event_mask & SC_EVENT_READER_ATTACHED) { - rgReaderStates[i].szReader = "\\\\?PnP?\\Notification"; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; + num_watch = 0; + count = sc_ctx_get_reader_count(ctx); + for (i = 0; i < count; i++) { + sc_reader_t *reader = sc_ctx_get_reader(ctx, i); + if (reader->flags & SC_READER_REMOVED) + continue; + struct pcsc_private_data *priv = reader->drv_data; + rgReaderStates[num_watch].szReader = reader->name; + if (priv->reader_state.szReader == NULL) { + rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + } else { + rgReaderStates[num_watch].dwCurrentState = priv->reader_state.dwEventState; + } + rgReaderStates[num_watch].dwEventState = SCARD_STATE_UNAWARE; num_watch++; } + sc_log(ctx, "Trying to watch %d reader%s", num_watch, num_watch == 1 ? "" : "s"); + if (event_mask & SC_EVENT_READER_ATTACHED) { +#ifdef __APPLE__ + /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ + sc_log(ctx, "PnP notification not supported"); + /* Always check on new readers as if a hotplug + * event was detected. This overwrites a + * SC_ERROR_EVENT_TIMEOUT if a new reader is + * detected with SC_SUCCESS. */ + detect_readers = 1; + detected_hotplug = 1; +#else + rgReaderStates[num_watch].szReader = "\\\\?PnP?\\Notification"; + rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + rgReaderStates[num_watch].dwEventState = SCARD_STATE_UNAWARE; + num_watch++; + sc_log(ctx, "Trying to detect new readers"); #endif + } } else { rgReaderStates = (SCARD_READERSTATE *)(*reader_states); @@ -1606,14 +1643,14 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re goto out; } -#ifdef __APPLE__ + *event_reader = NULL; + *event = 0; + if (num_watch == 0) { - sc_log(ctx, "No readers available, PnP notification not supported"); - *event_reader = NULL; + sc_log(ctx, "No readers available to be watched"); r = SC_ERROR_NO_READERS_FOUND; goto out; } -#endif rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, 0, rgReaderStates, num_watch); if (rv != SCARD_S_SUCCESS) { @@ -1632,7 +1669,6 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re /* Scan the current state of all readers to see if they * match any of the events we're polling for */ - *event = 0; for (i = 0, rsp = rgReaderStates; i < num_watch; i++, rsp++) { DWORD state, prev_state; sc_log(ctx, "'%s' before=0x%08X now=0x%08X", @@ -1643,51 +1679,72 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re state = rsp->dwEventState; rsp->dwCurrentState = rsp->dwEventState; if (state & SCARD_STATE_CHANGED) { - /* check for hotplug events */ - if (!strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification")) { + if (!strcmp(rsp->szReader, "\\\\?PnP?\\Notification")) { sc_log(ctx, "detected hotplug event"); - *event |= SC_EVENT_READER_ATTACHED; - *event_reader = NULL; - } + /* Windows sends hotplug event on both, attaching and + * detaching a reader. pcscd only sends it in case of + * attaching a reader. We'll detect later in which case we + * are. */ + detect_readers = 1; + detected_hotplug = 1; - if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) { - sc_log(ctx, "card inserted event"); - *event |= SC_EVENT_CARD_INSERTED; - } + /* Windows wants us to manually reset the changed state */ + rsp->dwEventState &= ~SCARD_STATE_CHANGED; - if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) { - sc_log(ctx, "card removed event"); - *event |= SC_EVENT_CARD_REMOVED; - } + /* By default, ignore a hotplug event as if a timout + * occurred, since it may be an unrequested removal or + * false alarm. Just continue to loop and check at the end + * of this function whether we need to return the attached + * reader or not. */ + r = SC_ERROR_EVENT_TIMEOUT; + } else { + sc_reader_t *reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader); + if (reader) { + /* copy the state so we know what to watch out for */ + struct pcsc_private_data *priv = reader->drv_data; + priv->reader_state.dwEventState = state; + priv->reader_state.dwCurrentState = prev_state; + } - if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) { - sc_log(ctx, "reader detached event"); - *event |= SC_EVENT_READER_DETACHED; - } + if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) { + sc_log(ctx, "card inserted event"); + *event |= SC_EVENT_CARD_INSERTED; + } - if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) { - sc_log(ctx, "reader re-attached event"); - *event |= SC_EVENT_READER_ATTACHED; - } + if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) { + sc_log(ctx, "card removed event"); + *event |= SC_EVENT_CARD_REMOVED; + } - if (*event & event_mask) { - sc_log(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader); - *event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader); - r = SC_SUCCESS; - goto out; - } + if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) { + sc_log(ctx, "reader detached event"); + *event |= SC_EVENT_READER_DETACHED; + detect_readers = 1; + } + if ((state & SCARD_STATE_IGNORE) && !(prev_state & SCARD_STATE_IGNORE)) { + sc_log(ctx, "reader detached event"); + *event |= SC_EVENT_READER_DETACHED; + detect_readers = 1; + } + + if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) { + sc_log(ctx, "reader re-attached event"); + *event |= SC_EVENT_READER_ATTACHED; + detect_readers = 1; + } + + if (*event & event_mask) { + sc_log(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader); + *event_reader = reader; + r = SC_SUCCESS; + goto out; + } else { + *event = 0; + } + } } - - /* No match - copy the state so pcscd knows - * what to watch out for */ - /* rsp->dwCurrentState = rsp->dwEventState; */ - } - - if (timeout == 0) { - r = SC_ERROR_EVENT_TIMEOUT; - goto out; } /* Set the timeout if caller wants to time out */ @@ -1699,13 +1756,13 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, dwtimeout, rgReaderStates, num_watch); - if (rv == (LONG) SCARD_E_CANCELLED) { + if (rv == (LONG)SCARD_E_CANCELLED) { /* C_Finalize was called, events don't matter */ r = SC_ERROR_EVENT_TIMEOUT; goto out; } - if (rv == (LONG) SCARD_E_TIMEOUT) { + if (rv == (LONG)SCARD_E_TIMEOUT) { r = SC_ERROR_EVENT_TIMEOUT; goto out; } @@ -1717,12 +1774,54 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re } } out: - if (!reader_states) { - free(rgReaderStates); + /* in case of an error re-detect all readers */ + if (r < 0 && r != SC_ERROR_EVENT_TIMEOUT) + detect_readers = 1; + + if (detect_readers) { + pcsc_detect_readers(ctx); } - else if (*reader_states == NULL) { - sc_log(ctx, "return allocated 'reader states'"); - *reader_states = rgReaderStates; + + if (detected_hotplug) { + if (gpriv->attached_reader) { + if (event_reader && event && !*event) { + /* no other event has been detected, yet */ + *event_reader = gpriv->attached_reader; + *event = SC_EVENT_READER_ATTACHED; + r = SC_SUCCESS; + } + gpriv->attached_reader = NULL; + } else if (gpriv->removed_reader) { + /* Normally, we only check the hotplug event for attached readers. + * However, Windows also notifies on removal. Check, if the latter + * was requested by the caller. */ + if (event_mask & SC_EVENT_READER_DETACHED + && event_reader && event && !*event) { + /* no other event has been detected, yet */ + *event_reader = gpriv->removed_reader; + *event = SC_EVENT_READER_DETACHED; + r = SC_SUCCESS; + } + gpriv->removed_reader = NULL; + } else { + /* false alarm, there was no reader attached or removed, + * avoid re-initialize the reader states by resetting detect_readers */ + detect_readers = 0; + } + } + + if (detect_readers) { + free(rgReaderStates); + if (reader_states && *reader_states) + *reader_states = NULL; + } else { + if (!reader_states) { + free(rgReaderStates); + } + else if (*reader_states == NULL) { + sc_log(ctx, "return allocated reader states"); + *reader_states = rgReaderStates; + } } LOG_FUNC_RETURN(ctx, r); @@ -2411,14 +2510,31 @@ int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_c goto out; } - /* if we already had a reader, delete it */ + if (!gpriv->cardmod) { + ret = SC_ERROR_INTERNAL; + goto out; + } + + /* Only minidriver calls this and only uses one reader */ + /* if we already have a reader, update it */ if (sc_ctx_get_reader_count(ctx) > 0) { - sc_reader_t *oldrdr = list_extract_at(&ctx->readers, 0); - if (oldrdr) - _sc_delete_reader(ctx, oldrdr); + sc_log(ctx, "Reusing the reader"); + sc_reader_t *reader = list_get_at(&ctx->readers, 0); + + if (reader) { + struct pcsc_private_data *priv = reader->drv_data; + priv->pcsc_card =*(SCARDHANDLE *)pcsc_card_handle; + gpriv->pcsc_ctx = *(SCARDCONTEXT *)pcsc_context_handle; + ret = SC_SUCCESS; + goto out; + } else { + ret = SC_ERROR_INTERNAL; + goto out; + } } sc_log(ctx, "Probing PC/SC reader"); + gpriv->attached_reader = NULL; gpriv->pcsc_ctx = *(SCARDCONTEXT *)pcsc_context_handle; card_handle = *(SCARDHANDLE *)pcsc_card_handle; @@ -2434,6 +2550,7 @@ int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_c priv->pcsc_card = card_handle; detect_protocol(reader, card_handle); detect_reader_features(reader, card_handle); + gpriv->attached_reader = reader; } else { _sc_delete_reader(ctx, reader); } diff --git a/src/libopensc/reader-tr03119.c b/src/libopensc/reader-tr03119.c index 009e62a7..0a425a50 100644 --- a/src/libopensc/reader-tr03119.c +++ b/src/libopensc/reader-tr03119.c @@ -40,8 +40,13 @@ #ifndef _BSD_SOURCE #define _BSD_SOURCE /* See feature_test_macros(7) */ #endif +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif +#ifdef HAVE_ENDIAN_H #include #endif +#endif int get_pace_capabilities(u8 *bitmap) { diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 7d014a34..1b957653 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -227,6 +227,16 @@ unsigned short lebytes2ushort(const u8 *buf) | (unsigned short)buf[0]; } +unsigned long lebytes2ulong(const u8 *buf) +{ + if (buf == NULL) + return 0UL; + return (unsigned long)buf[3] << 24 + | (unsigned long)buf[2] << 16 + | (unsigned long)buf[1] << 8 + | (unsigned long)buf[0]; +} + void sc_init_oid(struct sc_object_id *oid) { int ii; @@ -892,7 +902,7 @@ void *sc_mem_secure_alloc(size_t len) len = pages * page_size; } - p = malloc(len); + p = calloc(1, len); if (p == NULL) { return NULL; } @@ -918,7 +928,13 @@ void sc_mem_secure_free(void *ptr, size_t len) void sc_mem_clear(void *ptr, size_t len) { if (len > 0) { -#ifdef ENABLE_OPENSSL +#ifdef HAVE_MEMSET_S + memset_s(ptr, len, 0, len); +#elif _WIN32 + SecureZeroMemory(ptr, len); +#elif HAVE_EXPLICIT_BZERO + explicit_bzero(ptr, len); +#elif ENABLE_OPENSSL OPENSSL_cleanse(ptr, len); #else memset(ptr, 0, len); diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c index bc498678..abe31061 100644 --- a/src/libopensc/sec.c +++ b/src/libopensc/sec.c @@ -192,12 +192,19 @@ int sc_reset_retry_counter(sc_card_t *card, unsigned int type, int ref, int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) { - int r; + int r, debug; if (card == NULL) { return SC_ERROR_INVALID_ARGUMENTS; } LOG_FUNC_CALLED(card->ctx); + + debug = card->ctx->debug; + if (data->cmd != SC_PIN_CMD_GET_INFO + && card->ctx->debug < SC_LOG_DEBUG_PIN) { + card->ctx->debug = 0; + } + if (card->ops->pin_cmd) { r = card->ops->pin_cmd(card, data, tries_left); } else if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) { @@ -244,6 +251,8 @@ int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, sc_log(card->ctx, "Use of pin pad not supported by card driver"); r = SC_ERROR_NOT_SUPPORTED; } + card->ctx->debug = debug; + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } diff --git a/src/libopensc/simpletlv.h b/src/libopensc/simpletlv.h index a9527797..6bcd4f08 100644 --- a/src/libopensc/simpletlv.h +++ b/src/libopensc/simpletlv.h @@ -29,7 +29,6 @@ extern "C" { #endif #include "libopensc/opensc.h" -#include "libopensc/pkcs15.h" /* * Create a tag/length file in Simple TLV based on the val_len content length diff --git a/src/libopensc/types.h b/src/libopensc/types.h index ab5cbded..17035b55 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -52,9 +52,11 @@ typedef unsigned char u8; /* When changing this value, pay attention to the initialization of the ASN1 * static variables that use this macro, like, for example, - * 'c_asn1_supported_algorithms' in src/libopensc/pkcs15.c + * 'c_asn1_supported_algorithms' in src/libopensc/pkcs15.c, + * src/libopensc/pkcs15-prkey.c and src/libopensc/pkcs15-skey.c + * `grep "src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as"' */ -#define SC_MAX_SUPPORTED_ALGORITHMS 8 +#define SC_MAX_SUPPORTED_ALGORITHMS 16 struct sc_lv_data { unsigned char *value; @@ -209,6 +211,7 @@ typedef struct sc_acl_entry { } sc_acl_entry_t; /* File types */ +#define SC_FILE_TYPE_UNKNOWN 0x00 #define SC_FILE_TYPE_DF 0x04 #define SC_FILE_TYPE_INTERNAL_EF 0x03 #define SC_FILE_TYPE_WORKING_EF 0x01 diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c index 8aa38707..639f88bb 100644 --- a/src/minidriver/minidriver.c +++ b/src/minidriver/minidriver.c @@ -69,6 +69,25 @@ #include "cardmod.h" +#define MD_FUNC_CALLED(pCardData, level) do { \ + logprintf(pCardData, level, "MD_Function:%s:%d called\n",__FUNCTION__, __LINE__); \ + } while(0) + + +#define MD_FUNC_CALLED_EXT(pCardData, level) do { \ + logprintf(pCardData, level, "\nP:%lu T:%lu MD_Function:%s:%d called\n", \ + (unsigned long)GetCurrentProcessId(),\ + (unsigned long)GetCurrentThreadId(), \ + __FUNCTION__, __LINE__); \ + } while(0) + +#define MD_FUNC_RETURN(pCardData, level, ...) do { \ + DWORD _ret = __VA_ARGS__; \ + logprintf(pCardData, level,\ + "MD_Function:%s:%d returning with: 0x%08X\n", __FUNCTION__, __LINE__, _ret); \ + return _ret; \ + } while(0) + /* store the instance given at DllMain when attached to access internal resources */ HINSTANCE g_inst; @@ -307,13 +326,11 @@ static DWORD reinit_card(PCARD_DATA pCardData) DWORD r; if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); vs = (VENDOR_SPECIFIC *)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; - - logprintf(pCardData, 2, "trying to reinit card\n"); + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (vs->initialized) { disassociate_card(pCardData); @@ -322,7 +339,7 @@ static DWORD reinit_card(PCARD_DATA pCardData) r = associate_card(pCardData); if (r != SCARD_S_SUCCESS) - return r; + MD_FUNC_RETURN(pCardData, 1, r); r = md_fs_init(pCardData); if (r != SCARD_S_SUCCESS) { @@ -330,10 +347,10 @@ static DWORD reinit_card(PCARD_DATA pCardData) "reinit_card md_fs_init failed, r = 0x%lX\n", (unsigned long)r); disassociate_card(pCardData); - return r; + MD_FUNC_RETURN(pCardData, 1, r); } - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } static BOOL lock(PCARD_DATA pCardData) @@ -369,24 +386,26 @@ static DWORD reinit_card_for(PCARD_DATA pCardData, const char *name) "%s was called, but unable to initialize card, r = %u\n", name, (unsigned int)r); - return r; + MD_FUNC_RETURN(pCardData, 1, r); } static DWORD check_card_status(PCARD_DATA pCardData, const char *name) { VENDOR_SPECIFIC *vs; + MD_FUNC_CALLED(pCardData, 3); + if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 3, SCARD_E_INVALID_PARAMETER); vs = (VENDOR_SPECIFIC *)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 3, SCARD_E_INVALID_PARAMETER); if (vs->initialized) - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 3, SCARD_S_SUCCESS); - return reinit_card_for(pCardData, name); + MD_FUNC_RETURN(pCardData, 3, reinit_card_for(pCardData, name)); } /* @@ -401,27 +420,37 @@ check_card_reader_status(PCARD_DATA pCardData, const char *name) DWORD dwRet; int r; - logprintf(pCardData, 4, "check_reader_status\n"); + logprintf(pCardData, 1, "check_reader_status for %s\n", name); if(!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwRet = check_card_status(pCardData, name); if (dwRet != SCARD_S_SUCCESS) - return dwRet; + MD_FUNC_RETURN(pCardData, 3, dwRet); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if(!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 3, SCARD_E_INVALID_PARAMETER); - logprintf(pCardData, 7, "pCardData->hSCardCtx:0x%08X hScard:0x%08X\n", - (unsigned int)pCardData->hSCardCtx, - (unsigned int)pCardData->hScard); + logprintf(pCardData, 7, "sizeof(size_t):%d sizeof(ULONG_PTR):%d sizeof(__int3264):%d sizeof pCardData->hSCardCtx:%d\n", + sizeof(size_t), sizeof(ULONG_PTR), sizeof(__int3264), sizeof pCardData->hSCardCtx); + + logprintf(pCardData, 1, "pCardData->hSCardCtx:0x%08"SC_FORMAT_LEN_SIZE_T"X hScard:0x%08"SC_FORMAT_LEN_SIZE_T"X\n", + (size_t)pCardData->hSCardCtx, + (size_t)pCardData->hScard); if (pCardData->hSCardCtx != vs->hSCardCtx || pCardData->hScard != vs->hScard) { - logprintf(pCardData, 1, "HANDLES CHANGED from 0x%08X 0x%08X\n", - (unsigned int)vs->hSCardCtx, - (unsigned int)vs->hScard); - return reinit_card_for(pCardData, name); + logprintf(pCardData, 1, "HANDLES CHANGED from vs->hSCardCtx:0x%08"SC_FORMAT_LEN_SIZE_T"X vs->hScard:0x%08"SC_FORMAT_LEN_SIZE_T"X\n", + (size_t)vs->hSCardCtx, + (size_t)vs->hScard); + if (vs->ctx) { + vs->hScard = pCardData->hScard; + vs->hSCardCtx = pCardData->hSCardCtx; + r = sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard); + logprintf(pCardData, 1, "sc_ctx_use_reader returned %d\n", r); + if (r) + MD_FUNC_RETURN(pCardData, 1, SCARD_F_INTERNAL_ERROR); + } } /* This should always work, as BaseCSP should be checking for removal too */ @@ -430,8 +459,8 @@ check_card_reader_status(PCARD_DATA pCardData, const char *name) "check_reader_status r=%d flags 0x%08X\n", r, (unsigned int)vs->reader->flags); if (r < 0) - return md_translate_OpenSC_to_Windows_error(r, - SCARD_F_INTERNAL_ERROR); + MD_FUNC_RETURN(pCardData, 1, + md_translate_OpenSC_to_Windows_error(r, SCARD_F_INTERNAL_ERROR)); if (!(r & SC_READER_CARD_PRESENT)) { /* @@ -440,10 +469,10 @@ check_card_reader_status(PCARD_DATA pCardData, const char *name) * it anyway for completeness */ logprintf(pCardData, 1, "no card present? trying to reinit\n"); - return reinit_card_for(pCardData, name); + MD_FUNC_RETURN(pCardData, 1, reinit_card_for(pCardData, name)); } - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } static DWORD @@ -452,12 +481,14 @@ md_get_pin_by_role(PCARD_DATA pCardData, PIN_ID role, struct sc_pkcs15_object ** VENDOR_SPECIFIC *vs; int rv; + MD_FUNC_CALLED(pCardData, 1); + if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!ret_obj) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* please keep me in sync with _get_auth_object_by_name() in pkcs11/framework-pkcs15.c */ if (role == ROLE_USER) { @@ -505,18 +536,18 @@ md_get_pin_by_role(PCARD_DATA pCardData, PIN_ID role, struct sc_pkcs15_object ** logprintf(pCardData, 2, "cannot get PIN object: unsupported role %u\n", (unsigned int)role); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } if (rv) - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); if (*ret_obj) logprintf(pCardData, 7, "Returning PIN '%.*s' for role %u\n", (int) sizeof (*ret_obj)->label, (*ret_obj)->label, (unsigned int)role); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } static const char * @@ -651,6 +682,7 @@ md_get_config_bool(PCARD_DATA pCardData, char *flag_name, BOOL ret_default) ret = scconf_get_bool(atrblock, flag_name, ret_default) ? TRUE : FALSE; } + logprintf(pCardData, 2, "flag_name:%s:%s\n", flag_name, ret ? "TRUE": "FALSE"); return ret; } @@ -1655,19 +1687,19 @@ md_set_cmapfile(PCARD_DATA pCardData, struct md_file *file) dwret = md_get_pin_by_role(pCardData, ROLE_USER, &vs->pin_objs[ROLE_USER]); if (dwret != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get User PIN object"); + logprintf(pCardData, 2, "Cannot get User PIN object\n"); return dwret; } dwret = md_get_pin_by_role(pCardData, MD_ROLE_USER_SIGN, &vs->pin_objs[MD_ROLE_USER_SIGN]); if (dwret != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get Sign PIN object -- ignored"); + logprintf(pCardData, 2, "Cannot get Sign PIN object -- ignored\n"); vs->pin_objs[MD_ROLE_USER_SIGN] = NULL; } dwret = md_get_pin_by_role(pCardData, ROLE_ADMIN, &vs->pin_objs[ROLE_ADMIN]); if (dwret != SCARD_S_SUCCESS) { - logprintf(pCardData, 2, "Cannot get Admin PIN object -- ignored"); + logprintf(pCardData, 2, "Cannot get Admin PIN object -- ignored\n"); vs->pin_objs[ROLE_ADMIN] = NULL; } @@ -3167,19 +3199,21 @@ DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) VENDOR_SPECIFIC *vs = NULL; CRITICAL_SECTION hScard_lock; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 1, - "\nP:%lu T:%lu pCardData:%p hScard=0x%08X hSCardCtx=0x%08X CardDeleteContext\n", + "\nP:%lu T:%lu pCardData:%p hScard=0x%08"SC_FORMAT_LEN_SIZE_T"X hSCardCtx=0x%08"SC_FORMAT_LEN_SIZE_T"X CardDeleteContext\n", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData, - (unsigned int)pCardData->hScard, - (unsigned int)pCardData->hSCardCtx); + (size_t)pCardData->hScard, + (size_t)pCardData->hSCardCtx); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if(!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); hScard_lock = vs->hScard_lock; EnterCriticalSection(&hScard_lock); @@ -3201,7 +3235,7 @@ DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData) LeaveCriticalSection(&hScard_lock); DeleteCriticalSection(&hScard_lock); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } DWORD WINAPI CardQueryCapabilities(__in PCARD_DATA pCardData, @@ -3209,13 +3243,15 @@ DWORD WINAPI CardQueryCapabilities(__in PCARD_DATA pCardData, { DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "pCardCapabilities=%p\n", pCardCapabilities); if (!pCardData || !pCardCapabilities || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_status(pCardData, "CardQueryCapabilities"); if (dwret != SCARD_S_SUCCESS) { @@ -3230,7 +3266,7 @@ DWORD WINAPI CardQueryCapabilities(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData, @@ -3240,6 +3276,9 @@ DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData, VENDOR_SPECIFIC *vs = NULL; DWORD dwret; struct md_pkcs15_container* cont; + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -3247,7 +3286,7 @@ DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData, (unsigned int)bContainerIndex); if (!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardDeleteContainer"); if (dwret != SCARD_S_SUCCESS) { @@ -3292,7 +3331,7 @@ DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } /** The CardCreateContainerEx function creates a new key container that the @@ -3315,8 +3354,10 @@ DWORD WINAPI CardCreateContainerEx(__in PCARD_DATA pCardData, { DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + if (!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (PinId == ROLE_ADMIN) { dwret = SCARD_W_SECURITY_VIOLATION; @@ -3389,7 +3430,7 @@ DWORD WINAPI CardCreateContainerEx(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } DWORD WINAPI CardCreateContainer(__in PCARD_DATA pCardData, @@ -3399,9 +3440,15 @@ DWORD WINAPI CardCreateContainer(__in PCARD_DATA pCardData, __in DWORD dwKeySize, __in PBYTE pbKeyData) { - return CardCreateContainerEx(pCardData, bContainerIndex, dwFlags, + DWORD dwret; + + MD_FUNC_CALLED(pCardData, 1); + + dwret = CardCreateContainerEx(pCardData, bContainerIndex, dwFlags, dwKeySpec, dwKeySize, pbKeyData, ROLE_USER); + + MD_FUNC_RETURN(pCardData, 1, dwret); } typedef struct { @@ -3422,10 +3469,12 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine pubkey_der.value = NULL; pubkey_der.len = 0; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pContainerInfo || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); ret = check_card_reader_status(pCardData, "CardGetContainerInfo"); if (ret != SCARD_S_SUCCESS) @@ -3676,14 +3725,14 @@ DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContaine } } } - logprintf(pCardData, 7, "returns container(idx:%u) info", + logprintf(pCardData, 7, "returns container(idx:%u) info\n", (unsigned int)bContainerIndex); err: free(pubkey_der.value); unlock(pCardData); - return ret; + MD_FUNC_RETURN(pCardData, 1, ret); } DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData, @@ -3693,6 +3742,9 @@ DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData, __out_opt PDWORD pcAttemptsRemaining) { PIN_ID PinId = 0; + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -3706,12 +3758,12 @@ DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData, PinId = ROLE_ADMIN; } else { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if (pbPin == NULL) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); - return CardAuthenticateEx(pCardData, PinId, CARD_PIN_SILENT_CONTEXT, pbPin, cbPin, NULL, NULL, pcAttemptsRemaining); + MD_FUNC_RETURN(pCardData, 1, CardAuthenticateEx(pCardData, PinId, CARD_PIN_SILENT_CONTEXT, pbPin, cbPin, NULL, NULL, pcAttemptsRemaining)); } @@ -3723,15 +3775,17 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData, DWORD dwret; int rv; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetChallenge\n"); if(!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!ppbChallengeData || !pcbChallengeData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardGetChallenge"); if (dwret != SCARD_S_SUCCESS) { @@ -3768,7 +3822,7 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -3777,11 +3831,14 @@ DWORD WINAPI CardAuthenticateChallenge(__in PCARD_DATA pCardData, __in DWORD cbResponseData, __out_opt PDWORD pcAttemptsRemaining) { + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardAuthenticateChallenge - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } @@ -3796,8 +3853,10 @@ DWORD WINAPI CardUnblockPin(__in PCARD_DATA pCardData, { DWORD r = SCARD_S_SUCCESS; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -3851,7 +3910,7 @@ DWORD WINAPI CardUnblockPin(__in PCARD_DATA pCardData, err: unlock(pCardData); - return r; + MD_FUNC_RETURN(pCardData, 1, r); } @@ -3868,8 +3927,10 @@ DWORD WINAPI CardChangeAuthenticator(__in PCARD_DATA pCardData, DWORD r = SCARD_S_SUCCESS; PIN_ID pinid; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -3917,7 +3978,7 @@ DWORD WINAPI CardChangeAuthenticator(__in PCARD_DATA pCardData, err: unlock(pCardData); - return r; + MD_FUNC_RETURN(pCardData, 1, r); } /* Note: the PIN freshness will be managed by the Base CSP */ @@ -3929,6 +3990,8 @@ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, VENDOR_SPECIFIC* vs = NULL; int rv; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%ld T:%ld pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -3936,7 +3999,7 @@ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, NULLWSTR(pwszUserId), (unsigned long)dwFlags); if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardDeauthenticate"); if (dwret != SCARD_S_SUCCESS) @@ -3964,28 +4027,34 @@ DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } DWORD WINAPI CardCreateDirectory(__in PCARD_DATA pCardData, __in LPSTR pszDirectoryName, __in CARD_DIRECTORY_ACCESS_CONDITION AccessCondition) { + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardCreateDirectory - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } DWORD WINAPI CardDeleteDirectory(__in PCARD_DATA pCardData, __in LPSTR pszDirectoryName) { + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeleteDirectory(%s) - unsupported\n", NULLSTR(pszDirectoryName)); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, @@ -3997,6 +4066,8 @@ DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, struct md_directory *dir = NULL; DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -4006,7 +4077,7 @@ DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, (unsigned long)cbInitialCreationSize, AccessCondition); if (!lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_status(pCardData, "CardCreateFile"); if (dwret != SCARD_S_SUCCESS) @@ -4025,7 +4096,7 @@ DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4039,13 +4110,15 @@ DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, struct md_file *file = NULL; DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardReadFile\n"); if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 2, "pszDirectoryName = %s, pszFileName = %s, dwFlags = %lX, pcbData=%p, ppbData=%p\n", @@ -4093,7 +4166,7 @@ DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4107,8 +4180,10 @@ DWORD WINAPI CardWriteFile(__in PCARD_DATA pCardData, struct md_file *file = NULL; DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -4155,7 +4230,7 @@ DWORD WINAPI CardWriteFile(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, @@ -4165,13 +4240,15 @@ DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, { DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeleteFile(%s, %s) called\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName)); if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardDeleteFile"); if (dwret != SCARD_S_SUCCESS) @@ -4187,7 +4264,7 @@ DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4204,13 +4281,15 @@ DWORD WINAPI CardEnumFiles(__in PCARD_DATA pCardData, struct md_file *file = NULL; size_t offs; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardEnumFiles() directory '%s'\n", NULLSTR(pszDirectoryName)); if (!pCardData || !pmszFileNames || !pdwcbFileName || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags) { logprintf(pCardData, 1, "CardEnumFiles() dwFlags not 'zero' -- %lX\n", @@ -4262,7 +4341,7 @@ DWORD WINAPI CardEnumFiles(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4274,8 +4353,10 @@ DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData, DWORD dwret; struct md_file *file = NULL; + MD_FUNC_CALLED(pCardData, 1); + if(!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -4299,7 +4380,7 @@ DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4308,6 +4389,8 @@ DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags, { DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -4317,7 +4400,7 @@ DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags, (unsigned long)pCardFreeSpaceInfo->dwVersion); if (!pCardData || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_status(pCardData, "CardQueryFreeSpace"); if (dwret != SCARD_S_SUCCESS) @@ -4334,7 +4417,7 @@ DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4345,6 +4428,8 @@ DWORD WINAPI CardQueryKeySizes(__in PCARD_DATA pCardData, { DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -4354,7 +4439,7 @@ DWORD WINAPI CardQueryKeySizes(__in PCARD_DATA pCardData, pKeySizes ? (unsigned long)pKeySizes->dwVersion : 0); if (!pCardData || dwFlags != 0 || dwKeySpec == 0 || !lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_status(pCardData, "CardQueryKeySizes"); if (dwret != SCARD_S_SUCCESS) @@ -4369,7 +4454,7 @@ DWORD WINAPI CardQueryKeySizes(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4386,22 +4471,25 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, struct sc_pkcs15_object *pkey = NULL; struct sc_algorithm_info *alg_info = NULL; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardRSADecrypt\n"); + if (!pCardData || !pInfo || pInfo->pbData == NULL) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (pInfo->dwVersion > CARD_RSA_KEY_DECRYPT_INFO_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if ( pInfo->dwVersion < CARD_RSA_KEY_DECRYPT_INFO_CURRENT_VERSION && pCardData->dwVersion == CARD_DATA_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (pInfo->dwKeySpec != AT_KEYEXCHANGE) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardRSADecrypt"); if (dwret != SCARD_S_SUCCESS) @@ -4573,7 +4661,7 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -4588,18 +4676,20 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __inout PCARD_SIGNING_INFO size_t dataToSignLen = sizeof(dataToSign); sc_pkcs15_object_t *pkey; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardSignData\n"); if (!pCardData || !pInfo) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if ( ( pInfo->dwVersion != CARD_SIGNING_INFO_BASIC_VERSION ) && ( pInfo->dwVersion != CARD_SIGNING_INFO_CURRENT_VERSION ) ) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if ( pInfo->pbData == NULL ) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); switch(pInfo->dwKeySpec) { case AT_SIGNATURE: @@ -4612,7 +4702,7 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __inout PCARD_SIGNING_INFO case AT_ECDHE_P521: break; default: - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, 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; @@ -4858,15 +4948,15 @@ DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __inout PCARD_SIGNING_INFO } logprintf(pCardData, 3, - "CardSignData, dwVersion=%lu, name=%S, hScard=0x%08X, hSCardCtx=0x%08X\n", + "CardSignData, dwVersion=%lu, name=%S, hScard=0x%08"SC_FORMAT_LEN_SIZE_T"X, hSCardCtx=0x%08"SC_FORMAT_LEN_SIZE_T"X\n", (unsigned long)pCardData->dwVersion, NULLWSTR(pCardData->pwszCardName), - (unsigned int)pCardData->hScard, - (unsigned int)pCardData->hSCardCtx); + (size_t)pCardData->hScard, + (size_t)pCardData->hSCardCtx); err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, @@ -4884,25 +4974,27 @@ DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, struct md_dh_agreement* temp = NULL; BYTE i; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardConstructDHAgreement\n"); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pAgreementInfo) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if ( pAgreementInfo->pbPublicKey == NULL ) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (pAgreementInfo->dwVersion > CARD_DH_AGREEMENT_INFO_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if ( pAgreementInfo->dwVersion < CARD_DH_AGREEMENT_INFO_VERSION && pCardData->dwVersion == CARD_DATA_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (!lock(pCardData)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardConstructDHAgreement"); if (dwret != SCARD_S_SUCCESS) @@ -5007,7 +5099,7 @@ DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData, err: unlock(pCardData); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } @@ -5028,6 +5120,8 @@ DWORD WINAPI CardDeriveHashOrHMAC(__in PCARD_DATA pCardData, ULONG i; NCryptBufferDesc* parameters = NULL; + MD_FUNC_CALLED(pCardData, 1); + dwReturn = BCryptOpenAlgorithmProvider(&hAlgorithm, szAlgorithm, NULL, (pbHmacKey?BCRYPT_ALG_HANDLE_HMAC_FLAG:0)); if (dwReturn) { logprintf(pCardData, 0, @@ -5134,7 +5228,7 @@ cleanup: LocalFree(pbBuffer); if (hAlgorithm) BCryptCloseAlgorithmProvider(hAlgorithm, 0); - return dwReturn; + MD_FUNC_RETURN(pCardData, 1, dwReturn); } /* Generic function to perform hash. Could have been OpenSSL but used BCrypt* functions. @@ -5444,18 +5538,21 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDeriveKey\n"); + + MD_FUNC_CALLED(pCardData, 1); + if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pAgreementInfo) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pAgreementInfo->dwVersion) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (pAgreementInfo->dwVersion > CARD_DERIVE_KEY_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (pAgreementInfo->pwszKDF == NULL) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (pAgreementInfo->dwFlags & ~(KDF_USE_SECRET_AS_HMAC_KEY_FLAG | CARD_RETURN_KEY_HANDLE | CARD_BUFFER_SIZE_ONLY)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* according to the documentation, CARD_DERIVE_KEY_CURRENT_VERSION should be equal to 2. In practice it is not 2 but 1 @@ -5466,20 +5563,20 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* check if the agreement index is ok */ if (pAgreementInfo->bSecretAgreementIndex >= vs->allocatedAgreements) { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } agreement = vs->dh_agreements + pAgreementInfo->bSecretAgreementIndex; if (agreement->pbAgreement == NULL) { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if (pAgreementInfo->dwFlags & CARD_RETURN_KEY_HANDLE ) { - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /* find the algorithm, checks parameters */ @@ -5509,7 +5606,7 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, logprintf(pCardData, 0, "CardDeriveKey: unsupported algorithm %S\n", (PWSTR)buffer->pvBuffer); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } break; case KDF_HMAC_KEY: @@ -5527,7 +5624,7 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, case KDF_TLS_PRF_LABEL: if (pbLabel != NULL) { logprintf(pCardData, 0, "CardDeriveKey: got more than one Label\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } pbLabel = (PBYTE)buffer->pvBuffer; dwLabelSize = buffer->cbBuffer; @@ -5535,14 +5632,14 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, case KDF_TLS_PRF_SEED: if (pbSeed != NULL) { logprintf(pCardData, 0, "CardDeriveKey: got more than one Seed\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if (buffer->cbBuffer != 64) { logprintf(pCardData, 0, "CardDeriveKey: invalid seed size %lu\n", buffer->cbBuffer); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } pbSeed = (PBYTE)buffer->pvBuffer; break; @@ -5559,7 +5656,7 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, logprintf(pCardData, 0, "CardDeriveKey: unknown buffer type %lu\n", (parameters->pBuffers + i)->BufferType); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } } } @@ -5574,21 +5671,21 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, else if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_HMAC) == 0) { if (pbHmacKey == NULL) { logprintf(pCardData, 0, "CardDeriveKey: no hhmac key for hmac KDF\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } } else if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_TLS_PRF) == 0) { if (!pbSeed) { logprintf(pCardData, 0, "CardDeriveKey: No seed was provided\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if (!pbLabel) { logprintf(pCardData, 0, "CardDeriveKey: No label was provided\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } } else { logprintf(pCardData, 0, "CardDeriveKey: unsupported KDF %S\n", pAgreementInfo->pwszKDF); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } /* do the job for the KDF Hash & Hmac */ @@ -5600,7 +5697,7 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, logprintf(pCardData, 0, "CardDeriveKey: got an error while deriving the Key (hash or HMAC) 0x%08X\n", (unsigned int)dwReturn); - return dwReturn; + MD_FUNC_RETURN(pCardData, 1, dwReturn); } } else if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_TLS_PRF) == 0) { @@ -5609,14 +5706,14 @@ DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData, logprintf(pCardData, 0, "CardDeriveKey: got an error while deriving the Key (TlsPrf) 0x%08X\n", (unsigned int)dwReturn); - return dwReturn; + MD_FUNC_RETURN(pCardData, 1, dwReturn); } } /*else if (wcscmp(pAgreementInfo->pwszKDF, BCRYPT_KDF_SP80056A_CONCAT ) == 0) { }*/ - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } @@ -5628,31 +5725,34 @@ DWORD WINAPI CardDestroyDHAgreement( VENDOR_SPECIFIC *vs; struct md_dh_agreement* agreement = NULL; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDestroyDHAgreement\n"); + if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (bSecretAgreementIndex >= vs->allocatedAgreements) { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } agreement = vs->dh_agreements + bSecretAgreementIndex; if (agreement->pbAgreement == NULL) { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } SecureZeroMemory(agreement->pbAgreement, agreement->dwSize); pCardData->pfnCspFree(agreement->pbAgreement); agreement->pbAgreement = 0; agreement->dwSize = 0; - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } DWORD WINAPI CardGetChallengeEx(__in PCARD_DATA pCardData, @@ -5661,11 +5761,14 @@ DWORD WINAPI CardGetChallengeEx(__in PCARD_DATA pCardData, __out PDWORD pcbChallengeData, __in DWORD dwFlags) { + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetChallengeEx - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, @@ -5685,17 +5788,19 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, int r; BOOL DisplayPinpadUI = FALSE; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardAuthenticateEx\n"); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardAuthenticateEx"); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); logprintf(pCardData, 2, "CardAuthenticateEx: PinId=%u, dwFlags=0x%08X, cbPinData=%lu, Attempts %s\n", @@ -5704,14 +5809,14 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (PinId >= MD_MAX_PINS) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); pin_obj = vs->pin_objs[PinId]; if (!pin_obj) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); #if 0 /* TODO do we need to return SCARD_E_UNSUPPORTED_FEATURE if the card @@ -5720,22 +5825,22 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) { if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } #endif if (dwFlags & ~(CARD_AUTHENTICATE_GENERATE_SESSION_PIN | CARD_AUTHENTICATE_SESSION_PIN | CARD_PIN_SILENT_CONTEXT)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN && (ppbSessionPin == NULL || pcbSessionPin == NULL)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* using a pin pad */ if (NULL == pbPinData) { if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!(dwFlags & CARD_PIN_SILENT_CONTEXT) && !(vs->ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS)) { DisplayPinpadUI = TRUE; @@ -5824,12 +5929,12 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, if (r == SC_ERROR_AUTH_METHOD_BLOCKED) { if(pcAttemptsRemaining) (*pcAttemptsRemaining) = 0; - return SCARD_W_CHV_BLOCKED; + MD_FUNC_RETURN(pCardData, 1, SCARD_W_CHV_BLOCKED); } if(pcAttemptsRemaining) (*pcAttemptsRemaining) = auth_info->tries_left; - return md_translate_OpenSC_to_Windows_error(r, SCARD_W_WRONG_CHV); + MD_FUNC_RETURN(pCardData, 1, md_translate_OpenSC_to_Windows_error(r, SCARD_W_WRONG_CHV)); } logprintf(pCardData, 2, "Pin code correct.\n"); @@ -5848,7 +5953,7 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, } } - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } @@ -5871,38 +5976,40 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, BOOL DisplayPinpadUI = FALSE; size_t target_len = cbTargetData; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardChangeAuthenticatorEx\n"); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardChangeAuthenticatorEx"); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, 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; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if ((dwFlags & PIN_CHANGE_FLAG_UNBLOCK) && (dwFlags & PIN_CHANGE_FLAG_CHANGEPIN)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags & PIN_CHANGE_FLAG_UNBLOCK && dwAuthenticatingPinId == dwTargetPinId) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwAuthenticatingPinId >= MD_MAX_PINS || dwTargetPinId >= MD_MAX_PINS) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!vs->pin_objs[dwAuthenticatingPinId] || !vs->pin_objs[dwTargetPinId]) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* according to the spec: cRetryCount MUST be zero */ if (cRetryCount) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 2, "CardChangeAuthenticatorEx: AuthenticatingPinId=%u, dwFlags=0x%08X, cbAuthenticatingPinData=%lu, TargetPinId=%u, cbTargetData=%lu, Attempts %s\n", @@ -5915,12 +6022,12 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { if (pbAuthenticatingPinData == NULL || cbAuthenticatingPinData == 0) { logprintf(pCardData, 1, "Invalid current PIN data\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } if (pbTargetData == NULL || cbTargetData == 0) { logprintf(pCardData, 1, "Invalid new PIN data\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } } /* using a pin pad */ @@ -5955,22 +6062,23 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, if (rv == SC_ERROR_AUTH_METHOD_BLOCKED) { if(pcAttemptsRemaining) (*pcAttemptsRemaining) = 0; - return SCARD_W_CHV_BLOCKED; + MD_FUNC_RETURN(pCardData, 1, SCARD_W_CHV_BLOCKED); } if(pcAttemptsRemaining) (*pcAttemptsRemaining) = auth_info->tries_left; - return md_translate_OpenSC_to_Windows_error(rv, SCARD_W_WRONG_CHV); + MD_FUNC_RETURN(pCardData, 1, md_translate_OpenSC_to_Windows_error(rv, SCARD_W_WRONG_CHV)); } logprintf(pCardData, 7, "returns success\n"); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } DWORD WINAPI CardDeauthenticateEx(__in PCARD_DATA pCardData, __in PIN_SET PinId, __in DWORD dwFlags) { + MD_FUNC_CALLED(pCardData, 1); logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), @@ -5979,7 +6087,7 @@ DWORD WINAPI CardDeauthenticateEx(__in PCARD_DATA pCardData, "CardDeauthenticateEx PinId=%u dwFlags=0x%08X\n", (unsigned int)PinId, (unsigned int)dwFlags); - return CardDeauthenticate(pCardData, wszCARD_USER_USER, 0); + MD_FUNC_RETURN(pCardData, 1, CardDeauthenticate(pCardData, wszCARD_USER_USER, 0)); } DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, @@ -5994,42 +6102,44 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, VENDOR_SPECIFIC *vs = NULL; struct md_pkcs15_container *cont = NULL; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetContainerProperty\n"); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_status(pCardData, "CardGetContainerProperty"); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); logprintf(pCardData, 2, "CardGetContainerProperty bContainerIndex=%u, wszProperty=%S, cbData=%lu, dwFlags=0x%08X\n", (unsigned int)bContainerIndex, NULLWSTR(wszProperty), (unsigned long)cbData, (unsigned int)dwFlags); if (!wszProperty) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pbData || !pdwDataLen) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (bContainerIndex >= MD_MAX_KEY_CONTAINERS) - return SCARD_E_NO_KEY_CONTAINER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_NO_KEY_CONTAINER); /* the test for the existence of containers is redundant with the one made in CardGetContainerInfo but CCP_PIN_IDENTIFIER does not do it */ vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); cont = &vs->p15_containers[bContainerIndex]; if (!cont->prkey_obj) { logprintf(pCardData, 7, "Container %u is empty\n", (unsigned int)bContainerIndex); - return SCARD_E_NO_KEY_CONTAINER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_NO_KEY_CONTAINER); } if (wcscmp(CCP_CONTAINER_INFO,wszProperty) == 0) { @@ -6037,10 +6147,10 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData >= sizeof(DWORD)) if (p->dwVersion != CONTAINER_INFO_CURRENT_VERSION && p->dwVersion != 0 ) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; - return CardGetContainerInfo(pCardData,bContainerIndex,0,p); + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); + MD_FUNC_RETURN(pCardData, 1, CardGetContainerInfo(pCardData,bContainerIndex,0,p)); } if (wcscmp(CCP_PIN_IDENTIFIER,wszProperty) == 0) { @@ -6048,7 +6158,7 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); if (cont->prkey_obj->auth_id.len == 0) *p = ROLE_EVERYONE; @@ -6079,10 +6189,10 @@ DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData, logprintf(pCardData, 2, "Return Pin id %u\n", (unsigned int)*p); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } DWORD WINAPI CardSetContainerProperty(__in PCARD_DATA pCardData, @@ -6092,11 +6202,14 @@ DWORD WINAPI CardSetContainerProperty(__in PCARD_DATA pCardData, __in DWORD cbDataLen, __in DWORD dwFlags) { + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardSetContainerProperty - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } @@ -6110,6 +6223,8 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, VENDOR_SPECIFIC *vs; DWORD dwret; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); @@ -6119,29 +6234,29 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, (unsigned long)dwFlags); if (!pCardData || !wszProperty) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!pbData || !pdwDataLen) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); dwret = check_card_reader_status(pCardData, "CardGetProperty"); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (wcscmp(CP_CARD_FREE_SPACE,wszProperty) == 0) { PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo = (PCARD_FREE_SPACE_INFO )pbData; if (pdwDataLen) *pdwDataLen = sizeof(*pCardFreeSpaceInfo); if (cbData < sizeof(*pCardFreeSpaceInfo)) - return SCARD_E_NO_MEMORY; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_NO_MEMORY); dwret = md_free_space(pCardData, pCardFreeSpaceInfo); if (dwret != SCARD_S_SUCCESS) { logprintf(pCardData, 1, "Get free space error"); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } } else if (wcscmp(CP_CARD_CAPABILITIES, wszProperty) == 0) { @@ -6150,28 +6265,28 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*pCardCapabilities); if (cbData < sizeof(*pCardCapabilities)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); dwret = md_card_capabilities(pCardData, pCardCapabilities); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } else if (wcscmp(CP_CARD_KEYSIZES,wszProperty) == 0) { PCARD_KEY_SIZES pKeySizes = (PCARD_KEY_SIZES )pbData; if (pdwDataLen) *pdwDataLen = sizeof(*pKeySizes); if (cbData < sizeof(*pKeySizes)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); dwret = md_query_key_sizes(pCardData, 0, pKeySizes); if (dwret != SCARD_S_SUCCESS) - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } else if (wcscmp(CP_CARD_READ_ONLY, wszProperty) == 0) { BOOL *p = (BOOL *)pbData; if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); *p = md_is_read_only(pCardData); } @@ -6180,7 +6295,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); *p = CP_CACHE_MODE_NO_CACHE; } else if (wcscmp(CP_SUPPORTS_WIN_X509_ENROLLMENT, wszProperty) == 0) { @@ -6188,7 +6303,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); *p = md_is_supports_X509_enrollment(pCardData); } else if (wcscmp(CP_CARD_GUID, wszProperty) == 0) { @@ -6197,13 +6312,13 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, md_fs_find_file(pCardData, NULL, "cardid", &cardid); if (!cardid) { logprintf(pCardData, 2, "file 'cardid' not found\n"); - return SCARD_E_FILE_NOT_FOUND; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_FILE_NOT_FOUND); } if (pdwDataLen) *pdwDataLen = (DWORD) cardid->size; if (cbData < cardid->size) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); CopyMemory(pbData, cardid->blob, cardid->size); } @@ -6222,7 +6337,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = (DWORD) buf_len; if (cbData < buf_len) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); CopyMemory(pbData, buf, buf_len); } @@ -6233,16 +6348,16 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); if (p->dwVersion != PIN_INFO_CURRENT_VERSION) - return ERROR_REVISION_MISMATCH; + MD_FUNC_RETURN(pCardData, 1, ERROR_REVISION_MISMATCH); if (dwFlags >= MD_MAX_PINS) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!vs->pin_objs[dwFlags]) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH @@ -6286,7 +6401,7 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); memset(p, 0, sizeof(*p)); for (pinidx = 0; pinidx < MD_MAX_PINS; pinidx++) { @@ -6301,24 +6416,24 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); logprintf(pCardData, 7, "CARD_AUTHENTICATED_STATE invalid\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } else if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY,wszProperty) == 0) { DWORD *p = (DWORD *)pbData; if (dwFlags >= MD_MAX_PINS) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!vs->pin_objs[dwFlags]) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); *p = CARD_PIN_STRENGTH_PLAINTEXT; if (vs->p15card->card->caps & SC_CARD_CAP_SESSION_PIN) { *p |= CARD_PIN_STRENGTH_SESSION_PIN; @@ -6329,33 +6444,33 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (pdwDataLen) *pdwDataLen = sizeof(*p); if (cbData < sizeof(*p)) - return ERROR_INSUFFICIENT_BUFFER; + MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER); *p = 0; } else if (wcscmp(CP_ENUM_ALGORITHMS, wszProperty) == 0) { logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty); //TODO - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } else if (wcscmp(CP_PADDING_SCHEMES, wszProperty) == 0) { logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty); //TODO - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } else if (wcscmp(CP_CHAINING_MODES, wszProperty) == 0) { logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty); //TODO - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } else { logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } logprintf(pCardData, 7, "returns '%S' ", wszProperty); loghex(pCardData, 7, pbData, *pdwDataLen); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, @@ -6366,13 +6481,15 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, { VENDOR_SPECIFIC *vs; + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardSetProperty\n"); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); logprintf(pCardData, 2, "CardSetProperty wszProperty=%S, pbData=%p, cbDataLen=%lu, dwFlags=%lu", @@ -6381,16 +6498,16 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!wszProperty) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (dwFlags) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if (!cbDataLen) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* the following properties cannot be set according to the minidriver specifications */ if (wcscmp(wszProperty,CP_CARD_FREE_SPACE) == 0 || @@ -6406,14 +6523,14 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, wcscmp(wszProperty,CP_CARD_CACHE_MODE) == 0 || wcscmp(wszProperty,CP_CARD_SERIAL_NO) == 0 ) { - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /* 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; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /* This property and CP_PIN_CONTEXT_STRING are set just prior to a call to @@ -6421,25 +6538,25 @@ DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData, */ if (wcscmp(CP_PARENT_WINDOW, wszProperty) == 0) { if (cbDataLen != sizeof(HWND) || !pbData) { - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } else { HWND cp = *((HWND *) pbData); if (cp!=0 && !IsWindow(cp)) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); vs->hwndParent = cp; } logprintf(pCardData, 3, "Saved parent window (%p)\n", vs->hwndParent); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, 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; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } logprintf(pCardData, 3, "INVALID PARAMETER\n"); - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); } @@ -6472,11 +6589,14 @@ DWORD WINAPI CardImportSessionKey( UNREFERENCED_PARAMETER(pbInput); UNREFERENCED_PARAMETER(cbInput); UNREFERENCED_PARAMETER(dwFlags); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardImportSessionKey - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /** The MDImportSessionKey function imports a temporary session key to the card minidriver @@ -6497,11 +6617,14 @@ DWORD WINAPI MDImportSessionKey( UNREFERENCED_PARAMETER(phKey); UNREFERENCED_PARAMETER(pbInput); UNREFERENCED_PARAMETER(cbInput); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "MDImportSessionKey - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /** The MDEncryptData function uses a key handle to encrypt data with a symmetric key. @@ -6527,11 +6650,14 @@ DWORD WINAPI MDEncryptData( UNREFERENCED_PARAMETER(dwFlags); UNREFERENCED_PARAMETER(ppEncryptedData); UNREFERENCED_PARAMETER(pcEncryptedData); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "MDEncryptData - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } @@ -6557,11 +6683,15 @@ DWORD WINAPI CardGetSharedKeyHandle( UNREFERENCED_PARAMETER(ppbOutput); UNREFERENCED_PARAMETER(pcbOutput); UNREFERENCED_PARAMETER(phKey); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetSharedKeyHandle - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); + } /** The CardDestroyKey function releases a temporary key on the card. The card @@ -6574,11 +6704,14 @@ DWORD WINAPI CardDestroyKey( { UNREFERENCED_PARAMETER(pCardData); UNREFERENCED_PARAMETER(hKey); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardDestroyKey - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /** This function can be used to get properties for a cryptographic algorithm.*/ @@ -6600,11 +6733,14 @@ DWORD WINAPI CardGetAlgorithmProperty ( UNREFERENCED_PARAMETER(cbData); UNREFERENCED_PARAMETER(pdwDataLen); UNREFERENCED_PARAMETER(dwFlags); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetAlgorithmProperty - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /** This function is used to get the properties of a key.*/ @@ -6625,11 +6761,14 @@ DWORD WINAPI CardGetKeyProperty( UNREFERENCED_PARAMETER(cbData); UNREFERENCED_PARAMETER(pdwDataLen); UNREFERENCED_PARAMETER(dwFlags); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardGetKeyProperty - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } /** This function is used to set the properties of a key.*/ @@ -6649,11 +6788,15 @@ DWORD WINAPI CardSetKeyProperty( UNREFERENCED_PARAMETER(pbInput); UNREFERENCED_PARAMETER(cbInput); UNREFERENCED_PARAMETER(dwFlags); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardSetKeyProperty - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); + } /** CardProcessEncryptedData processes a set of encrypted data BLOBs by @@ -6682,11 +6825,15 @@ DWORD WINAPI CardProcessEncryptedData( UNREFERENCED_PARAMETER(cbOutput); UNREFERENCED_PARAMETER(pdwOutputLen); UNREFERENCED_PARAMETER(dwFlags); + + MD_FUNC_CALLED(pCardData, 1); + logprintf(pCardData, 1, "\nP:%lu T:%lu pCardData:%p ", (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, "CardProcessEncryptedData - unsupported\n"); - return SCARD_E_UNSUPPORTED_FEATURE; + + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } DWORD WINAPI CardAcquireContext(__inout PCARD_DATA pCardData, __in DWORD dwFlags) @@ -6696,51 +6843,55 @@ DWORD WINAPI CardAcquireContext(__inout PCARD_DATA pCardData, __in DWORD dwFlags CRITICAL_SECTION hScard_lock; if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); + + MD_FUNC_CALLED(pCardData, 1); + if (dwFlags & ~CARD_SECURE_KEY_INJECTION_NO_CARD_MODE) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); + if (!(dwFlags & CARD_SECURE_KEY_INJECTION_NO_CARD_MODE)) { if( pCardData->hSCardCtx == 0) { logprintf(pCardData, 0, "Invalid handle.\n"); - return SCARD_E_INVALID_HANDLE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_HANDLE); } if( pCardData->hScard == 0) { logprintf(pCardData, 0, "Invalid handle.\n"); - return SCARD_E_INVALID_HANDLE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_HANDLE); } } else { /* secure key injection not supported */ - return SCARD_E_UNSUPPORTED_FEATURE; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNSUPPORTED_FEATURE); } if (pCardData->pbAtr == NULL) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); if ( pCardData->pwszCardName == NULL ) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* <2 length or >=0x22 are not ISO compliant */ if (pCardData->cbAtr >= 0x22 || pCardData->cbAtr <= 0x2) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, 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; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNKNOWN_CARD); /* Memory management functions */ if ( ( pCardData->pfnCspAlloc == NULL ) || ( pCardData->pfnCspReAlloc == NULL ) || ( pCardData->pfnCspFree == NULL ) ) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, 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; + MD_FUNC_RETURN(pCardData, 1, (DWORD) ERROR_REVISION_MISMATCH); suppliedVersion = pCardData->dwVersion; /* VENDOR SPECIFIC */ vs = pCardData->pvVendorSpecific = pCardData->pfnCspAlloc(sizeof(VENDOR_SPECIFIC)); if (!vs) - return SCARD_E_NO_MEMORY; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_NO_MEMORY); memset(vs, 0, sizeof(VENDOR_SPECIFIC)); InitializeCriticalSection(&vs->hScard_lock); @@ -6751,11 +6902,11 @@ DWORD WINAPI CardAcquireContext(__inout PCARD_DATA pCardData, __in DWORD dwFlags (unsigned long)GetCurrentProcessId(), (unsigned long)GetCurrentThreadId(), pCardData); logprintf(pCardData, 1, - "CardAcquireContext, dwVersion=%lu, name=%S,hScard=0x%08X, hSCardCtx=0x%08X\n", + "CardAcquireContext, dwVersion=%lu, name=%S,hScard=0x%08"SC_FORMAT_LEN_SIZE_T"X, hSCardCtx=0x%08"SC_FORMAT_LEN_SIZE_T"X\n", (unsigned long)pCardData->dwVersion, NULLWSTR(pCardData->pwszCardName), - (unsigned int)pCardData->hScard, - (unsigned int)pCardData->hSCardCtx); + (size_t)pCardData->hScard, + (size_t)pCardData->hSCardCtx); vs->hScard = pCardData->hScard; vs->hSCardCtx = pCardData->hSCardCtx; @@ -6842,7 +6993,7 @@ DWORD WINAPI CardAcquireContext(__inout PCARD_DATA pCardData, __in DWORD dwFlags unlock(pCardData); - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); ret_disassoc: disassociate_card(pCardData); @@ -6856,7 +7007,7 @@ ret_free: pCardData->pvVendorSpecific = NULL; LeaveCriticalSection(&hScard_lock); DeleteCriticalSection(&hScard_lock); - return dwret; + MD_FUNC_RETURN(pCardData, 1, dwret); } static DWORD associate_card(PCARD_DATA pCardData) @@ -6866,13 +7017,13 @@ static DWORD associate_card(PCARD_DATA pCardData) struct sc_app_info *app_generic; struct sc_aid *aid; - logprintf(pCardData, 1, "associate_card\n"); + MD_FUNC_CALLED(pCardData, 1); if (!pCardData) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); if (!vs) - return SCARD_E_INVALID_PARAMETER; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_INVALID_PARAMETER); /* * set the addresses of the reader and card handles @@ -6885,8 +7036,8 @@ static DWORD associate_card(PCARD_DATA pCardData) /* set the provided reader and card handles into ctx */ r = sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard); if (r != SC_SUCCESS) { - logprintf(pCardData, 0, "sc_ctx_use_reader() failed with %d\n", r); - return SCARD_E_COMM_DATA_LOST; + logprintf(pCardData, 1, "sc_ctx_use_reader() failed with %d\n", r); + MD_FUNC_RETURN(pCardData, 1, SCARD_E_COMM_DATA_LOST); } /* should be only one reader */ @@ -6894,12 +7045,12 @@ static DWORD associate_card(PCARD_DATA pCardData) vs->reader = sc_ctx_get_reader(vs->ctx, 0); if (!vs->reader) - return SCARD_E_COMM_DATA_LOST; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_COMM_DATA_LOST); r = sc_connect_card(vs->reader, &(vs->card)); if (r != SC_SUCCESS) { logprintf(pCardData, 0, "Cannot connect card in reader '%s'\n", NULLSTR(vs->reader->name)); - return SCARD_E_UNKNOWN_CARD; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNKNOWN_CARD); } logprintf(pCardData, 3, "Connected card in '%s'\n", NULLSTR(vs->reader->name)); @@ -6913,12 +7064,12 @@ static DWORD associate_card(PCARD_DATA pCardData) if (r != SC_SUCCESS) { logprintf(pCardData, 0, "PKCS#15 init failed.\n"); sc_disconnect_card(vs->card); - return SCARD_E_UNKNOWN_CARD; + MD_FUNC_RETURN(pCardData, 1, SCARD_E_UNKNOWN_CARD); } vs->initialized = TRUE; - return SCARD_S_SUCCESS; + MD_FUNC_RETURN(pCardData, 1, SCARD_S_SUCCESS); } static void disassociate_card(PCARD_DATA pCardData) diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 22081ffe..b9ee80d8 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -732,7 +732,7 @@ __pkcs15_create_pubkey_object(struct pkcs15_fw_data *fw_data, /* if emulation already created pubkey use it */ if (pubkey->emulated && (fw_data->p15_card->flags & SC_PKCS15_CARD_FLAG_EMULATED)) { sc_log(context, "Use emulated pubkey"); - p15_key = (struct sc_pkcs15_pubkey *) pubkey->emulated; + sc_pkcs15_dup_pubkey(context, (struct sc_pkcs15_pubkey *) pubkey->emulated, &p15_key); } else { sc_log(context, "Get pubkey from PKCS#15 object"); @@ -1122,9 +1122,10 @@ pkcs15_init_slot(struct sc_pkcs15_card *p15card, struct sc_pkcs11_slot *slot, max_tokeninfo_len); slot->token_info.label[max_tokeninfo_len] = ' '; slot->token_info.label[max_tokeninfo_len+1] = '('; - slot->token_info.label[max_tokeninfo_len+2+pin_len] = ')'; strcpy_bp(slot->token_info.label+max_tokeninfo_len+2, auth->label, pin_len); + strcpy_bp(slot->token_info.label+max_tokeninfo_len+2+pin_len, + ")", 32 - max_tokeninfo_len-2-pin_len); } } else { /* PIN label is empty or just says non-useful "PIN", @@ -1667,22 +1668,6 @@ pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType, if (!p11card) return CKR_TOKEN_NOT_RECOGNIZED; - if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD - || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { - /* pPin should be NULL in case of a pin pad reader, but - * some apps (e.g. older Netscapes) don't know about it. - * So we don't require that pPin == NULL, but set it to - * NULL ourselves. This way, you can supply an empty (if - * possible) or fake PIN if an application asks a PIN). - */ - /* But we want to be able to specify a PIN on the command - * line (e.g. for the test scripts). So we don't do anything - * here - this gives the user the choice of entering - * an empty pin (which makes us use the pin pad) or - * a valid pin (which is processed normally). --okir */ - if (ulPinLen == 0) - pPin = NULL; - } /* By default, we make the reader resource manager keep other * processes from accessing the card while we're logged in. @@ -1842,26 +1827,11 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot, return CKR_USER_PIN_NOT_INITIALIZED; sc_log(context, "Change '%.*s' (ref:%i,type:%i)", (int) sizeof pin_obj->label, pin_obj->label, auth_info->attrs.pin.reference, login_user); - if ((p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) - || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { - /* pPin should be NULL in case of a pin pad reader, but - * some apps (e.g. older Netscapes) don't know about it. - * So we don't require that pPin == NULL, but set it to - * NULL ourselves. This way, you can supply an empty (if - * possible) or fake PIN if an application asks a PIN). - */ - pOldPin = pNewPin = NULL; - ulOldLen = ulNewLen = 0; - } - else if (ulNewLen < auth_info->attrs.pin.min_length || ulNewLen > auth_info->attrs.pin.max_length) { + if (pNewPin && (ulNewLen < auth_info->attrs.pin.min_length || ulNewLen > auth_info->attrs.pin.max_length)) { return CKR_PIN_LEN_RANGE; } - if (login_user < 0) { - if (sc_pkcs11_conf.pin_unblock_style != SC_PKCS11_PIN_UNBLOCK_UNLOGGED_SETPIN) { - sc_log(context, "PIN unlock is not allowed in unlogged session"); - return CKR_FUNCTION_NOT_SUPPORTED; - } + if (login_user < 0 && sc_pkcs11_conf.pin_unblock_style == SC_PKCS11_PIN_UNBLOCK_UNLOGGED_SETPIN) { rc = sc_pkcs15_unblock_pin(fw_data->p15_card, pin_obj, pOldPin, ulOldLen, pNewPin, ulNewLen); } else if (login_user == CKU_CONTEXT_SPECIFIC) { @@ -1871,7 +1841,7 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot, } rc = sc_pkcs15_unblock_pin(fw_data->p15_card, pin_obj, pOldPin, ulOldLen, pNewPin, ulNewLen); } - else if ((login_user == CKU_USER) || (login_user == CKU_SO)) { + else if (login_user < 0 || login_user == CKU_USER || login_user == CKU_SO) { rc = sc_pkcs15_change_pin(fw_data->p15_card, pin_obj, pOldPin, ulOldLen, pNewPin, ulNewLen); } else { @@ -3976,7 +3946,7 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, /* Check the data length matches the selected hash */ rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); if (rv != CKR_OK) { - sc_log(context, "Invalid data lenght for the selected " + sc_log(context, "Invalid data length for the selected " "PSS parameters"); return rv; } @@ -4179,6 +4149,39 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj, case CKM_RSA_X_509: flags |= SC_ALGORITHM_RSA_RAW; break; + case CKM_RSA_PKCS_OAEP: + flags |= SC_ALGORITHM_RSA_PAD_OAEP; + + /* Omited parameter can use MGF1-SHA1 and SHA1 hash ? */ + if (pMechanism->pParameter == NULL) { + flags |= SC_ALGORITHM_RSA_HASH_SHA1; + flags |= SC_ALGORITHM_MGF1_SHA1; + break; + } + + switch (((CK_RSA_PKCS_OAEP_PARAMS*)pMechanism->pParameter)->hashAlg) { + case CKM_SHA_1: + flags |= SC_ALGORITHM_RSA_HASH_SHA1; + break; + case CKM_SHA224: + flags |= SC_ALGORITHM_RSA_HASH_SHA224; + break; + case CKM_SHA256: + flags |= SC_ALGORITHM_RSA_HASH_SHA256; + break; + case CKM_SHA384: + flags |= SC_ALGORITHM_RSA_HASH_SHA384; + break; + case CKM_SHA512: + flags |= SC_ALGORITHM_RSA_HASH_SHA512; + break; + default: + return CKR_MECHANISM_PARAM_INVALID; + } + + /* The MGF parameter was already verified in SignInit() */ + flags |= mgf2flags(((CK_RSA_PKCS_OAEP_PARAMS*)pMechanism->pParameter)->mgf); + break; default: return CKR_MECHANISM_INVALID; } @@ -4352,6 +4355,7 @@ pkcs15_prkey_init_params(struct sc_pkcs11_session *session, const unsigned int salt_lens[5] = { 160, 256, 384, 512, 224 }; const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256, CKM_SHA384, CKM_SHA512, CKM_SHA224 }; + const CK_RSA_PKCS_OAEP_PARAMS *oaep_params; switch (pMechanism->mechanism) { case CKM_RSA_PKCS_PSS: @@ -4407,6 +4411,26 @@ pkcs15_prkey_init_params(struct sc_pkcs11_session *session, /* TODO support different salt lengths */ break; + case CKM_RSA_PKCS_OAEP: + if (!pMechanism->pParameter || + pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) + return CKR_MECHANISM_PARAM_INVALID; + + oaep_params = (CK_RSA_PKCS_OAEP_PARAMS*)pMechanism->pParameter; + switch (oaep_params->mgf) { + case CKG_MGF1_SHA1: + case CKG_MGF1_SHA224: + case CKG_MGF1_SHA256: + case CKG_MGF1_SHA384: + case CKG_MGF1_SHA512: + /* OK */ + break; + default: + return CKR_MECHANISM_PARAM_INVALID; + } + /* TODO support different salt lengths */ + /* TODO is there something more to check */ + break; } return CKR_OK; } @@ -5619,6 +5643,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; #ifdef ENABLE_OPENSSL rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS; + /* TODO support OAEP decryption & encryption using OpenSSL */ #endif } @@ -5699,6 +5724,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) } if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) { + CK_FLAGS old_flags = mech_info.flags; mech_info.flags &= ~(CKF_DECRYPT|CKF_ENCRYPT); mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL); rc = sc_pkcs11_register_mechanism(p11card, mt); @@ -5735,6 +5761,18 @@ register_mechanisms(struct sc_pkcs11_card *p11card) if (rc != CKR_OK) return rc; } + mech_info.flags = old_flags; + } + + if (rsa_flags & SC_ALGORITHM_RSA_PAD_OAEP) { + CK_FLAGS old_flags = mech_info.flags; + mech_info.flags &= ~(CKF_SIGN|CKF_VERIFY|CKF_SIGN_RECOVER|CKF_VERIFY_RECOVER); + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_OAEP, &mech_info, CKK_RSA, NULL, NULL); + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) { + return rc; + } + mech_info.flags = old_flags; } if (rsa_flags & SC_ALGORITHM_ONBOARD_KEY_GEN) { diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 358cad40..983d8dcb 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -811,6 +811,15 @@ sc_pkcs11_decr_init(struct sc_pkcs11_session *session, } rv = mt->decrypt_init(operation, key); + /* Validate the mechanism parameters */ + if (key->ops->init_params) { + rv = key->ops->init_params(operation->session, &operation->mechanism); + if (rv != CKR_OK) { + /* Probably bad arguments */ + LOG_FUNC_RETURN(context, (int) rv); + } + } + if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT); diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 71e13831..67189030 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -269,7 +269,6 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) pid_t current_pid = getpid(); #endif int rc; - unsigned int i; sc_context_param_t ctx_opts; #if !defined(_WIN32) @@ -321,9 +320,7 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) } list_attributes_seeker(&virtual_slots, slot_list_seeker); - /* Create slots for readers found on initialization, only if in 2.11 mode */ - for (i=0; iflags &= ~SC_PKCS11_SLOT_FLAG_SEEN; - } - } + + DEBUG_VSS(NULL, "C_GetSlotList after ctx_detect_readers"); card_detect_all(); + if (list_empty(&virtual_slots)) { + sc_log(context, "returned 0 slots\n"); + *pulCount = 0; + rv = CKR_OK; + goto out; + } + found = calloc(list_size(&virtual_slots), sizeof(CK_SLOT_ID)); if (found == NULL) { @@ -473,13 +475,11 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese for (i=0; ireader) - || (!tokenPresent && slot->reader != prev_reader) + if ((!tokenPresent && slot->reader != prev_reader) || (slot->slot_info.flags & CKF_TOKEN_PRESENT) || (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN)) { found[numMatches++] = slot->id; @@ -487,21 +487,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese } prev_reader = slot->reader; } - - /* Slot list can only change in v2.20 */ - if (pSlotList == NULL_PTR) { - /* slot->id is derived from its location in the list virtual_slots. - * When the slot list changes, so does slot->id, so we reindex the - * slots here the same way it is done in `create_slot()` - * - * TODO use a persistent CK_SLOT_ID, e.g. by using something like - * `slot->id = sc_crc32(slot, sizeof *slot);` (this example, however, - * is currently not thread safe). */ - for (i=0; iid = (CK_SLOT_ID) list_locate(&virtual_slots, slot); - } - } + DEBUG_VSS(NULL, "C_GetSlotList after card_detect_all"); if (pSlotList == NULL_PTR) { sc_log(context, "was only a size inquiry (%lu)\n", numMatches); @@ -509,6 +495,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese rv = CKR_OK; goto out; } + DEBUG_VSS(NULL, "C_GetSlotList after slot->id reassigned"); if (*pulCount < numMatches) { sc_log(context, "buffer was too small (needed %lu)\n", numMatches); @@ -522,12 +509,10 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese rv = CKR_OK; sc_log(context, "returned %lu slots\n", numMatches); + DEBUG_VSS(NULL, "Returning a new slot list"); out: - if (found != NULL) { - free (found); - found = NULL; - } + free (found); sc_pkcs11_unlock(); return rv; } @@ -561,7 +546,7 @@ static sc_timestamp_t get_current_time(void) CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { - struct sc_pkcs11_slot *slot; + struct sc_pkcs11_slot *slot = NULL; sc_timestamp_t now; CK_RV rv; @@ -575,7 +560,7 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) sc_log(context, "C_GetSlotInfo(0x%lx)", slotID); if (sc_pkcs11_conf.init_sloppy) { - /* Most likely virtual_slots only contains the hotplug slot and has not + /* Most likely virtual_slots is empty and has not * been initialized because the caller has *not* called C_GetSlotList * before C_GetSlotInfo, as required by PKCS#11. Initialize * virtual_slots to make things work and hope the caller knows what @@ -584,6 +569,7 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) } rv = slot_get_slot(slotID, &slot); + DEBUG_VSS(slot, "C_GetSlotInfo found"); sc_log(context, "C_GetSlotInfo() get slot rv %s", lookup_enum( RV_T, rv)); if (rv == CKR_OK) { if (slot->reader == NULL) { diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 4309b631..f87a56f8 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -65,7 +65,6 @@ struct sc_pkcs11_slot; struct sc_pkcs11_card; struct sc_pkcs11_config { - unsigned int plug_and_play; unsigned int max_virtual_slots; unsigned int slots_per_card; unsigned char lock_login; @@ -227,6 +226,12 @@ struct sc_pkcs11_slot { }; typedef struct sc_pkcs11_slot sc_pkcs11_slot_t; +/* Debug virtual slots. S is slot to be highlighted or NULL + * C is a comment format string and args It will be preceeded by "VSS " */ +#define DEBUG_VSS(S, ...) do { sc_log(context,"VSS " __VA_ARGS__); _debug_virtual_slots(S); } while (0) + +/* called by DEBUG_VSS to print table of virtual slots */ +void _debug_virtual_slots(sc_pkcs11_slot_t *p); /* Forward decl */ typedef struct sc_pkcs11_operation sc_pkcs11_operation_t; @@ -361,7 +366,7 @@ void sc_pkcs11_print_attrs(int level, const char *file, unsigned int line, const CK_RV card_removed(sc_reader_t *reader); CK_RV card_detect_all(void); CK_RV create_slot(sc_reader_t *reader); -CK_RV initialize_reader(sc_reader_t *reader); +void init_slot_info(CK_SLOT_INFO_PTR pInfo, sc_reader_t *reader); CK_RV card_detect(sc_reader_t *reader); CK_RV slot_get_slot(CK_SLOT_ID id, struct sc_pkcs11_slot **); CK_RV slot_get_token(CK_SLOT_ID id, struct sc_pkcs11_slot **); diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index d72fa3fb..148b59ec 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -27,6 +27,32 @@ #include "sc-pkcs11.h" +/* Print virtual_slots list. Called by DEBUG_VSS(S, C) */ +void _debug_virtual_slots(sc_pkcs11_slot_t *p) +{ + int i, vs_size; + sc_pkcs11_slot_t * slot; + + vs_size = list_size(&virtual_slots); + _sc_debug(context, 10, + "VSS size:%d", vs_size); + _sc_debug(context, 10, + "VSS [i] id flags LU events nsessions slot_info.flags reader p11card description"); + for (i = 0; i < vs_size; i++) { + slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); + if (slot) { + _sc_debug(context, 10, + "VSS %s[%d] 0x%2.2lx 0x%4.4x %d %d %d %4.4lx %p %p %.64s", + ((slot == p) ? "*" : " "), + i, slot->id, slot->flags, slot->login_user, slot->events, slot->nsessions, + slot->slot_info.flags, + slot->reader, slot->p11card, + slot->slot_info.slotDescription); + } + } + _sc_debug(context, 10, "VSS END"); +} + static struct sc_pkcs11_framework_ops *frameworks[] = { &framework_pkcs15, #ifdef USE_PKCS15_INIT @@ -37,20 +63,30 @@ static struct sc_pkcs11_framework_ops *frameworks[] = { NULL }; -static struct sc_pkcs11_slot * reader_get_slot(sc_reader_t *reader) +static struct sc_pkcs11_slot * reader_reclaim_slot(sc_reader_t *reader) { unsigned int i; + CK_UTF8CHAR slotDescription[64]; + CK_UTF8CHAR manufacturerID[32]; + + strcpy_bp(slotDescription, reader->name, 64); + strcpy_bp(manufacturerID, reader->vendor, 32); /* Locate a slot related to the reader */ for (i = 0; ireader == reader) + if (slot->reader == NULL && reader != NULL + && 0 == memcmp(slot->slot_info.slotDescription, slotDescription, 64) + && 0 == memcmp(slot->slot_info.manufacturerID, manufacturerID, 32) + && slot->slot_info.hardwareVersion.major == reader->version_major + && slot->slot_info.hardwareVersion.minor == reader->version_minor) { return slot; + } } return NULL; } -static void init_slot_info(CK_SLOT_INFO_PTR pInfo, sc_reader_t *reader) +void init_slot_info(CK_SLOT_INFO_PTR pInfo, sc_reader_t *reader) { if (reader) { strcpy_bp(pInfo->slotDescription, reader->name, 64); @@ -82,11 +118,12 @@ static int object_list_seeker(const void *el, const void *key) CK_RV create_slot(sc_reader_t *reader) { - /* find unused virtual hotplug slots */ - struct sc_pkcs11_slot *slot = reader_get_slot(NULL); + /* find unused slots previously allocated for the same reader */ + struct sc_pkcs11_slot *slot = reader_reclaim_slot(reader); /* create a new slot if no empty slot is available */ if (!slot) { + sc_log(context, "Creating new slot"); if (list_size(&virtual_slots) >= sc_pkcs11_conf.max_virtual_slots) return CKR_FUNCTION_FAILED; @@ -104,6 +141,8 @@ CK_RV create_slot(sc_reader_t *reader) return CKR_HOST_MEMORY; } } else { + DEBUG_VSS(slot, "Reusing this old slot"); + /* reuse the old list of logins/objects since they should be empty */ list_t logins = slot->logins; list_t objects = slot->objects; @@ -115,63 +154,15 @@ CK_RV create_slot(sc_reader_t *reader) } slot->login_user = -1; - init_slot_info(&slot->slot_info, reader); - sc_log(context, "Initializing slot with id 0x%lx", slot->id); - - if (reader != NULL) { - slot->reader = reader; - strcpy_bp(slot->slot_info.manufacturerID, reader->vendor, 32); - strcpy_bp(slot->slot_info.slotDescription, reader->name, 64); - slot->slot_info.hardwareVersion.major = reader->version_major; - slot->slot_info.hardwareVersion.minor = reader->version_minor; - } slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot); + init_slot_info(&slot->slot_info, reader); + slot->reader = reader; + + DEBUG_VSS(slot, "Finished initializing this slot"); return CKR_OK; } -void empty_slot(struct sc_pkcs11_slot *slot) -{ - if (slot) { - if (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN) { - /* Keep the slot visible to the application. The slot's state has - * already been reset by `slot_token_removed()`, lists have been - * emptied. We replace the reader with a virtual hotplug slot. */ - slot->reader = NULL; - init_slot_info(&slot->slot_info, NULL); - } else { - list_destroy(&slot->objects); - list_destroy(&slot->logins); - 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) -{ - unsigned int i; - CK_RV rv; - - for (i = 0; i < sc_pkcs11_conf.slots_per_card; i++) { - rv = create_slot(reader); - if (rv != CKR_OK) - return rv; - } - - sc_log(context, "Initialize reader '%s': detect SC card presence", reader->name); - if (sc_detect_card_presence(reader)) { - sc_log(context, "Initialize reader '%s': detect PKCS11 card presence", reader->name); - card_detect(reader); - } - - sc_log(context, "Reader '%s' initialized", reader->name); - return CKR_OK; -} - - CK_RV card_removed(sc_reader_t * reader) { unsigned int i; @@ -388,25 +379,45 @@ fail: CK_RV card_detect_all(void) { - unsigned int i; + unsigned int i, j; sc_log(context, "Detect all cards"); /* 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->flags & SC_READER_REMOVED) { - struct sc_pkcs11_slot *slot; card_removed(reader); - while ((slot = reader_get_slot(reader))) { - empty_slot(slot); + /* do not remove slots related to this reader which would be + * possible according to PKCS#11 2.20 and later, because NSS can't + * handle a shrinking slot list + * https://bugzilla.mozilla.org/show_bug.cgi?id=1613632 */ + + /* Instead, remove the releation between reader and slot */ + for (j = 0; jreader == reader) { + slot->reader = NULL; + } } - _sc_delete_reader(context, reader); - i--; } else { - if (!reader_get_slot(reader)) - initialize_reader(reader); - else - card_detect(sc_ctx_get_reader(context, i)); + /* Locate a slot related to the reader */ + int found = 0; + for (j = 0; jreader == reader) { + found = 1; + break; + } + } + if (!found) { + for (j = 0; j < sc_pkcs11_conf.slots_per_card; j++) { + CK_RV rv = create_slot(reader); + if (rv != CKR_OK) + return rv; + } + } + card_detect(reader); } } sc_log(context, "All cards detected"); diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 830c2007..2b28bce0 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -1871,7 +1871,7 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile profile->dirty = 1; err: - if (object && r < 0) + if (r < 0) sc_pkcs15init_free_object(object); LOG_FUNC_RETURN(ctx, r); diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c index dfd4b8b8..3740e2bb 100644 --- a/src/pkcs15init/pkcs15-openpgp.c +++ b/src/pkcs15init/pkcs15-openpgp.c @@ -119,6 +119,7 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_cardctl_openpgp_keystore_info_t key_info; int r; + unsigned int i; LOG_FUNC_CALLED(card->ctx); @@ -150,8 +151,18 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, key_info.key_id = kinfo->id.value[0]; key_info.u.ec.privateD = key->u.ec.privateD.data; key_info.u.ec.privateD_len = key->u.ec.privateD.len; - key_info.u.ec.ecpoint = key->u.ec.ecpointQ.value; - key_info.u.ec.ecpoint_len = key->u.ec.ecpointQ.len; + key_info.u.ec.ecpointQ = key->u.ec.ecpointQ.value; + key_info.u.ec.ecpointQ_len = key->u.ec.ecpointQ.len; + /* extract oid the way we need to import it to OpenPGP Card */ + if (key->u.ec.params.der.len > 2) + key_info.u.ec.oid_len = key->u.ec.params.der.value[1]; + else + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + + for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < key->u.ec.params.der.len); i++){ + key_info.u.ec.oid.value[i] = key->u.ec.params.der.value[i+2]; + } + key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1; r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info); break; default: diff --git a/src/pkcs15init/profile.c b/src/pkcs15init/profile.c index 107529a5..b5f08a9d 100644 --- a/src/pkcs15init/profile.c +++ b/src/pkcs15init/profile.c @@ -485,7 +485,6 @@ sc_profile_free(struct sc_profile *profile) if (profile->p15_spec) sc_pkcs15_card_free(profile->p15_spec); - memset(profile, 0, sizeof(*profile)); free(profile); } diff --git a/src/sm/sm-iso.c b/src/sm/sm-iso.c index 9dbda86e..5baded77 100644 --- a/src/sm/sm-iso.c +++ b/src/sm/sm-iso.c @@ -469,16 +469,17 @@ static int sm_encrypt(const struct iso_sm_ctx *ctx, sc_card_t *card, sm_apdu->datalen = sm_data_len; sm_apdu->lc = sm_data_len; sm_apdu->le = 0; + /* for encrypted APDUs we usually get authenticated status bytes (4B), a + * MAC (2B without data) and a cryptogram with padding indicator (2B tag + * and indicator, max. 2B/3B ASN.1 length, without data). The cryptogram is + * always padded to the block size. */ if (apdu->cse & SC_APDU_EXT) { sm_apdu->cse = SC_APDU_CASE_4_EXT; + sm_apdu->resplen = 4 + 2 + mac_len + 2 + 3 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length; } else { sm_apdu->cse = SC_APDU_CASE_4_SHORT; + sm_apdu->resplen = 4 + 2 + mac_len + 2 + 2 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length; } - /* for encrypted APDUs we usually get authenticated status bytes - * (4B), a MAC (2B without data) and a cryptogram with padding - * indicator (3B without data). The cryptogram is always padded to - * the block size. */ - sm_apdu->resplen = 4 + 2 + mac_len + 3 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length; resp_data = calloc(sm_apdu->resplen, 1); if (!resp_data) { r = SC_ERROR_OUT_OF_MEMORY; diff --git a/src/tests/p11test/p11test.c b/src/tests/p11test/p11test.c index feecf6fb..a16282cb 100644 --- a/src/tests/p11test/p11test.c +++ b/src/tests/p11test/p11test.c @@ -34,6 +34,9 @@ #define DEFAULT_P11LIB "../../pkcs11/.libs/opensc-pkcs11.so" +/* Global variable keeping information about token we are using */ +token_info_t token; + void display_usage() { fprintf(stdout, " Usage:\n" diff --git a/src/tests/p11test/p11test_case_common.c b/src/tests/p11test/p11test_case_common.c index bd4b39af..22e639cf 100644 --- a/src/tests/p11test/p11test_case_common.c +++ b/src/tests/p11test/p11test_case_common.c @@ -422,7 +422,7 @@ int search_objects(test_certs_t *objects, token_info_t *info, CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE_PTR object_handles = NULL; unsigned long i = 0, objects_length = 0; - int j; + int j, ret = -1; /* FindObjects first * https://wiki.oasis-open.org/pkcs11/CommonBugs @@ -439,16 +439,18 @@ int search_objects(test_certs_t *objects, token_info_t *info, break; if (rv != CKR_OK) { fprintf(stderr, "C_FindObjects: rv = 0x%.8lX\n", rv); - return -1; + goto out; } /* store handle */ if (i >= objects_length) { + CK_OBJECT_HANDLE_PTR new_object_handles = NULL; objects_length += 4; // do not realloc after each row - object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE)); - if (object_handles == NULL) { + new_object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE)); + if (new_object_handles == NULL) { fail_msg("Realloc failed. Need to store object handles.\n"); - return -1; + goto out; } + object_handles = new_object_handles; } object_handles[i++] = object_handle; } @@ -458,8 +460,7 @@ int search_objects(test_certs_t *objects, token_info_t *info, if (rv != CKR_OK) { fprintf(stderr, "C_FindObjectsFinal: rv = 0x%.8lX\n", rv); fail_msg("Could not find certificate.\n"); - free(object_handles); - return -1; + goto out; } for (i = 0; i < objects_length; i++) { @@ -476,8 +477,7 @@ int search_objects(test_certs_t *objects, token_info_t *info, continue; } else if (rv != CKR_OK) { fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv); - free(object_handles); - return -1; + goto out; } /* Allocate memory to hold the data we want */ @@ -487,8 +487,7 @@ int search_objects(test_certs_t *objects, token_info_t *info, template[j].pValue = malloc(template[j].ulValueLen); if (template[j].pValue == NULL) { fail_msg("malloc failed"); - free(object_handles); - return -1; + goto out; } } /* Call again to get actual attribute */ @@ -496,8 +495,7 @@ int search_objects(test_certs_t *objects, token_info_t *info, &(template[j]), 1); if (rv != CKR_OK) { fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv); - free(object_handles); - return -1; + goto out; } } @@ -506,8 +504,10 @@ int search_objects(test_certs_t *objects, token_info_t *info, for (j = 0; j < template_size; j++) free(template[j].pValue); } + ret = 0; +out: free(object_handles); - return 0; + return ret; } void search_for_all_objects(test_certs_t *objects, token_info_t *info) diff --git a/src/tests/p11test/p11test_case_pss_oaep.c b/src/tests/p11test/p11test_case_pss_oaep.c index 01947119..b114b736 100644 --- a/src/tests/p11test/p11test_case_pss_oaep.c +++ b/src/tests/p11test/p11test_case_pss_oaep.c @@ -376,7 +376,7 @@ int oaep_encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *m CK_BYTE *dec_message = NULL; int dec_message_length = 0; int message_length = 16; - unsigned char *enc_message; + unsigned char *enc_message = NULL; int enc_message_length, rv; if (o->private_handle == CK_INVALID_HANDLE) { diff --git a/src/tests/p11test/p11test_common.h b/src/tests/p11test/p11test_common.h index 2f3b238d..9eb5cede 100644 --- a/src/tests/p11test/p11test_common.h +++ b/src/tests/p11test/p11test_common.h @@ -84,7 +84,7 @@ typedef struct { size_t num_keygen_mechs; } token_info_t; -token_info_t token; +extern token_info_t token; #endif /* P11TEST_COMMON_H */ diff --git a/src/tests/unittests/Makefile.am b/src/tests/unittests/Makefile.am index 0795b62a..e2887d73 100644 --- a/src/tests/unittests/Makefile.am +++ b/src/tests/unittests/Makefile.am @@ -12,11 +12,10 @@ TESTS = asn1 simpletlv noinst_HEADERS = torture.h AM_CFLAGS = -I$(top_srcdir)/src/ \ - -L$(top_srcdir)/src/libopensc/ \ $(CODE_COVERAGE_CFLAGS) \ $(CMOCKA_CFLAGS) AM_CPPFLAGS =$(CODE_COVERAGE_CPPFLAGS) -LDADD = $(top_srcdir)/src/libopensc/libopensc.la \ +LDADD = $(top_builddir)/src/libopensc/libopensc.la \ $(CODE_COVERAGE_LIBS) \ $(OPTIONAL_OPENSSL_LIBS) \ $(CMOCKA_LIBS) diff --git a/src/tests/unittests/asn1.c b/src/tests/unittests/asn1.c index cef1128c..c5fad085 100644 --- a/src/tests/unittests/asn1.c +++ b/src/tests/unittests/asn1.c @@ -439,6 +439,124 @@ static void torture_asn1_decode_entry_bit_string_ni(void **state) assert_memory_equal(bit_string + 1, result, resultlen/8); } +static void torture_asn1_put_tag_short(void **state) +{ + unsigned int tag = 0xAC; + const u8 expected[] = {0xAC, 0x01, 0x02}; + const u8 data[] = {0x02}; + size_t data_len = 1; + u8 out[10]; + size_t out_len = sizeof(out); + u8 *p = out; + int rv; + + /* Without the out and out_len we are getting expected length */ + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, &p); + assert_int_equal(rv, sizeof(expected)); + assert_ptr_equal(p, out); + + /* Now we do the actual encoding */ + rv = sc_asn1_put_tag(tag, data, data_len, out, out_len, &p); + assert_int_equal(rv, SC_SUCCESS); + assert_memory_equal(out, expected, sizeof(expected)); + assert_ptr_equal(p, out + sizeof(expected)); + + /* Short buffer */ + rv = sc_asn1_put_tag(tag, data, data_len, out, 2, &p); + assert_int_equal(rv, SC_ERROR_BUFFER_TOO_SMALL); +} + +static void torture_asn1_put_tag_long_tag(void **state) +{ + /* Max supported value already encoded as ASN1 tag */ + unsigned int tag = 0xFFFFFF7F; + const u8 expected[] = {0xFF, 0xFF, 0xFF, 0x7F, 0x01, 0x02}; + const u8 data[] = {0x02}; + size_t data_len = 1; + u8 out[10]; + size_t out_len = sizeof(out); + u8 *p = out; + int rv; + + /* Without the out and out_len we are getting expected length */ + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, &p); + assert_int_equal(rv, sizeof(expected)); + assert_ptr_equal(p, out); + + /* Now we do the actual encoding */ + rv = sc_asn1_put_tag(tag, data, data_len, out, out_len, &p); + assert_int_equal(rv, SC_SUCCESS); + assert_memory_equal(out, expected, sizeof(expected)); + assert_ptr_equal(p, out + sizeof(expected)); + + /* The buffer is too small */ + rv = sc_asn1_put_tag(tag, data, data_len, out, 5, &p); + assert_int_equal(rv, SC_ERROR_BUFFER_TOO_SMALL); + + /* the MSB of last byte needs to be 0 */ + tag = 0xFFFFFF8F; + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, NULL); + assert_int_equal(rv, SC_ERROR_INVALID_DATA); + + /* the MSB of all byts needs to be 1 */ + tag = 0xFFFF7F7F; + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, NULL); + assert_int_equal(rv, SC_ERROR_INVALID_DATA); + + /* Fisrt byte has bits 5-1 set to 1 */ + tag = 0xE0FFFF7F; + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, NULL); + assert_int_equal(rv, SC_ERROR_INVALID_DATA); +} + +static void torture_asn1_put_tag_long_data(void **state) +{ + unsigned int tag = 0xAC; + const u8 expected[131] = {0xAC, 0x81, 0x80, 0x00, /* the rest is zero */}; + const u8 data[128] = {0}; + size_t data_len = sizeof(data); + u8 out[200]; + size_t out_len = sizeof(out); + u8 *p = out; + int rv; + + /* Without the out and out_len we are getting expected length */ + rv = sc_asn1_put_tag(tag, data, data_len, NULL, 0, &p); + assert_int_equal(rv, sizeof(expected)); + assert_ptr_equal(p, out); + + /* Now we do the actual encoding */ + rv = sc_asn1_put_tag(tag, data, data_len, out, out_len, &p); + assert_int_equal(rv, SC_SUCCESS); + assert_memory_equal(out, expected, sizeof(expected)); + assert_ptr_equal(p, out + sizeof(expected)); + + /* The buffer is too small */ + rv = sc_asn1_put_tag(tag, data, data_len, out, 130, &p); + assert_int_equal(rv, SC_ERROR_BUFFER_TOO_SMALL); +} + +static void torture_asn1_put_tag_without_data(void **state) +{ + unsigned int tag = 0xAC; + const u8 expected[] = {0xAC, 0x01}; + size_t data_len = 1; + u8 out[10]; + size_t out_len = sizeof(out); + u8 *p = out; + int rv; + + /* Without the out and out_len we are getting expected length */ + rv = sc_asn1_put_tag(tag, NULL, data_len, NULL, 0, &p); + assert_int_equal(rv, sizeof(expected) + data_len); + assert_ptr_equal(p, out); + + /* Now we do the actual encoding, but data field is not filled */ + rv = sc_asn1_put_tag(tag, NULL, data_len, out, out_len, &p); + assert_int_equal(rv, SC_SUCCESS); + assert_memory_equal(out, expected, sizeof(expected)); + assert_ptr_equal(p, out + sizeof(expected)); +} int main(void) { @@ -502,6 +620,11 @@ int main(void) setup_sc_context, teardown_sc_context), cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_bit_string_ni, setup_sc_context, teardown_sc_context), + /* put_tag() */ + cmocka_unit_test(torture_asn1_put_tag_short), + cmocka_unit_test(torture_asn1_put_tag_without_data), + cmocka_unit_test(torture_asn1_put_tag_long_tag), + cmocka_unit_test(torture_asn1_put_tag_long_data), }; rc = cmocka_run_group_tests(tests, NULL, NULL); diff --git a/src/tests/unittests/compression.c b/src/tests/unittests/compression.c index d1b7a4d7..07fea8e6 100644 --- a/src/tests/unittests/compression.c +++ b/src/tests/unittests/compression.c @@ -63,6 +63,22 @@ u8 invalid_suffix_data[] = { 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}; +/* https://github.com/madler/zlib/blob/master/test/infcover.c + */ +u8 zlib_good[] = {0x78, 0x9c, 0x63, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1}; + +/* Generated using + * $ echo "test" > /tmp/test + * $ pigz --zlib /tmp/test > /tmp/test.zz + * $ hexdump -C /tmp/test.zz + */ +u8 valid_zlib_data[] = {0x78, 0x5e, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0x06, 0x28, 0x01, 0xcb}; + +/* Generated as in the previous test case with some added mess on the end + */ +u8 invalid_zlib_suffix_data[] = {0x78, 0x5e, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0x06, 0x28, 0x01, 0xcb, + 0xff, 0xff, 0xff, 0xff}; + static void torture_compression_decompress_alloc_empty(void **state) { u8 *buf = NULL; @@ -150,10 +166,14 @@ static void torture_compression_decompress_alloc_valid(void **state) { u8 *buf = NULL; size_t buflen = 0; - size_t datalen = sizeof(valid_data); int rv; - rv = sc_decompress_alloc(&buf, &buflen, valid_data, datalen, COMPRESSION_AUTO); + rv = sc_decompress_alloc(&buf, &buflen, valid_data, sizeof(valid_data), COMPRESSION_AUTO); + assert_int_equal(rv, SC_SUCCESS); + assert_int_equal(buflen, 5); + assert_memory_equal(buf, "test\x0a", 5); + + rv = sc_decompress_alloc(&buf, &buflen, valid_zlib_data, sizeof(valid_zlib_data), COMPRESSION_AUTO); assert_int_equal(rv, SC_SUCCESS); assert_int_equal(buflen, 5); assert_memory_equal(buf, "test\x0a", 5); @@ -163,10 +183,14 @@ static void torture_compression_decompress_alloc_invalid_suffix(void **state) { u8 *buf = NULL; size_t buflen = 0; - size_t datalen = sizeof(invalid_suffix_data); int rv; - rv = sc_decompress_alloc(&buf, &buflen, invalid_suffix_data, datalen, COMPRESSION_AUTO); + rv = sc_decompress_alloc(&buf, &buflen, invalid_suffix_data, sizeof(invalid_suffix_data), COMPRESSION_AUTO); + assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */ + assert_int_equal(buflen, 5); + assert_memory_equal(buf, "test\x0a", 5); + + rv = sc_decompress_alloc(&buf, &buflen, invalid_zlib_suffix_data, sizeof(invalid_zlib_suffix_data), COMPRESSION_AUTO); assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */ assert_int_equal(buflen, 5); assert_memory_equal(buf, "test\x0a", 5); @@ -185,7 +209,7 @@ static void torture_compression_decompress_empty(void **state) rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_AUTO); assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED); - assert_int_equal(buflen, sizeof(buf)); /* Was not touched */ + assert_int_equal(buflen, sizeof(buf)); /* not touched */ } static void torture_compression_decompress_gzip_empty(void **state) @@ -198,7 +222,7 @@ static void torture_compression_decompress_gzip_empty(void **state) rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_GZIP); assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED); - assert_int_equal(buflen, sizeof(buf)); + assert_int_equal(buflen, sizeof(buf)); /* not touched */ } static void torture_compression_decompress_zlib_empty(void **state) @@ -211,7 +235,7 @@ static void torture_compression_decompress_zlib_empty(void **state) rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_ZLIB); assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED); - assert_int_equal(buflen, 0); + assert_int_equal(buflen, sizeof(buf)); /* not touched */ } static void torture_compression_decompress_header(void **state) @@ -256,10 +280,14 @@ static void torture_compression_decompress_valid(void **state) { u8 buf[1024]; size_t buflen = sizeof(buf); - size_t datalen = sizeof(valid_data); int rv; - rv = sc_decompress(buf, &buflen, valid_data, datalen, COMPRESSION_AUTO); + rv = sc_decompress(buf, &buflen, valid_data, sizeof(valid_data), COMPRESSION_AUTO); + assert_int_equal(rv, SC_SUCCESS); + assert_int_equal(buflen, 5); + assert_memory_equal(buf, "test\x0a", 5); + + rv = sc_decompress(buf, &buflen, valid_zlib_data, sizeof(valid_zlib_data), COMPRESSION_AUTO); assert_int_equal(rv, SC_SUCCESS); assert_int_equal(buflen, 5); assert_memory_equal(buf, "test\x0a", 5); @@ -269,13 +297,28 @@ static void torture_compression_decompress_invalid_suffix(void **state) { u8 buf[1024]; size_t buflen = sizeof(buf); - size_t datalen = sizeof(invalid_suffix_data); int rv; - rv = sc_decompress(buf, &buflen, invalid_suffix_data, datalen, COMPRESSION_AUTO); + rv = sc_decompress(buf, &buflen, invalid_suffix_data, sizeof(invalid_suffix_data), COMPRESSION_AUTO); assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */ assert_int_equal(buflen, 5); assert_memory_equal(buf, "test\x0a", 5); + + rv = sc_decompress(buf, &buflen, invalid_zlib_suffix_data, sizeof(invalid_zlib_suffix_data), COMPRESSION_AUTO); + assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */ + assert_int_equal(buflen, 5); + assert_memory_equal(buf, "test\x0a", 5); +} + +static void torture_compression_decompress_zlib_good(void **state) +{ + u8 buf[1024]; + size_t buflen; + int rv; + + buflen = sizeof(buf); + rv = sc_decompress(buf, &buflen, zlib_good, sizeof zlib_good, COMPRESSION_AUTO); + assert_int_equal(rv, SC_SUCCESS); } @@ -302,6 +345,7 @@ int main(void) cmocka_unit_test(torture_compression_decompress_invalid), cmocka_unit_test(torture_compression_decompress_invalid_suffix), cmocka_unit_test(torture_compression_decompress_valid), + cmocka_unit_test(torture_compression_decompress_zlib_good), }; rc = cmocka_run_group_tests(tests, NULL, NULL); diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index 5ee5edfb..55beb631 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -52,7 +52,7 @@ piv_tool_SOURCES = piv-tool.c util.c piv_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) opensc_explorer_SOURCES = opensc-explorer.c util.c opensc_explorer_LDADD = $(OPTIONAL_READLINE_LIBS) -pkcs15_tool_SOURCES = pkcs15-tool.c util.c +pkcs15_tool_SOURCES = pkcs15-tool.c util.c ../pkcs11/pkcs11-display.c ../pkcs11/pkcs11-display.h pkcs15_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) pkcs11_tool_SOURCES = pkcs11-tool.c util.c pkcs11_tool_LDADD = \ diff --git a/src/tools/Makefile.mak b/src/tools/Makefile.mak index 4637a44d..38e5ba4e 100644 --- a/src/tools/Makefile.mak +++ b/src/tools/Makefile.mak @@ -52,6 +52,11 @@ pkcs11-register.exe: pkcs11-register-cmdline.obj fread_to_eof.obj $(LIBS) link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj pkcs11-register-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib mt -manifest exe.manifest -outputresource:$@;1 +pkcs15-tool.exe: pkcs15-tool.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj + cl $(COPTS) /c $*.c + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + .c.exe: cl $(COPTS) /c $< link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib diff --git a/src/tools/apdus b/src/tools/apdus deleted file mode 100644 index 922c3cd4..00000000 --- a/src/tools/apdus +++ /dev/null @@ -1,29 +0,0 @@ -00:22:81:B6:0F:83:0D:5A:5A:43:56:43:41:41:54:41:30:30:30:31 -00:2a:00:be:e4:7f:4e:81:9d:5f:29:01:00:42:0d:5a:5a:43:56:43:41:41:54:41:30:30:30:31:7f:49:4f:06:0a:04:00:7f:00:07:02:02:02:02:03:86:41:04:52:dd:32:ea:fe:1f:bb:b4:00:0c:d9:ce:75:f6:66:36:cf:cf:1e:dd:44:f7:b1:ed:ae:25:b8:41:93:da:04:a9:1c:77:ee:87:f5:c8:f9:59:ed:27:62:00:de:33:ab:57:4c:e9:80:11:35:ff:44:97:a3:71:62:b7:c8:54:8a:0c:5f:20:0e:5a:5a:44:56:43:41:41:54:41:30:30:30:30:35:7f:4c:12:06:09:04:00:7f:00:07:03:01:02:02:53:05:70:03:01:ff:b7:5f:25:06:01:00:00:06:01:01:5f:24:06:01:00:01:00:03:01:5f:37:40:6f:13:ae:9a:6f:4e:dd:b7:83:9f:f3:f0:4d:71:e0:dc:37:7b:c4:b0:8f:ad:29:5e:ed:24:1b:52:43:28:ad:07:30:eb:55:34:97:b4:fb:66:e9:bb:7a:b9:08:15:f0:42:73:f0:9e:75:1d:7f:d4:b8:61:43:9b:4e:e6:53:81:c3 -002281B610830E5A5A445643414154413030303035 -002a00be0001417f4e81fa5f290100420e5a5a4456434141544130303030357f494f060a04007f000702020202038641049bfe7415d73c4a78d60b2cc1bca11b6d5e523969acfb5b756a3be1551b22239c79ae362b838b00669983c0caf6ed0c781d401c95d2b32857de8ce1b619dac4a75f200a5a5a5349543030304f347f4c12060904007f000703010202530500000000045f25060100000902015f2406010000090206655e732d060904007f0007030103028020b02baa51a94fac0954df204d61fe22da1d408d45db4aa1d70e600dad4faf6799732d060904007f0007030103018020c72e13582f01ba068dd1aac29a2428c0c54ab9c204fd53b3f13e8290e21e50f95f374083c5b441fec5b18efd1caa4a11b8e1cede0a8b42d442f00d7f604e429f339b4e3e6c06f9e76a2daa82c1722ee137a89038b969c634561581e6c26d9f6fa75c52 -00:22:81:A4:53:80:0A:04:00:7F:00:07:02:02:02:02:03:83:0A:5A:5A:53:49:54:30:30:30:4F:34:91:20:88:E5:F2:C6:11:18:0D:0A:C1:0E:BD:E6:FC:2A:5E:62:41:79:C0:A5:77:C3:E4:88:52:DD:81:A4:CD:F7:90:51:67:17:73:15:06:09:04:00:7F:00:07:03:01:04:02:53:08:32:30:31:30:30:39:32:34 -00:84:00:00:08 -00820000400C9E7DB72CB0FAEA15B00FECAE0257546446A9395862239AF240C3C29E857F8403345817760FE13F6597F04D2F7330B59065F68DF71EF7FDEC86743CDE2869DD -00a4000c023f00 -00:A4:02:0C:02:01:1D -00:b0:00:00:80 -00B0008080 -00b0010080 -00:B0:01:80:80 -00:b0:02:00:80 -00B0028080 -00b0030080 -00:B0:03:80:80 -00:b0:04:00:80 -00B0048080 -00b0050080 -00:B0:05:80:80 -00:b0:06:00:80 -00B0068080 -00b0070080 -00:B0:07:80:80 -00:22:41:a4:0c:80:0a:04:00:7f:00:07:02:02:03:02:02 -00860000457C43804104239E3D05EEB059117D30F86AEB5AE7D12E0EBF758889C79115F2A13DC1BB570A5CAD91A384337C09D1B74BED1C0FF195A7C3EA3A2CEDF86DDEF7B95D1FD1B35D00 -0020001006010203040506 - diff --git a/src/tools/egk-tool-cmdline.c b/src/tools/egk-tool-cmdline.c index 22851b0e..6b64cf33 100644 --- a/src/tools/egk-tool-cmdline.c +++ b/src/tools/egk-tool-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=egk-tool-cmdline --output-dir=. @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: egk-tool [OPTIONS]..."; +const char *gengetopt_args_info_usage = "Usage: egk-tool [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; @@ -36,7 +36,7 @@ const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", - " -r, --reader=STRING Number of the reader to use. By default, the first\n reader with a present card is used. If the arguement\n is an ATR, the reader with a matching card will be\n chosen.", + " -r, --reader=STRING Number of the reader to use. By default, the first\n reader with a present card is used. If the argument\n is an ATR, the reader with a matching card will be\n chosen.", " -v, --verbose Use (several times) to be more verbose", "\nHealth Care Application (HCA):", " --pd Show 'Persönliche Versicherungsdaten' (XML)\n (default=off)", @@ -122,19 +122,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -507,7 +513,8 @@ int update_arg(void *field, char **orig_field, break; }; - + FIX_UNUSED(stop_char); + /* store the original value */ switch(arg_type) { case ARG_NO: @@ -546,10 +553,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -593,7 +606,7 @@ cmdline_parser_internal ( cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); - case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ + case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ if (update_arg( (void *)&(args_info->reader_arg), @@ -694,3 +707,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/egk-tool-cmdline.h b/src/tools/egk-tool-cmdline.h index 3fb36efa..f231389c 100644 --- a/src/tools/egk-tool-cmdline.h +++ b/src/tools/egk-tool-cmdline.h @@ -1,9 +1,9 @@ /** @file egk-tool-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef EGK_TOOL_CMDLINE_H #define EGK_TOOL_CMDLINE_H @@ -39,9 +39,9 @@ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ - char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ - char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. original value given at command line. */ - const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. help description. */ + char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ + char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. original value given at command line. */ + const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. help description. */ unsigned int verbose_min; /**< @brief Use (several times) to be more verbose's minimum occurreces */ unsigned int verbose_max; /**< @brief Use (several times) to be more verbose's maximum occurreces */ const char *verbose_help; /**< @brief Use (several times) to be more verbose help description. */ diff --git a/src/tools/egk-tool.ggo.in b/src/tools/egk-tool.ggo.in index 6b709461..dc7dcf2c 100644 --- a/src/tools/egk-tool.ggo.in +++ b/src/tools/egk-tool.ggo.in @@ -2,7 +2,7 @@ package "egk-tool" purpose "@PACKAGE_SUMMARY@" option "reader" r - "Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen." + "Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen." string optional option "verbose" v diff --git a/src/tools/gids-tool.c b/src/tools/gids-tool.c index 5902ae16..b9b0a4a0 100644 --- a/src/tools/gids-tool.c +++ b/src/tools/gids-tool.c @@ -115,8 +115,7 @@ static int initialize(sc_card_t *card, const char *so_pin, const char *user_pin, return -1; } - if (len == 0) { - } else if (len != 24) { + if (len != 24) { fprintf(stderr, "The admin key must be a hexadecimal string of 48 characters\n"); return -1; } @@ -417,7 +416,7 @@ static int print_info(sc_card_t *card) { } for (i = 0; i < cmaprecordnum; i++) { printf(" container: %d\n", i); - wprintf(L" guid: %ls\n", cmaprecords[i].wszGuid); + wprintf(L" guid: %s\n", cmaprecords[i].wszGuid); printf(" bFlags: "); if (cmaprecords[i].bFlags & CONTAINER_MAP_VALID_CONTAINER) { printf("Valid container"); diff --git a/src/tools/goid-tool-cmdline.c b/src/tools/goid-tool-cmdline.c index 6e020347..51d27883 100644 --- a/src/tools/goid-tool-cmdline.c +++ b/src/tools/goid-tool-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=goid-tool-cmdline --output-dir=. @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: goid-tool [OPTIONS]..."; +const char *gengetopt_args_info_usage = "Usage: goid-tool [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; @@ -36,7 +36,7 @@ const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", - " -r, --reader=STRING Number of the reader to use. By default, the\n first reader with a present card is used. If\n the arguement is an ATR, the reader with a\n matching card will be chosen.", + " -r, --reader=STRING Number of the reader to use. By default, the\n first reader with a present card is used. If\n the argument is an ATR, the reader with a\n matching card will be chosen.", " -v, --verbose Use (several times) to be more verbose", " -p, --verify-pin Verify PIN", " -b, --verify-bio Verify finger print", @@ -231,19 +231,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -1142,10 +1148,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -1208,7 +1220,7 @@ cmdline_parser_internal ( cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); - case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ + case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ if (update_arg( (void *)&(args_info->reader_arg), @@ -1634,3 +1646,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/goid-tool-cmdline.h b/src/tools/goid-tool-cmdline.h index f684b6df..9685d56f 100644 --- a/src/tools/goid-tool-cmdline.h +++ b/src/tools/goid-tool-cmdline.h @@ -1,9 +1,9 @@ /** @file goid-tool-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef GOID_TOOL_CMDLINE_H #define GOID_TOOL_CMDLINE_H @@ -39,9 +39,9 @@ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ - char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ - char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. original value given at command line. */ - const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. help description. */ + char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ + char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. original value given at command line. */ + const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. help description. */ unsigned int verbose_min; /**< @brief Use (several times) to be more verbose's minimum occurreces */ unsigned int verbose_max; /**< @brief Use (several times) to be more verbose's maximum occurreces */ const char *verbose_help; /**< @brief Use (several times) to be more verbose help description. */ diff --git a/src/tools/goid-tool.ggo.in b/src/tools/goid-tool.ggo.in index 3034e56c..e606da76 100644 --- a/src/tools/goid-tool.ggo.in +++ b/src/tools/goid-tool.ggo.in @@ -2,7 +2,7 @@ package "goid-tool" purpose "@PACKAGE_SUMMARY@" option "reader" r - "Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen." + "Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen." string optional option "verbose" v "Use (several times) to be more verbose" diff --git a/src/tools/npa-tool-cmdline.c b/src/tools/npa-tool-cmdline.c index 2918888a..68a4b94b 100644 --- a/src/tools/npa-tool-cmdline.c +++ b/src/tools/npa-tool-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=npa-tool-cmdline --output-dir=. @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: npa-tool [OPTIONS]..."; +const char *gengetopt_args_info_usage = "Usage: npa-tool [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; @@ -36,7 +36,7 @@ const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", - " -r, --reader=STRING Number of the reader to use. By default, the\n first reader with a present card is used. If\n the arguement is an ATR, the reader with a\n matching card will be chosen.", + " -r, --reader=STRING Number of the reader to use. By default, the\n first reader with a present card is used. If\n the argument is an ATR, the reader with a\n matching card will be chosen.", " -v, --verbose Use (several times) to be more verbose", "\nPassword Authenticated Connection Establishment (PACE):", " -p, --pin[=STRING] Run PACE with (transport) eID-PIN", @@ -54,8 +54,8 @@ const char *gengetopt_args_info_help[] = { " --chat=HEX_STRING Card holder authorization template to use\n (default is terminal's CHAT). Use\n 7F4C0E060904007F000703010203530103 to trigger\n EAC on the CAT-C (Komfortleser).", " -A, --auxiliary-data=HEX_STRING\n Terminal's auxiliary data (default is\n determined by verification of validity, age\n and community ID).", " -P, --private-key=FILENAME Terminal's private key", - " --cvc-dir=DIRECTORY Where to look for the CVCA's certificate\n (default=`/home/fm/.local/etc/eac/cvc')", - " --x509-dir=DIRECTORY Where to look for the CSCA's certificate\n (default=`/home/fm/.local/etc/eac/x509')", + " --cvc-dir=DIRECTORY Where to look for the CVCA's certificate\n (default=`')", + " --x509-dir=DIRECTORY Where to look for the CSCA's certificate\n (default=`')", " --disable-ta-checks Disable checking the validity period of CV\n certificates (default=off)", " --disable-ca-checks Disable passive authentication (default=off)", "\nRead and write data groups:", @@ -206,9 +206,9 @@ void clear_args (struct gengetopt_args_info *args_info) args_info->auxiliary_data_orig = NULL; args_info->private_key_arg = NULL; args_info->private_key_orig = NULL; - args_info->cvc_dir_arg = gengetopt_strdup ("/home/fm/.local/etc/eac/cvc"); + args_info->cvc_dir_arg = gengetopt_strdup (""); args_info->cvc_dir_orig = NULL; - args_info->x509_dir_arg = gengetopt_strdup ("/home/fm/.local/etc/eac/x509"); + args_info->x509_dir_arg = gengetopt_strdup (""); args_info->x509_dir_orig = NULL; args_info->disable_ta_checks_flag = 0; args_info->disable_ca_checks_flag = 0; @@ -334,19 +334,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -978,7 +984,8 @@ int update_arg(void *field, char **orig_field, break; }; - + FIX_UNUSED(stop_char); + /* store the original value */ switch(arg_type) { case ARG_NO: @@ -1139,10 +1146,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -1232,7 +1245,7 @@ cmdline_parser_internal ( cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); - case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ + case 'r': /* Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ if (update_arg( (void *)&(args_info->reader_arg), @@ -1433,7 +1446,7 @@ cmdline_parser_internal ( if (update_arg( (void *)&(args_info->cvc_dir_arg), &(args_info->cvc_dir_orig), &(args_info->cvc_dir_given), - &(local_args_info.cvc_dir_given), optarg, 0, "/home/fm/.local/etc/eac/cvc", ARG_STRING, + &(local_args_info.cvc_dir_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "cvc-dir", '-', additional_error)) @@ -1447,7 +1460,7 @@ cmdline_parser_internal ( if (update_arg( (void *)&(args_info->x509_dir_arg), &(args_info->x509_dir_orig), &(args_info->x509_dir_given), - &(local_args_info.x509_dir_given), optarg, 0, "/home/fm/.local/etc/eac/x509", ARG_STRING, + &(local_args_info.x509_dir_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "x509-dir", '-', additional_error)) @@ -1907,3 +1920,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/npa-tool-cmdline.h b/src/tools/npa-tool-cmdline.h index ad42cc0b..6412362f 100644 --- a/src/tools/npa-tool-cmdline.h +++ b/src/tools/npa-tool-cmdline.h @@ -1,9 +1,9 @@ /** @file npa-tool-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef NPA_TOOL_CMDLINE_H #define NPA_TOOL_CMDLINE_H @@ -39,9 +39,9 @@ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ - char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen.. */ - char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. original value given at command line. */ - const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen. help description. */ + char * reader_arg; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen.. */ + char * reader_orig; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. original value given at command line. */ + const char *reader_help; /**< @brief Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen. help description. */ unsigned int verbose_min; /**< @brief Use (several times) to be more verbose's minimum occurreces */ unsigned int verbose_max; /**< @brief Use (several times) to be more verbose's maximum occurreces */ const char *verbose_help; /**< @brief Use (several times) to be more verbose help description. */ @@ -83,10 +83,10 @@ struct gengetopt_args_info char * private_key_arg; /**< @brief Terminal's private key. */ char * private_key_orig; /**< @brief Terminal's private key original value given at command line. */ const char *private_key_help; /**< @brief Terminal's private key help description. */ - char * cvc_dir_arg; /**< @brief Where to look for the CVCA's certificate (default='/home/fm/.local/etc/eac/cvc'). */ + char * cvc_dir_arg; /**< @brief Where to look for the CVCA's certificate (default=''). */ char * cvc_dir_orig; /**< @brief Where to look for the CVCA's certificate original value given at command line. */ const char *cvc_dir_help; /**< @brief Where to look for the CVCA's certificate help description. */ - char * x509_dir_arg; /**< @brief Where to look for the CSCA's certificate (default='/home/fm/.local/etc/eac/x509'). */ + char * x509_dir_arg; /**< @brief Where to look for the CSCA's certificate (default=''). */ char * x509_dir_orig; /**< @brief Where to look for the CSCA's certificate original value given at command line. */ const char *x509_dir_help; /**< @brief Where to look for the CSCA's certificate help description. */ int disable_ta_checks_flag; /**< @brief Disable checking the validity period of CV certificates (default=off). */ diff --git a/src/tools/npa-tool.ggo.in b/src/tools/npa-tool.ggo.in index e27889ca..f2439a72 100644 --- a/src/tools/npa-tool.ggo.in +++ b/src/tools/npa-tool.ggo.in @@ -2,7 +2,7 @@ package "npa-tool" purpose "@PACKAGE_SUMMARY@" option "reader" r - "Number of the reader to use. By default, the first reader with a present card is used. If the arguement is an ATR, the reader with a matching card will be chosen." + "Number of the reader to use. By default, the first reader with a present card is used. If the argument is an ATR, the reader with a matching card will be chosen." string optional option "verbose" v diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c index 63db8b49..25d982f4 100644 --- a/src/tools/openpgp-tool.c +++ b/src/tools/openpgp-tool.c @@ -1,7 +1,7 @@ /* * openpgp-tool.c: OpenPGP card utility * - * Copyright (C) 2012 Peter Marschall + * Copyright (C) 2012-2020 Peter Marschall * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,6 +47,7 @@ #include "libopensc/errors.h" #include "util.h" #include "libopensc/log.h" +#include "libopensc/card-openpgp.h" #define OPT_RAW 256 #define OPT_PRETTY 257 @@ -194,7 +195,7 @@ static void show_version(void) fprintf(stderr, "openpgp-tool - OpenPGP card utility version " PACKAGE_VERSION "\n" "\n" - "Copyright (c) 2012-18 Peter Marschall \n" + "Copyright (c) 2012-2020 Peter Marschall \n" "Licensed under LGPL v2\n"); } @@ -292,15 +293,20 @@ static char *prettify_manufacturer(u8 *data, size_t length) case 0x0008: return "LogoEmail"; case 0x0009: return "Fidesmo"; case 0x000A: return "Dangerous Things"; + case 0x000B: return "Feitian Technologies"; case 0x002A: return "Magrathea"; case 0x0042: return "GnuPG e.V."; case 0x1337: return "Warsaw Hackerspace"; case 0x2342: return "warpzone"; /* hackerspace Muenster. */ + case 0x4354: return "Confidential Technologies"; /* cotech.de */ + case 0x5443: return "TIF-IT e.V."; case 0x63AF: return "Trustica"; + case 0xBA53: return "c-base e.V."; case 0xBD0E: return "Paranoidlabs"; case 0xF517: return "FSIJ"; + case 0xF5EC: return "F-Secure"; /* 0x0000 and 0xFFFF are defined as test cards per spec, 0xFF00 to 0xFFFE are assigned for use with randomly created @@ -611,19 +617,25 @@ static int do_info(sc_card_t *card, const struct ef_name_map *map) static int do_dump_do(sc_card_t *card, unsigned int tag) { + struct pgp_priv_data *priv = DRVDATA(card); int r; size_t length; - unsigned char buffer[254]; // Private DO are specified up to 254 bytes - - memset(buffer, '\0', sizeof(buffer)); + unsigned char *buffer; if (tag < 0x101 || tag > 0x104) { util_error("illegal DO identifier %04X", tag); return SC_ERROR_INVALID_ARGUMENTS; } - r = sc_get_data(card, tag, buffer, sizeof(buffer)); + buffer = calloc(priv->max_specialDO_size, sizeof(unsigned char)); + if (buffer == NULL) { + util_error("error allocating memory for DO %04X", tag); + return SC_ERROR_OUT_OF_MEMORY; + } + + r = sc_get_data(card, tag, buffer, priv->max_specialDO_size); if (r < 0) { + free(buffer); util_error("failed to get data object DO %04X: %s", tag, sc_strerror(r)); if (SC_ERROR_SECURITY_STATUS_NOT_SATISFIED == r) { util_error("make sure the 'verify' and 'pin' parameters are correct"); @@ -655,12 +667,15 @@ static int do_dump_do(sc_card_t *card, unsigned int tag) clearerr(stdout); close(tmp); - if (length != (size_t) r) /* fail on write errors */ + if (length != (size_t) r) { /* fail on write errors */ + free(buffer); return EXIT_FAILURE; + } } else { util_hex_dump_asc(stdout, buffer, length, -1); } + free(buffer); return EXIT_SUCCESS; } @@ -686,8 +701,11 @@ int do_genkey(sc_card_t *card, u8 in_key_id, const char *keytype) /* generate key depending on keytype passed */ if (strncasecmp("RSA", keytype, strlen("RSA")) == 0) { - size_t keylen = 2048; /* default length for RSA keys */ const char *keylen_ptr = keytype + strlen("RSA"); + size_t keylen = 2048; /* default key length for RSA keys */ + size_t expolen = 32; /* default exponent length for RSA keys */ + u8 keyformat = SC_OPENPGP_KEYFORMAT_RSA_STD; /* default keyformat */ + char pathstr[SC_MAX_PATH_STRING_SIZE]; /* try to get key length from keytype, e.g. "rsa3072" -> 3072 */ if (strlen(keylen_ptr) > 0) { @@ -701,14 +719,29 @@ int do_genkey(sc_card_t *card, u8 in_key_id, const char *keytype) } } + /* get some algorithm attributes from respective DO - ignore errors */ + snprintf(pathstr, sizeof(pathstr), "006E007300C%d", in_key_id); + sc_format_path(pathstr, &path); + if (sc_select_file(card, &path, &file) >= 0) { + u8 attrs[6]; /* algorithm attrs DO for RSA is <= 6 bytes */ + + r = sc_read_binary(card, 0, attrs, sizeof(attrs), 0); + if (r >= 5 && attrs[0] == SC_OPENPGP_KEYALGO_RSA) { + expolen = (unsigned short) attrs[3] << 8 + | (unsigned short) attrs[4]; + if (r > 5) + keyformat = attrs[5]; + } + } + /* set key_info */ key_info.key_id = in_key_id; key_info.algorithm = SC_OPENPGP_KEYALGO_RSA; key_info.u.rsa.modulus_len = keylen; key_info.u.rsa.modulus = calloc(BYTES4BITS(keylen), 1); - /* The OpenPGP supports only 32-bit exponent. */ - key_info.u.rsa.exponent_len = 32; - key_info.u.rsa.exponent = calloc(BYTES4BITS(key_info.u.rsa.exponent_len), 1); + key_info.u.rsa.exponent_len = expolen; + key_info.u.rsa.exponent = calloc(BYTES4BITS(expolen), 1); + key_info.u.rsa.keyformat = keyformat; r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); free(key_info.u.rsa.modulus); @@ -878,6 +911,14 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + /* force OpenPGP card driver */ + r = sc_set_card_driver(ctx, "openpgp"); + if (r) { + sc_release_context(ctx); + util_fatal("OpenPGP card driver not found!\n"); + return EXIT_FAILURE; + } + r = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); if (r) { sc_release_context(ctx); diff --git a/src/tools/opensc-asn1-cmdline.c b/src/tools/opensc-asn1-cmdline.c index f8b20b94..13e5412a 100644 --- a/src/tools/opensc-asn1-cmdline.c +++ b/src/tools/opensc-asn1-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=opensc-asn1-cmdline --output-dir=. --unamed-opts @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: opensc-asn1 [OPTIONS]... [FILES]..."; +const char *gengetopt_args_info_usage = "Usage: opensc-asn1 [OPTION]... [FILE]..."; const char *gengetopt_args_info_versiontext = ""; @@ -91,19 +91,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -315,10 +321,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -370,6 +382,7 @@ cmdline_parser_internal ( + FIX_UNUSED(check_required); cmdline_parser_release (&local_args_info); @@ -407,3 +420,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/opensc-asn1-cmdline.h b/src/tools/opensc-asn1-cmdline.h index 43baee5b..93073da9 100644 --- a/src/tools/opensc-asn1-cmdline.h +++ b/src/tools/opensc-asn1-cmdline.h @@ -1,9 +1,9 @@ /** @file opensc-asn1-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef OPENSC_ASN1_CMDLINE_H #define OPENSC_ASN1_CMDLINE_H @@ -43,8 +43,8 @@ struct gengetopt_args_info unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ - char **inputs ; /**< @brief unamed options (options without names) */ - unsigned inputs_num ; /**< @brief unamed options number */ + char **inputs ; /**< @brief unnamed options (options without names) */ + unsigned inputs_num ; /**< @brief unnamed options number */ } ; /** @brief The additional parameters to pass to parser functions */ diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index fb116546..ae86e478 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef ENABLE_READLINE #include #include @@ -371,7 +372,8 @@ arg_to_path(const char *arg, sc_path_t *path, int is_id) } else { /* file id */ u8 cbuf[2]; - if (arg_to_fid(arg, cbuf) < 0) + + if (arg_to_fid(arg, cbuf) < 0) return -1; if ((cbuf[0] == 0x3F && cbuf[1] == 0x00) || is_id) { @@ -380,8 +382,8 @@ arg_to_path(const char *arg, sc_path_t *path, int is_id) path->type = (is_id) ? SC_PATH_TYPE_FILE_ID : SC_PATH_TYPE_PATH; } else { *path = current_path; - if (path->type == SC_PATH_TYPE_DF_NAME) { - if (path->len > sizeof(path->aid.value)) { + if (path->type == SC_PATH_TYPE_DF_NAME) { + if (path->len > sizeof(path->aid.value)) { fprintf(stderr, "Invalid length of DF_NAME path\n"); return -1; } @@ -487,24 +489,22 @@ static int pattern_match(const char *pattern, const char *string) static int do_ls(int argc, char **argv) { - u8 buf[256], *cur = buf; + u8 buf[SC_MAX_EXT_APDU_RESP_SIZE], *cur = buf; int r, count; - memset(buf, 0, sizeof buf); + memset(buf, 0, sizeof(buf)); r = sc_lock(card); if (r == SC_SUCCESS) r = sc_list_files(card, buf, sizeof(buf)); sc_unlock(card); if (r < 0) { - check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file); + check_ret(r, SC_AC_OP_LIST_FILES, "Unable to receive file listing", current_file); return -1; } count = r; printf("FileID\tType Size\n"); while (count >= 2) { - sc_path_t path; - sc_file_t *file = NULL; - char filename[10]; + char filename[SC_MAX_PATH_STRING_SIZE]; int i = 0; int matches = 0; @@ -521,12 +521,15 @@ static int do_ls(int argc, char **argv) /* if any filename pattern were given, filter only matching file names */ if (argc == 0 || matches) { + sc_path_t path; + sc_file_t *file = NULL; + if (current_path.type != SC_PATH_TYPE_DF_NAME) { path = current_path; sc_append_path_id(&path, cur, 2); } else { if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, cur, 2, 0, 0) != SC_SUCCESS) { - fprintf(stderr, "unable to set path.\n"); + fprintf(stderr, "Unable to set path.\n"); die(1); } } @@ -536,10 +539,11 @@ static int do_ls(int argc, char **argv) r = sc_select_file(card, &path, &file); sc_unlock(card); if (r) { - fprintf(stderr, " %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r)); + fprintf(stderr, "Unable to select file %02X%02X: %s\n", + cur[0], cur[1], sc_strerror(r)); } else { file->id = (cur[0] << 8) | cur[1]; - print_file(file); + print_file(file); sc_file_free(file); } } @@ -552,14 +556,11 @@ static int do_ls(int argc, char **argv) static int do_find(int argc, char **argv) { - u8 fid[2], end[2]; + u8 fid[2] = { 0x00, 0x00 }; + u8 end[2] = { 0xFF, 0xFF }; sc_path_t path; int r; - fid[0] = 0; - fid[1] = 0; - end[0] = 0xFF; - end[1] = 0xFF; switch (argc) { case 2: if (arg_to_fid(argv[1], end) != 0) @@ -584,10 +585,10 @@ static int do_find(int argc, char **argv) if (current_path.type != SC_PATH_TYPE_DF_NAME) { path = current_path; - sc_append_path_id(&path, fid, sizeof fid); + sc_append_path_id(&path, fid, sizeof(fid)); } else { - if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0) != SC_SUCCESS) { - fprintf(stderr, "unable to set path.\n"); + if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0) != SC_SUCCESS) { + fprintf(stderr, "Unable to set path.\n"); die(1); } } @@ -620,14 +621,12 @@ static int do_find(int argc, char **argv) static int do_find_tags(int argc, char **argv) { - u8 start[2], end[2], rbuf[256]; + u8 start[2] = { 0x00, 0x00 }; + u8 end[2] = { 0xFF, 0xFF }; + u8 rbuf[SC_MAX_EXT_APDU_RESP_SIZE]; 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) @@ -652,7 +651,9 @@ static int do_find_tags(int argc, char **argv) r = sc_lock(card); if (r == SC_SUCCESS) - r = sc_get_data(card, tag, rbuf, sizeof rbuf); + r = sc_get_data(card, tag, rbuf, sizeof(rbuf)); + else + r = SC_ERROR_READER_LOCKED; sc_unlock(card); if (r >= 0) { printf(" %04X ", tag); @@ -704,10 +705,10 @@ static int do_cd(int argc, char **argv) return -1; } - if (path.type == SC_PATH_TYPE_DF_NAME) { + if (path.type == SC_PATH_TYPE_DF_NAME) { sc_format_path("3F00", &path); } - else { + else { path.len -= 2; } @@ -735,7 +736,8 @@ static int do_cd(int argc, char **argv) check_ret(r, SC_AC_OP_SELECT, "unable to select DF", current_file); return -1; } - if ((file->type != SC_FILE_TYPE_DF) && (card->type != SC_CARD_TYPE_BELPIC_EID)) { + if ((file->type != SC_FILE_TYPE_DF) && (file->type != SC_FILE_TYPE_UNKNOWN) && + (card->type != SC_CARD_TYPE_BELPIC_EID)) { fprintf(stderr, "Error: file is not a DF.\n"); sc_file_free(file); select_current_path_or_die(); @@ -748,35 +750,29 @@ static int do_cd(int argc, char **argv) return 0; } -static int read_and_util_print_binary_file(sc_file_t *file) +static int read_and_print_binary_file(sc_file_t *file) { - unsigned char *buf = NULL; + u8 *buf; + size_t size = (file->size > 0) ? file->size : SC_MAX_EXT_APDU_RESP_SIZE; int r, ret = -1; - size_t size; - if (file->size) { - size = file->size; - } else { - size = 1024; - } - buf = malloc(size); - if (!buf) + buf = calloc(size, 1); + if (buf == NULL) return -1; r = sc_lock(card); if (r == SC_SUCCESS) r = sc_read_binary(card, 0, buf, size, 0); sc_unlock(card); - if (r < 0) { - check_ret(r, SC_AC_OP_READ, "read failed", file); + if (r < 0) { + check_ret(r, SC_AC_OP_READ, "Read failed", file); goto err; } - if ((r == 0) && (card->type == SC_CARD_TYPE_BELPIC_EID)) - goto err; util_hex_dump_asc(stdout, buf, r, 0); ret = 0; + err: free(buf); return ret; @@ -784,7 +780,7 @@ err: static int read_and_print_record_file(sc_file_t *file, unsigned char sfi) { - u8 buf[256]; + u8 buf[SC_MAX_EXT_APDU_RESP_SIZE]; int rec, r; for (rec = 1; ; rec++) { @@ -792,16 +788,20 @@ static int read_and_print_record_file(sc_file_t *file, unsigned char sfi) if (r == SC_SUCCESS) r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR | sfi); + else + r = SC_ERROR_READER_LOCKED; sc_unlock(card); if (r == SC_ERROR_RECORD_NOT_FOUND) return 0; if (r < 0) { - check_ret(r, SC_AC_OP_READ, "read failed", file); + check_ret(r, SC_AC_OP_READ, "Read failed", file); return -1; } printf("Record %d:\n", rec); util_hex_dump_asc(stdout, buf, r, 0); } + + return 0; } static int do_cat(int argc, char **argv) @@ -858,7 +858,7 @@ static int do_cat(int argc, char **argv) goto err; } if (file->ef_structure == SC_FILE_EF_TRANSPARENT && !sfi) - read_and_util_print_binary_file(file); + read_and_print_binary_file(file); else read_and_print_record_file(file, sfi); @@ -900,13 +900,15 @@ static int do_info(int argc, char **argv) } else return usage(do_info); - if(!file->type_attr_len) + if (!file->type_attr_len) st = "Unknown File"; switch (file->type) { case SC_FILE_TYPE_WORKING_EF: + st = "Working Elementary File"; + break; case SC_FILE_TYPE_INTERNAL_EF: - st = "Elementary File"; + st = "Internal Elementary File"; break; case SC_FILE_TYPE_DF: st = "Dedicated File"; @@ -918,8 +920,8 @@ static int do_info(int argc, char **argv) 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); + printf("\n\n%-25s%s\n", "File path:", path_to_filename(&path, '/')); + printf("%-25s%"SC_FORMAT_LEN_SIZE_T"u bytes\n", "File size:", file->size); if (file->type == SC_FILE_TYPE_DF) { static const id2str_t ac_ops_df[] = { @@ -936,7 +938,7 @@ static int do_info(int argc, char **argv) }; if (file->namelen) { - printf("%-15s", "DF name:"); + printf("%-25s", "DF name:"); util_print_binary(stdout, file->name, file->namelen); printf("\n"); } @@ -969,7 +971,15 @@ static int do_info(int argc, char **argv) for (i = 0; ef_type_name[i].str != NULL; i++) if (file->ef_structure == ef_type_name[i].id) ef_type = ef_type_name[i].str; - printf("%-15s%s\n", "EF structure:", ef_type); + printf("%-25s%s\n", "EF structure:", ef_type); + + if (file->record_count > 0) + printf("%-25s%"SC_FORMAT_LEN_SIZE_T"u\n", + "Number of records:", file->record_count); + + if (file->record_length > 0) + printf("%-25s%"SC_FORMAT_LEN_SIZE_T"u bytes\n", + "Max. record size:", file->record_length); ac_ops = ac_ops_ef; } @@ -979,16 +989,21 @@ static int do_info(int argc, char **argv) printf("ACL for %s:%*s %s\n", ac_ops[i].str, - (12 > len) ? (12 - len) : 0, "", + (15 > len) ? (15 - len) : 0, "", util_acl_to_str(sc_file_get_acl_entry(file, ac_ops[i].id))); } - if (file->prop_attr_len) { + if (file->type_attr_len > 0) { + printf("%-25s", "Type attributes:"); + util_hex_dump(stdout, file->type_attr, file->type_attr_len, " "); + printf("\n"); + } + if (file->prop_attr_len > 0) { printf("%-25s", "Proprietary attributes:"); util_hex_dump(stdout, file->prop_attr, file->prop_attr_len, " "); printf("\n"); } - if (file->sec_attr_len) { + if (file->sec_attr_len > 0) { printf("%-25s", "Security attributes:"); util_hex_dump(stdout, file->sec_attr, file->sec_attr_len, " "); printf("\n"); @@ -1174,7 +1189,7 @@ static int do_verify(int argc, char **argv) { SC_AC_NONE, NULL, } }; int r, tries_left = -1; - u8 buf[64]; + u8 buf[SC_MAX_PIN_SIZE]; size_t buflen = sizeof(buf), i; struct sc_pin_cmd_data data; int prefix_len = 0; @@ -1259,8 +1274,8 @@ static int do_verify(int argc, char **argv) static int do_change(int argc, char **argv) { int ref, r, tries_left = -1; - u8 oldpin[64]; - u8 newpin[64]; + u8 oldpin[SC_MAX_PIN_SIZE]; + u8 newpin[SC_MAX_PIN_SIZE]; size_t oldpinlen = 0; size_t newpinlen = 0; struct sc_pin_cmd_data data; @@ -1324,8 +1339,8 @@ static int do_change(int argc, char **argv) static int do_unblock(int argc, char **argv) { int ref, r; - u8 puk[64]; - u8 newpin[64]; + u8 puk[SC_MAX_PIN_SIZE]; + u8 newpin[SC_MAX_PIN_SIZE]; size_t puklen = 0; size_t newpinlen = 0; struct sc_pin_cmd_data data; @@ -1383,7 +1398,7 @@ static int do_unblock(int argc, char **argv) static int do_get(int argc, char **argv) { - u8 buf[256]; + u8 buf[SC_MAX_EXT_APDU_RESP_SIZE]; int r, err = 1; size_t count = 0; unsigned int idx = 0; @@ -1410,11 +1425,11 @@ static int do_get(int argc, char **argv) r = sc_select_file(card, &path, &file); sc_unlock(card); if (r || file == NULL) { - check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); + check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file); goto err; } if (file->type != SC_FILE_TYPE_WORKING_EF || file->ef_structure != SC_FILE_EF_TRANSPARENT) { - fprintf(stderr, "only transparent working EFs may be read\n"); + fprintf(stderr, "Only transparent working EFs may be read\n"); goto err; } count = file->size; @@ -1424,11 +1439,11 @@ static int do_get(int argc, char **argv) r = sc_read_binary(card, idx, buf, c, 0); if (r < 0) { - check_ret(r, SC_AC_OP_READ, "read failed", file); + check_ret(r, SC_AC_OP_READ, "Read failed", file); goto err; } if ((r != c) && (card->type != SC_CARD_TYPE_BELPIC_EID)) { - fprintf(stderr, "expecting %d, got only %d bytes.\n", c, r); + fprintf(stderr, "Expecting %d, got only %d bytes.\n", c, r); goto err; } if ((r == 0) && (card->type == SC_CARD_TYPE_BELPIC_EID)) @@ -1456,7 +1471,7 @@ err: static int do_update_binary(int argc, char **argv) { - u8 buf[240]; + u8 buf[SC_MAX_EXT_APDU_DATA_SIZE]; size_t buflen = sizeof(buf); int r, err = 1; int offs; @@ -1467,13 +1482,11 @@ static int do_update_binary(int argc, char **argv) return usage(do_update_binary); if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_update_binary); - offs = strtol(argv[1],NULL,10); - - printf("in: %i; %s\n", offs, argv[2]); + offs = strtol(argv[1], NULL, 10); r = parse_string_or_hexdata(argv[2], buf, &buflen); if (r < 0) { - fprintf(stderr, "unable to parse data\n"); + fprintf(stderr, "Unable to parse input data: %s\n", sc_strerror(r)); return -1; } @@ -1482,11 +1495,11 @@ static int do_update_binary(int argc, char **argv) r = sc_select_file(card, &path, &file); sc_unlock(card); if (r) { - check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); + check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file); return -1; } - if (file->ef_structure != SC_FILE_EF_TRANSPARENT) { + if (file->ef_structure != SC_FILE_EF_TRANSPARENT) { fprintf(stderr, "EF structure should be SC_FILE_EF_TRANSPARENT\n"); goto err; } @@ -1496,11 +1509,11 @@ static int do_update_binary(int argc, char **argv) r = sc_update_binary(card, offs, buf, buflen, 0); sc_unlock(card); if (r < 0) { - fprintf(stderr, "Cannot update %04X; return %i\n", file->id, r); + fprintf(stderr, "Cannot update %04X: %s\n", file->id, sc_strerror(r)); goto err; } - printf("Total of %d bytes written to %04X at %i offset.\n", + printf("Total of %d bytes written to %04X at offset %d.\n", r, file->id, offs); err = 0; @@ -1512,9 +1525,9 @@ err: static int do_update_record(int argc, char **argv) { - u8 buf[240]; + u8 buf[SC_MAX_EXT_APDU_DATA_SIZE]; size_t buflen; - int r, i, err = 1; + int r, err = 1; size_t rec, offs; sc_path_t path; sc_file_t *file; @@ -1523,52 +1536,61 @@ static int do_update_record(int argc, char **argv) return usage(do_update_record); if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_update_record); - rec = strtol(argv[1],NULL,10); - offs = strtol(argv[2],NULL,10); - - printf("in: %"SC_FORMAT_LEN_SIZE_T"u; %"SC_FORMAT_LEN_SIZE_T"u; %s\n", rec, offs, argv[3]); + rec = strtol(argv[1], NULL, 10); + offs = strtol(argv[2], NULL, 10); r = sc_lock(card); if (r == SC_SUCCESS) r = sc_select_file(card, &path, &file); sc_unlock(card); if (r) { - check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); + check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file); return -1; } - if (file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE) { + if (file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE) { fprintf(stderr, "EF structure should be SC_FILE_EF_LINEAR_VARIABLE\n"); goto err; - } else if (rec < 1 || rec > file->record_count) { + } + + if (rec < 1 || rec > file->record_count) { fprintf(stderr, "Invalid record number %"SC_FORMAT_LEN_SIZE_T"u\n", rec); goto err; } r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR); - if (r<0) { - fprintf(stderr, "Cannot read record %"SC_FORMAT_LEN_SIZE_T"u; return %i\n", rec, r); - goto err;; + if (r < 0) { + fprintf(stderr, "Cannot read record %"SC_FORMAT_LEN_SIZE_T"u of %04X: %s\n", + rec, file->id, sc_strerror(r)); + goto err; + } + + /* do not allow gaps between data read and added */ + if (offs >= (size_t) r) { + fprintf(stderr, "Offset too large.\n"); + goto err; } buflen = sizeof(buf) - offs; - i = parse_string_or_hexdata(argv[3], buf + offs, &buflen); - if (!i) { - fprintf(stderr, "unable to parse data\n"); + r = parse_string_or_hexdata(argv[3], buf + offs, &buflen); + if (r < 0) { + fprintf(stderr, "Unable to parse input data: %s.\n", sc_strerror(r)); goto err; } r = sc_lock(card); if (r == SC_SUCCESS) - r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR); + r = sc_update_record(card, rec, buf, buflen, SC_RECORD_BY_REC_NR); sc_unlock(card); - if (r<0) { - fprintf(stderr, "Cannot update record %"SC_FORMAT_LEN_SIZE_T"u; return %i\n", rec, r); + if (r < 0) { + fprintf(stderr, "Cannot update record %"SC_FORMAT_LEN_SIZE_T"u of %04X: %s\n.", + rec, file->id, sc_strerror(r)); goto err; } - printf("Total of %d bytes written to record %"SC_FORMAT_LEN_SIZE_T"u at %"SC_FORMAT_LEN_SIZE_T"u offset.\n", - i, rec, offs); + printf("Total of %d bytes written to %04X's record %"SC_FORMAT_LEN_SIZE_T"u " + "at offset %"SC_FORMAT_LEN_SIZE_T"u.\n", + r, file->id, rec, offs); err = 0; err: @@ -1580,7 +1602,7 @@ err: static int do_put(int argc, char **argv) { - u8 buf[256]; + u8 buf[SC_MAX_EXT_APDU_DATA_SIZE]; int r, err = 1; size_t count = 0; unsigned int idx = 0; @@ -1605,7 +1627,7 @@ static int do_put(int argc, char **argv) r = sc_select_file(card, &path, &file); sc_unlock(card); if (r || file == NULL) { - check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); + check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file); goto err; } count = file->size; @@ -1624,17 +1646,17 @@ static int do_put(int argc, char **argv) r = sc_update_binary(card, idx, buf, c, 0); sc_unlock(card); if (r < 0) { - check_ret(r, SC_AC_OP_READ, "update failed", file); + check_ret(r, SC_AC_OP_READ, "Update failed", file); goto err; } if (r != c) { - fprintf(stderr, "expecting %d, wrote only %d bytes.\n", c, r); + fprintf(stderr, "Expecting %d, wrote only %d bytes.\n", c, r); goto err; } idx += c; count -= c; } - printf("Total of %d bytes written.\n", idx); + printf("Total of %d bytes written to %04X.\n", idx, file->id); err = 0; err: @@ -1676,7 +1698,7 @@ static int do_erase(int argc, char **argv) r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); sc_unlock(card); if (r) { - fprintf(stderr, "Failed to erase card: %s\n", sc_strerror (r)); + fprintf(stderr, "Failed to erase card: %s\n", sc_strerror(r)); return -1; } return 0; @@ -1691,11 +1713,11 @@ static int do_random(int argc, char **argv) if (argc < 1 || argc > 2) return usage(do_random); - count = atoi(argv[0]); - if (count < 0 || (size_t) count > sizeof buffer) { + + if (count < 0 || (size_t) count > sizeof(buffer)) { fprintf(stderr, "Number must be in range 0..%"SC_FORMAT_LEN_SIZE_T"u\n", - sizeof buffer); + sizeof(buffer)); return -1; } @@ -1754,35 +1776,38 @@ static int do_random(int argc, char **argv) static int do_get_data(int argc, char **argv) { - unsigned char buffer[256]; + u8 id[2] = { 0x00, 0x00 }; unsigned int tag; + u8 buffer[SC_MAX_EXT_APDU_RESP_SIZE]; FILE *fp; int r; if (argc != 1 && argc != 2) return usage(do_get_data); + if (arg_to_fid(argv[0], id) != 0) + return usage(do_get_data); + tag = id[0] << 8 | id[1]; - tag = strtoul(argv[0], NULL, 16); r = sc_lock(card); if (r == SC_SUCCESS) r = sc_get_data(card, tag, buffer, sizeof(buffer)); sc_unlock(card); if (r < 0) { - fprintf(stderr, "Failed to get data object: %s\n", sc_strerror(r)); + fprintf(stderr, "Failed to get DO %04X: %s\n", tag, sc_strerror(r)); return -1; } if (argc == 2) { - const char *filename = argv[1]; + const char *filename = argv[1]; - if (!(fp = fopen(filename, "w"))) { + if (!(fp = fopen(filename, "wb"))) { perror(filename); return -1; } fwrite(buffer, r, 1, fp); fclose(fp); } else { - printf("Object %04x:\n", tag & 0xFFFF); + printf("Data Object %04X:\n", tag & 0xFFFF); util_hex_dump_asc(stdout, buffer, r, 0); } @@ -1794,22 +1819,24 @@ static int do_get_data(int argc, char **argv) **/ static int do_put_data(int argc, char **argv) { + u8 id[2] = { 0x00, 0x00 }; unsigned int tag; - u8 buf[SC_MAX_EXT_APDU_BUFFER_SIZE]; + u8 buf[SC_MAX_EXT_APDU_DATA_SIZE]; size_t buflen = sizeof(buf); int r; if (argc != 2) return usage(do_put_data); - /* Extract DO's tag */ - tag = strtoul(argv[0], NULL, 16); + if (arg_to_fid(argv[0], id) != 0) + return usage(do_get_data); + tag = id[0] << 8 | id[1]; /* Extract the new content */ /* buflen is the max length of reception buffer */ r = parse_string_or_hexdata(argv[1], buf, &buflen); if (r < 0) { - fprintf(stderr, "error parsing %s: %s\n", argv[1], sc_strerror(r)); + fprintf(stderr, "Error parsing %s: %s\n", argv[1], sc_strerror(r)); return r; } @@ -1819,7 +1846,7 @@ static int do_put_data(int argc, char **argv) r = sc_put_data(card, tag, buf, buflen); sc_unlock(card); if (r < 0) { - fprintf(stderr, "Cannot put data to %04X; return %i\n", tag, r); + fprintf(stderr, "Failed to put data to DO %04X: %s\n", tag, sc_strerror(r)); return -1; } diff --git a/src/tools/opensc-notify-cmdline.c b/src/tools/opensc-notify-cmdline.c index 3fe2fcd2..9bae830a 100644 --- a/src/tools/opensc-notify-cmdline.c +++ b/src/tools/opensc-notify-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=opensc-notify-cmdline --output-dir=. @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: opensc-notify [OPTIONS]..."; +const char *gengetopt_args_info_usage = "Usage: opensc-notify [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; @@ -124,19 +124,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -424,7 +430,8 @@ int update_arg(void *field, char **orig_field, break; }; - + FIX_UNUSED(stop_char); + /* store the original value */ switch(arg_type) { case ARG_NO: @@ -486,10 +493,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -625,6 +638,7 @@ cmdline_parser_internal ( error_occurred += check_modes(customized_given, customized_desc, standard_given, standard_desc); } + FIX_UNUSED(check_required); cmdline_parser_release (&local_args_info); @@ -638,3 +652,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/opensc-notify-cmdline.h b/src/tools/opensc-notify-cmdline.h index 9bd77963..e36be178 100644 --- a/src/tools/opensc-notify-cmdline.h +++ b/src/tools/opensc-notify-cmdline.h @@ -1,9 +1,9 @@ /** @file opensc-notify-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef OPENSC_NOTIFY_CMDLINE_H #define OPENSC_NOTIFY_CMDLINE_H diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index afc24353..c67212b3 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -49,26 +49,21 @@ void Sleep(unsigned int Milliseconds) } #endif -void stop_daemon() -{ -#ifdef PCSCLITE_GOOD - sc_cancel(ctx); -#endif - run_daemon = 0; -} - void notify_daemon() { int r; - const unsigned int event_mask = SC_EVENT_CARD_EVENTS; + const unsigned int event_mask = SC_EVENT_CARD_EVENTS|SC_EVENT_READER_EVENTS; unsigned int event; struct sc_reader *event_reader = NULL; - size_t error_count = 0; + void *reader_states = NULL; +#ifndef __APPLE__ /* timeout adjusted to the maximum response time for WM_CLOSE in case * canceling doesn't work */ const int timeout = 20000; - struct sc_atr old_atr; - void *reader_states = NULL; +#else + /* lower timeout, because Apple doesn't support hotplug events */ + const int timeout = 2000; +#endif r = sc_establish_context(&ctx, "opensc-notify"); if (r < 0 || !ctx) { @@ -76,50 +71,51 @@ void notify_daemon() return; } - while (run_daemon && error_count < 1000) { + while (run_daemon) { + r = sc_wait_for_event(ctx, event_mask, &event_reader, &event, timeout, &reader_states); if (r < 0) { if (r == SC_ERROR_NO_READERS_FOUND) { - /* No readers available, PnP notification not supported */ - Sleep(200); - } else { - error_count++; + Sleep(timeout); + continue; } - continue; } - error_count = 0; - - if (event & SC_EVENT_CARD_REMOVED) { - sc_notify_id(ctx, &old_atr, NULL, NOTIFY_CARD_REMOVED); - } - if (event & SC_EVENT_CARD_INSERTED) { - if (event_reader) { - /* FIXME `pcsc_wait_for_event` has all the information that's - * requested again with `pcsc_detect_card_presence`, but it - * doesn't use the ATR, for example, to refresh the reader's - * attributes. To get the ATR we need to call - * sc_detect_card_presence. Eventually this should be fixed. */ - sc_detect_card_presence(event_reader); - memcpy(old_atr.value, event_reader->atr.value, - event_reader->atr.len); - old_atr.len = event_reader->atr.len; - } else { - old_atr.len = 0; + if (event_reader) { + if (event & SC_EVENT_CARD_REMOVED + || (event & SC_EVENT_READER_DETACHED + && event_reader->flags & SC_READER_CARD_PRESENT)) { + /* sc_notify_id uses only the reader's name for displaying on + * removal, so use a dummy card here to get that information + * into the notification */ + struct sc_pkcs15_card p15card; + sc_card_t card; + memset(&card, 0, sizeof card); + card.reader = event_reader; + memset(&p15card, 0, sizeof p15card); + p15card.card = &card; + sc_notify_id(ctx, &event_reader->atr, &p15card, NOTIFY_CARD_REMOVED); + } else if (event & SC_EVENT_CARD_INSERTED + || (event & SC_EVENT_READER_ATTACHED + && event_reader->flags & SC_READER_CARD_PRESENT)) { + /* sc_notify_id prevers the reader's name for displaying on + * insertion, so use a dummy card here to get that information + * into the notification */ + struct sc_pkcs15_card p15card; + sc_card_t card; + memset(&card, 0, sizeof card); + card.reader = event_reader; + memset(&p15card, 0, sizeof p15card); + p15card.card = &card; + sc_notify_id(ctx, &event_reader->atr, &p15card, NOTIFY_CARD_INSERTED); } - sc_notify_id(ctx, old_atr.len ? &old_atr : NULL, NULL, - NOTIFY_CARD_INSERTED); } } if (ctx) { - if (error_count >= 1000) { - sc_log(ctx, "Too many errors; aborting."); - } /* free `reader_states` */ sc_wait_for_event(ctx, 0, NULL, NULL, 0, &reader_states); - reader_states = NULL; sc_release_context(ctx); ctx = NULL; } @@ -132,7 +128,8 @@ void notify_daemon() LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_CLOSE || message == WM_QUIT) { - stop_daemon(); + run_daemon = 0; + sc_cancel(ctx); return TRUE; } @@ -182,32 +179,57 @@ WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowC #else -#ifdef HAVE_SIGACTION +#if defined(HAVE_SIGACTION) && defined(HAVE_PTHREAD) +#include +#include #include +#include + +static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { - stop_daemon(); + run_daemon = 0; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + (void)write(cancellation_fd[1], &sig, sizeof sig); +#pragma GCC diagnostic pop } -void set_sa_handler(void) +static void *cancellation_proc(void *arg) { - struct sigaction new_sig, old_sig; + (void)arg; + while (run_daemon) { + int sig; + if (sizeof sig == read(cancellation_fd[0], &sig, sizeof sig)) { + break; + } + } + sc_cancel(ctx); + return NULL; +} - /* Register signal handlers */ +void setup_cancellation(void) +{ + pthread_t cancellation_thread; + struct sigaction new_sig, old_sig; new_sig.sa_handler = sig_handler; sigemptyset(&new_sig.sa_mask); new_sig.sa_flags = SA_RESTART; - if ((sigaction(SIGINT, &new_sig, &old_sig) < 0) - || (sigaction(SIGTERM, &new_sig, &old_sig) < 0)) { - fprintf(stderr, "Failed to create signal handler: %s", strerror(errno)); + + if (pipe(cancellation_fd) != 0 + || (errno = pthread_create(&cancellation_thread, NULL, cancellation_proc, NULL)) != 0 + || sigaction(SIGINT, &new_sig, &old_sig) != 0 + || sigaction(SIGTERM, &new_sig, &old_sig) != 0) { + fprintf(stderr, "Failed to setup cancellation: %s", strerror(errno)); } } #else -void set_sa_handler(void) +void setup_cancellation(void) { } + #endif #include "opensc-notify-cmdline.h" @@ -244,8 +266,8 @@ main (int argc, char **argv) if ((!cmdline.customized_mode_counter && !cmdline.standard_mode_counter) || cmdline.daemon_mode_counter) { - set_sa_handler(); run_daemon = 1; + setup_cancellation(); notify_daemon(); } else { /* give the notification process some time to spawn */ diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c index 22fbbc7b..37c93da5 100644 --- a/src/tools/opensc-tool.c +++ b/src/tools/opensc-tool.c @@ -578,6 +578,7 @@ static int list_algorithms(void) { SC_ALGORITHM_RSA_PAD_PKCS1, "pkcs1" }, { SC_ALGORITHM_RSA_PAD_ANSI, "ansi" }, { SC_ALGORITHM_RSA_PAD_PSS, "pss" }, + { SC_ALGORITHM_RSA_PAD_OAEP, "oaep" }, { SC_ALGORITHM_RSA_PAD_ISO9796, "iso9796" }, { SC_ALGORITHM_RSA_HASH_SHA1, "sha1" }, { SC_ALGORITHM_RSA_HASH_MD5, "MD5" }, diff --git a/src/tools/pkcs11-register-cmdline.c b/src/tools/pkcs11-register-cmdline.c index f7f0b001..4cdc7890 100644 --- a/src/tools/pkcs11-register-cmdline.c +++ b/src/tools/pkcs11-register-cmdline.c @@ -1,5 +1,5 @@ /* - File autogenerated by gengetopt version 2.22.6 + File autogenerated by gengetopt version 2.23 generated with the following command: /usr/bin/gengetopt --file-name=pkcs11-register-cmdline --output-dir=. @@ -27,7 +27,7 @@ const char *gengetopt_args_info_purpose = ""; -const char *gengetopt_args_info_usage = "Usage: pkcs11-register [OPTIONS]..."; +const char *gengetopt_args_info_usage = "Usage: pkcs11-register [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; @@ -114,19 +114,25 @@ cmdline_parser_print_version (void) printf("\n%s\n", gengetopt_args_info_versiontext); } -static void print_help_common(void) { - cmdline_parser_print_version (); +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); + if (len_usage || len_purpose) { + printf("\n"); + } - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } } void @@ -410,7 +416,8 @@ int update_arg(void *field, char **orig_field, break; }; - + FIX_UNUSED(stop_char); + /* store the original value */ switch(arg_type) { case ARG_NO: @@ -449,10 +456,16 @@ cmdline_parser_internal ( package_name = argv[0]; + /* TODO: Why is this here? It is not used anywhere. */ override = params->override; + FIX_UNUSED(override); + initialize = params->initialize; check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); @@ -571,6 +584,7 @@ cmdline_parser_internal ( + FIX_UNUSED(check_required); cmdline_parser_release (&local_args_info); @@ -584,3 +598,4 @@ failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/src/tools/pkcs11-register-cmdline.h b/src/tools/pkcs11-register-cmdline.h index 8b38526a..67188023 100644 --- a/src/tools/pkcs11-register-cmdline.h +++ b/src/tools/pkcs11-register-cmdline.h @@ -1,9 +1,9 @@ /** @file pkcs11-register-cmdline.h * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.6 + * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ + * @author GNU Gengetopt */ #ifndef PKCS11_REGISTER_CMDLINE_H #define PKCS11_REGISTER_CMDLINE_H diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index 11d5e52d..b1674a76 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -137,6 +137,7 @@ enum { OPT_KEY_USAGE_SIGN, OPT_KEY_USAGE_DECRYPT, OPT_KEY_USAGE_DERIVE, + OPT_KEY_USAGE_WRAP, OPT_PRIVATE, OPT_SENSITIVE, OPT_EXTRACTABLE, @@ -197,6 +198,7 @@ static const struct option options[] = { { "usage-sign", 0, NULL, OPT_KEY_USAGE_SIGN }, { "usage-decrypt", 0, NULL, OPT_KEY_USAGE_DECRYPT }, { "usage-derive", 0, NULL, OPT_KEY_USAGE_DERIVE }, + { "usage-wrap", 0, NULL, OPT_KEY_USAGE_WRAP }, { "write-object", 1, NULL, 'w' }, { "read-object", 0, NULL, 'r' }, { "delete-object", 0, NULL, 'b' }, @@ -272,6 +274,7 @@ static const char *option_help[] = { "Specify 'sign' key usage flag (sets SIGN in privkey, sets VERIFY in pubkey)", "Specify 'decrypt' key usage flag (RSA only, set DECRYPT privkey, ENCRYPT in pubkey)", "Specify 'derive' key usage flag (EC only)", + "Specify 'wrap' key usage flag", "Write an object (key, cert, data) to the card", "Get object's CKA_VALUE attribute (use with --type)", "Delete an object (use with --type cert/data/privkey/pubkey/secrkey)", @@ -355,6 +358,7 @@ static int opt_login_type = -1; static int opt_key_usage_sign = 0; static int opt_key_usage_decrypt = 0; static int opt_key_usage_derive = 0; +static int opt_key_usage_wrap = 0; static int opt_key_usage_default = 1; /* uses defaults if no opt_key_usage options */ static int opt_derive_pass_der = 0; static unsigned long opt_random_bytes = 0; @@ -879,6 +883,10 @@ int main(int argc, char * argv[]) opt_key_usage_derive = 1; opt_key_usage_default = 0; break; + case OPT_KEY_USAGE_WRAP: + opt_key_usage_wrap = 1; + opt_key_usage_default = 0; + break; case OPT_PRIVATE: opt_is_private = 1; break; @@ -1590,53 +1598,42 @@ static void init_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess) static int change_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess) { - char old_buf[21], *old_pin = NULL; - char new_buf[21], *new_pin = NULL; + char old_buf[21], *old_pin = opt_so_pin ? (char*)opt_so_pin : (char*)opt_pin; + char new_buf[21], *new_pin = (char *)opt_new_pin; CK_TOKEN_INFO info; CK_RV rv; int r; size_t len = 0; get_token_info(slot, &info); + const CK_FLAGS hasReaderPinPad = info.flags & CKF_PROTECTED_AUTHENTICATION_PATH; - if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { - if (!opt_pin && !opt_so_pin) { - printf("Please enter the current PIN: "); - r = util_getpass(&old_pin, &len, stdin); - if (r < 0) - return 1; - if (!old_pin || !*old_pin || strlen(old_pin) > 20) - return 1; - strcpy(old_buf, old_pin); - old_pin = old_buf; - } - else { - if (opt_so_pin) - old_pin = (char *) opt_so_pin; - else - old_pin = (char *) opt_pin; - } + if (!hasReaderPinPad && !old_pin) { + printf("Please enter the current PIN: "); + r = util_getpass(&old_pin, &len, stdin); + if (r < 0) + return 1; + if (!old_pin || !*old_pin || strlen(old_pin) > 20) + return 1; + strcpy(old_buf, old_pin); + old_pin = old_buf; + } + if (!hasReaderPinPad && !new_pin) { + printf("Please enter the new PIN: "); + r = util_getpass(&new_pin, &len, stdin); + if (r < 0) + return 1; + if (!new_pin || !*new_pin || strlen(new_pin) > 20) + return 1; + strcpy(new_buf, new_pin); - if (!opt_new_pin) { - printf("Please enter the new PIN: "); - r = util_getpass(&new_pin, &len, stdin); - if (r < 0) - return 1; - if (!new_pin || !*new_pin || strlen(new_pin) > 20) - return 1; - strcpy(new_buf, new_pin); - - 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) { - free(new_pin); - return 1; - } - } - else { - new_pin = (char *) opt_new_pin; + 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) { + free(new_pin); + return 1; } } @@ -2058,7 +2055,7 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, rv = p11->C_Verify(session, in_buffer, r, sig_buffer, sig_len); } - if (rv != CKR_OK) { + if (rv != CKR_OK && rv != CKR_SIGNATURE_INVALID) { rv = p11->C_VerifyInit(session, &mech, key); if (rv != CKR_OK) p11_fatal("C_VerifyInit", rv); @@ -2073,7 +2070,7 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, sig_len = r2; rv = p11->C_VerifyFinal(session, sig_buffer, sig_len); - if (rv != CKR_OK) + if (rv != CKR_OK && rv != CKR_SIGNATURE_INVALID) p11_fatal("C_VerifyFinal", rv); } @@ -2127,9 +2124,15 @@ static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, case CKM_RSA_PKCS_OAEP: oaep_params.hashAlg = opt_hash_alg; switch (opt_hash_alg) { + case CKM_SHA_1: + oaep_params.mgf = CKG_MGF1_SHA1; + break; case CKM_SHA224: oaep_params.mgf = CKG_MGF1_SHA224; break; + default: + oaep_params.hashAlg = CKM_SHA256; + /* fall through */ case CKM_SHA256: oaep_params.mgf = CKG_MGF1_SHA256; break; @@ -2139,12 +2142,6 @@ static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, case CKM_SHA512: oaep_params.mgf = CKG_MGF1_SHA512; break; - default: - oaep_params.hashAlg = CKM_SHA_1; - /* fall through */ - case CKM_SHA_1: - oaep_params.mgf = CKG_MGF1_SHA1; - break; } break; case CKM_RSA_X_509: @@ -2326,10 +2323,12 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session, n_privkey_attr++; } - FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_WRAP, &_true, sizeof(_true)); - n_pubkey_attr++; - FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_UNWRAP, &_true, sizeof(_true)); - n_privkey_attr++; + if (opt_key_usage_wrap) { + FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_WRAP, &_true, sizeof(_true)); + n_pubkey_attr++; + FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_UNWRAP, &_true, sizeof(_true)); + n_privkey_attr++; + } } else if (!strncmp(type, "EC:", 3)) { CK_MECHANISM_TYPE mtypes[] = {CKM_EC_KEY_PAIR_GEN}; @@ -3319,7 +3318,7 @@ static int write_object(CK_SESSION_HANDLE session) else if (strncasecmp(opt_key_type, "DES3:", strlen("DES3:")) == 0) type = CKK_DES3; else - util_fatal("Unknown key type: 0x%X", type); + util_fatal("Unknown key type: 0x%lX", type); } FILL_ATTR(seckey_templ[0], CKA_CLASS, &clazz, sizeof(clazz)); @@ -4480,7 +4479,7 @@ static int read_object(CK_SESSION_HANDLE session) #endif } else - util_fatal("Reading public keys of type 0x%X not (yet) supported", type); + util_fatal("Reading public keys of type 0x%lX not (yet) supported", type); value = BIO_copy_data(pout, &derlen); BIO_free(pout); len = derlen; @@ -5045,8 +5044,8 @@ static int test_signature(CK_SESSION_HANDLE sess) } if (firstMechType == CKM_RSA_X_509) { - /* make sure our data is smaller than the modulus */ - data[0] = 0x00; + /* make sure our data is smaller than the modulus - 11 */ + memset(data, 0, 11); /* in effect is zero padding */ } ck_mech.mechanism = firstMechType; diff --git a/src/tools/pkcs15-crypt.c b/src/tools/pkcs15-crypt.c index 763510ed..d7ce7b95 100644 --- a/src/tools/pkcs15-crypt.c +++ b/src/tools/pkcs15-crypt.c @@ -132,8 +132,12 @@ static char * get_pin(struct sc_pkcs15_object *obj) { char buf[(sizeof obj->label) + 20]; char *pincode; - struct sc_pkcs15_auth_info *pinfo = (struct sc_pkcs15_auth_info *) obj->data; + struct sc_pkcs15_auth_info *pinfo; + if (!obj) + return NULL; + + pinfo = (struct sc_pkcs15_auth_info *) obj->data; if (pinfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return NULL; diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c index 899f5306..5339402e 100644 --- a/src/tools/pkcs15-init.c +++ b/src/tools/pkcs15-init.c @@ -115,13 +115,11 @@ static int do_read_public_key(const char *, const char *, EVP_PKEY **); static int do_read_certificate(const char *, const char *, X509 **); static char * cert_common_name(X509 *x509); static void parse_commandline(int argc, char **argv); -static void read_options_file(const char *); static void ossl_print_errors(void); static int verify_pin(struct sc_pkcs15_card *, char *); enum { - OPT_OPTIONS = 0x100, - OPT_PASSPHRASE, + OPT_PASSPHRASE = 0x100, OPT_PUBKEY, OPT_SECRKEY, OPT_EXTRACTABLE, @@ -213,7 +211,6 @@ const struct option options[] = { { "profile", required_argument, NULL, 'p' }, { "card-profile", required_argument, NULL, 'c' }, - { "options-file", required_argument, NULL, OPT_OPTIONS }, { "md-container-guid", required_argument, NULL, OPT_MD_CONTAINER_GUID}, { "wait", no_argument, NULL, 'w' }, { "help", no_argument, NULL, 'h' }, @@ -279,7 +276,6 @@ static const char * option_help[] = { "Specify the general profile to use", "Specify the card profile to use", - "Read additional command line options from file", "For a new key specify GUID for a MD container", "Wait for card insertion", "Display this message", @@ -2774,9 +2770,6 @@ handle_option(const struct option *opt) case 'w': opt_wait = 1; break; - case OPT_OPTIONS: - read_options_file(optarg); - break; case OPT_PIN1: case OPT_PUK1: case OPT_PIN2: case OPT_PUK2: util_get_pin(optarg, &(opt_pins[opt->val & 3])); @@ -2954,55 +2947,6 @@ next: ; } } -/* - * Read a file containing more command line options. - * This allows you to specify PINs to pkcs15-init without - * exposing them through ps. - */ -static void -read_options_file(const char *filename) -{ - const struct option *o; - char buffer[1024], *name; - FILE *fp; - - if ((fp = fopen(filename, "r")) == NULL) - util_fatal("Unable to open %s: %m", filename); - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - buffer[strcspn(buffer, "\n")] = '\0'; - - name = strtok(buffer, " \t"); - while (name) { - if (*name == '#') - break; - for (o = options; o->name; o++) - if (!strcmp(o->name, name)) - break; - if (!o->name) { - util_error("Unknown option \"%s\"\n", name); - util_print_usage_and_die(app_name, options, option_help, NULL); - } - if (o->has_arg != no_argument) { - optarg = strtok(NULL, ""); - if (optarg) { - while (isspace((int) *optarg)) - optarg++; - optarg = strdup(optarg); - } - } - if (o->has_arg == required_argument - && (!optarg || !*optarg)) { - util_error("Option %s: missing argument\n", name); - util_print_usage_and_die(app_name, options, option_help, NULL); - } - handle_option(o); - name = strtok(NULL, " \t"); - } - } - fclose(fp); -} - - /* * OpenSSL helpers */ diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index e901e17d..363bfb82 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -57,6 +57,7 @@ typedef unsigned __int32 uint32_t; #include "libopensc/pkcs15.h" #include "libopensc/asn1.h" #include "util.h" +#include "pkcs11/pkcs11-display.h" static const char *app_name = "pkcs15-tool"; @@ -607,6 +608,8 @@ static void print_prkey_info(const struct sc_pkcs15_object *obj) struct sc_pkcs15_prkey_info *prkey = (struct sc_pkcs15_prkey_info *) obj->data; unsigned char guid[40]; size_t guid_len; + int i; + int last_algo_refs = 0; if (compact) { printf("\t%-3s", key_types[7 & obj->type]); @@ -635,6 +638,16 @@ static void print_prkey_info(const struct sc_pkcs15_object *obj) printf("\tAccess Flags : [0x%02X]", prkey->access_flags); print_key_access_flags(prkey->access_flags); printf("\n"); + printf("\tAlgo_refs : "); + /* zero may be valid and don't know how many were read print at least 1*/ + for (i = 0; i< SC_MAX_SUPPORTED_ALGORITHMS; i++) { + if (prkey->algo_refs[i] != 0) + last_algo_refs = i; + } + for (i = 0; i< last_algo_refs + 1; i++) { + printf("%s%u", (i == 0) ? "" : ", ", prkey->algo_refs[i]); + } + printf("\n"); print_access_rules(obj->access_rules, SC_PKCS15_MAX_ACCESS_RULES); @@ -1645,6 +1658,21 @@ static int list_apps(FILE *fout) return 0; } + +static void print_supported_algo_info_operations(unsigned int operation) + +{ + size_t i; + const char *operations[] = { + "compute_checksum", "compute_signature", "verify_checksum", "verify_signature", + "encipher", "decipher", "hash", "generate/derive_key" + }; + const size_t operations_count = NELEMENTS(operations); + for (i = 0; i < operations_count; i++) + if (operation & (1 << i)) + printf(", %s", operations[i]); +} + static void list_info(void) { const char *flags[] = { @@ -1655,6 +1683,7 @@ static void list_info(void) }; char *last_update = sc_pkcs15_get_lastupdate(p15card); int i, count = 0; + int idx; printf("PKCS#15 Card [%s]:\n", p15card->tokeninfo->label); printf("\tVersion : %d\n", p15card->tokeninfo->version); @@ -1675,6 +1704,34 @@ static void list_info(void) count++; } } + printf("\n"); + for (i = 0; i < SC_MAX_SUPPORTED_ALGORITHMS; i++) { + struct sc_supported_algo_info * sa = &p15card->tokeninfo->supported_algos[i]; + + if (sa->reference == 0 && sa->reference == 0 && sa->mechanism == 0 + && sa->operations == 0 && sa->algo_ref == 0) + break; + printf("\t\t sc_supported_algo_info[%d]:\n", i); + printf("\t\t\t reference : %u (0x%02x)\n", sa->reference, sa->reference); + printf("\t\t\t mechanism : [0x%02x] %s\n", sa->mechanism, lookup_enum(MEC_T, sa->mechanism)); + if (sc_valid_oid(&sa->parameters)) { + printf("\t\t\t parameters: %i", sa->parameters.value[0]); + for (idx = 1; idx < SC_MAX_OBJECT_ID_OCTETS && sa->parameters.value[idx] != -1 ; idx++) + printf(".%i", sa->parameters.value[idx]); + printf("\n"); + } + printf("\t\t\t operations : [0x%2.2x]",sa->operations); + print_supported_algo_info_operations(sa->operations); + printf("\n"); + if (sc_valid_oid((const struct sc_object_id*)&sa->algo_id)) { + printf("\t\t\t algo_id : %i", sa->algo_id.value[0]); + for (idx = 1; idx < SC_MAX_OBJECT_ID_OCTETS && sa->algo_id.value[idx] != -1 ; idx++) + printf(".%i", sa->algo_id.value[idx]); + printf("\n"); + } + printf("\t\t\t algo_ref : [0x%02x]\n",sa->algo_ref); + } + printf((compact) ? "\n" : "\n\n"); } diff --git a/src/ui/strings.c b/src/ui/strings.c index ea1d3ba6..90dbc0f9 100644 --- a/src/ui/strings.c +++ b/src/ui/strings.c @@ -34,8 +34,12 @@ static const char *get_inserted_text(struct sc_pkcs15_card *p15card, struct sc_a static char text[3*SC_MAX_ATR_SIZE] = {0}; const char prefix[] = "ATR: "; - if (p15card && p15card->card && p15card->card->name) { + if (p15card && p15card->card + && p15card->card->name) { return p15card->card->name; + } else if (p15card && p15card->card + && p15card->card->reader && p15card->card->reader->name) { + return p15card->card->reader->name; } if (!atr) @@ -192,7 +196,7 @@ const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, str = "Dieses Fenster wird automatisch geschlossen, wenn die PIN am PIN-Pad eingegeben wurde (Timeout typischerweise nach 30 Sekunden)."; break; case NOTIFY_CARD_INSERTED: - if (p15card) { + if (p15card && p15card->card && p15card->card->name) { str = "Smartcard kann jetzt verwendet werden"; } else { str = "Smartcard erkannt"; @@ -260,7 +264,7 @@ const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, str = "This window will be closed automatically after the PIN has been submitted on the PIN pad (timeout typically after 30 seconds)."; break; case NOTIFY_CARD_INSERTED: - if (p15card) { + if (p15card && p15card->card && p15card->card->name) { str = "Smart card is ready to use"; } else { str = "Smart card detected"; diff --git a/tests/test-manpage.sh b/tests/test-manpage.sh index 89fab7d1..a8d53d4c 100755 --- a/tests/test-manpage.sh +++ b/tests/test-manpage.sh @@ -1,8 +1,8 @@ #!/bin/bash SOURCE_PATH=../ -# find all the manual pages in src/tools -TOOLS=`find "${SOURCE_PATH}/doc/tools" -name "*.1.xml" | sed -E -e "s|.*/([a-z0-9-]*).*|\1|"` +# find all the manual pages in doc/tools +TOOLS=`find "${SOURCE_PATH}/doc/tools" -name "*.1.xml" | sed -E -e "s|.*/([a-z0-9-]*).*|\1|" | grep -v goid-tool` ALL=1 for T in $TOOLS; do @@ -17,5 +17,17 @@ for T in $TOOLS; do done if [ "$ALL" = 0 ]; then echo "Not all the switches in help are documented in manual pages" - exit 1; + exit 1 fi + +RES=0 +# find all tools in src/tools (files without extension) +TOOLS=`find "${SOURCE_PATH}/src/tools" -maxdepth 1 -type f ! -name "*.*" | sed -E -e "s|.*/([a-z0-9-]*).*|\1|" | grep -v -- -example` +for T in $TOOLS; do + if [[ ! -f "${SOURCE_PATH}/doc/tools/$T.1.xml" ]]; then + echo "Missing manual page for '$T'" + RES=1 + fi +done + +exit $RES diff --git a/win32/Make.rules.mak b/win32/Make.rules.mak index b6759e57..4f4971a7 100644 --- a/win32/Make.rules.mak +++ b/win32/Make.rules.mak @@ -17,6 +17,12 @@ WIXVSVER = VS2013 !IF "$(VISUALSTUDIOVERSION)" == "14.0" WIXVSVER = VS2015 !ENDIF +!IF "$(VISUALSTUDIOVERSION)" == "15.0" +WIXVSVER = VS2017 +!ENDIF +!IF "$(VISUALSTUDIOVERSION)" == "16.0" +WIXVSVER = VS2019 +!ENDIF WIX_INCL_DIR = "/I$(WIX)\SDK\$(WIXVSVER)\inc" WIX_LIBS = "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\dutil.lib" "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\wcautil.lib" @@ -36,11 +42,13 @@ SM_DEF = /DENABLE_SM # - set the OPENSSL_LIB below to your openssl lib file #OPENSSL_DEF= /DENABLE_OPENSSL !IF "$(OPENSSL_DEF)" == "/DENABLE_OPENSSL" +!IF "$(OPENSSL_DIR)" == "" !IF "$(PLATFORM)" == "x86" OPENSSL_DIR = C:\OpenSSL-Win32 !ELSE OPENSSL_DIR = C:\OpenSSL-Win64 !ENDIF +!ENDIF OPENSSL_INCL_DIR = /I$(OPENSSL_DIR)\include #define OPENSSL_STATIC if you have visual studio compatible with OpenSSL's static binaries @@ -49,26 +57,26 @@ OPENSSL_STATIC_DIR = static !IF "$(DEBUG_DEF)" == "/DDEBUG" !IF "$(PLATFORM)" == "x86" # OpenSSL 1.0.2 -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib # OpenSSL 1.1.0 -#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib !ELSE # OpenSSL 1.0.2 -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib # OpenSSL 1.1.0 -#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MTd.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib !ENDIF !ELSE !IF "$(PLATFORM)" == "x86" # OpenSSL 1.0.2 -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib # OpenSSL 1.1.0 -#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib !ELSE # OpenSSL 1.0.2 -OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libeay32MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib # OpenSSL 1.1.0 -#OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib +OPENSSL_LIB = $(OPENSSL_DIR)\lib\VC\$(OPENSSL_STATIC_DIR)\libcrypto64MT.lib user32.lib advapi32.lib crypt32.lib ws2_32.lib !ENDIF !ENDIF diff --git a/win32/winconfig.h.in b/win32/winconfig.h.in index 94ed9b54..fa682c5b 100644 --- a/win32/winconfig.h.in +++ b/win32/winconfig.h.in @@ -103,6 +103,8 @@ #define DEFAULT_ONEPIN_PKCS11_PROVIDER "@DEFAULT_ONEPIN_PKCS11_PROVIDER@" #endif +#define PKCS11_THREAD_LOCKING + #ifndef DEFAULT_SM_MODULE #define DEFAULT_SM_MODULE "@DEFAULT_SM_MODULE@" #endif