Merge branch 'master' into recursion

This commit is contained in:
Frank Morgner 2020-05-11 18:45:36 +02:00 committed by GitHub
commit a7d563b657
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
140 changed files with 4798 additions and 1920 deletions

View File

@ -1,7 +1,9 @@
### Problem Description
<!--
Please read about [reporting bugs](https://github.com/OpenSC/OpenSC/wiki/How-to-report-bugs-so-that-they-can-be-fixed) before opening an issue.
Please read about reporting bugs on the wiki before opening an issue:
https://github.com/OpenSC/OpenSC/wiki/How-to-write-a-good-bug-report
-->
### 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)

28
.github/add_signing_key.sh vendored Executable file
View File

@ -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

View File

@ -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

8
.github/remove_signing_key.sh vendored Executable file
View File

@ -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

BIN
.github/secrets.tar.enc vendored Normal file

Binary file not shown.

2
.gitignore vendored
View File

@ -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
.#*#

View File

@ -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

View File

@ -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 \

View File

@ -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}

View File

@ -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

View File

@ -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/* \

View File

@ -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

View File

@ -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</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap; fi"
- bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -n \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-pr$APPVEYOR_PULL_REQUEST_NUMBER\"; fi"
@ -95,7 +102,7 @@ build_script:
- bash -c "exec 0</dev/null && ./configure --with-cygwin-native --disable-openssl --disable-readline --disable-zlib || cat config.log"
- bash -c "exec 0</dev/null && rm src/getopt.h"
- nmake /f Makefile.mak %NMAKE_EXTRA%
- cd win32 && nmake /f Makefile.mak %NMAKE_EXTRA% VSVER=%VSVER% OpenSC.msi && cd ..
- cd win32 && nmake /nologo /f Makefile.mak %NMAKE_EXTRA% OpenSC.msi && cd ..
- move win32\OpenSC.msi %ARTIFACT%.msi
# put all pdb files for dump analysis, but this consumes approx 100 MB per build
- md %ARTIFACT%-Debug

View File

@ -27,7 +27,7 @@ AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERS
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE(foreign 1.10)
AM_INIT_AUTOMAKE(foreign 1.10 [subdir-objects])
OPENSC_VERSION_MAJOR="PACKAGE_VERSION_MAJOR"
OPENSC_VERSION_MINOR="PACKAGE_VERSION_MINOR"
@ -79,7 +79,7 @@ AC_ARG_WITH(
)
if test "${enable_optimization}" = "no"; then
CFLAGS="-O0 -g"
CFLAGS="${CFLAGS} -O0 -g"
fi
dnl Check for some target-specific stuff
@ -400,7 +400,8 @@ AC_HEADER_ASSERT
AC_CHECK_HEADERS([ \
errno.h fcntl.h stdlib.h \
inttypes.h string.h strings.h \
sys/time.h unistd.h sys/mman.h
sys/time.h unistd.h sys/mman.h \
sys/endian.h endian.h
])
dnl Checks for typedefs, structures, and compiler characteristics.
@ -415,9 +416,10 @@ AC_FUNC_STAT
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([ \
getpass gettimeofday getline memset mkdir \
strdup strerror \
strlcpy strlcat strnlen sigaction
strdup strerror memset_s explicit_bzero \
strnlen sigaction
])
AC_CHECK_DECLS([strlcpy, strlcat], [], [], [[#include <string.h>]])
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
])

View File

@ -75,11 +75,23 @@
<option>--pin</option> <replaceable>pin</replaceable>,
<option>-p</option> <replaceable>pin</replaceable>
</term>
<listitem><para>Specify the user pin <replaceable>pin</replaceable> to use.
If set to env:<replaceable>VARIABLE</replaceable>, the
value of the environment variable
<replaceable>VARIABLE</replaceable> is used.
The default is do not enter pin</para></listitem>
<listitem>
<para>
These options can be used to specify the PIN value
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>

View File

@ -46,9 +46,25 @@
</varlistentry>
<varlistentry>
<term>
<option>--pin</option> <replaceable>argument</replaceable>
<option>--pin</option> <replaceable>pin</replaceable>
</term>
<listitem><para>Define user PIN.</para></listitem>
<listitem>
<para>
This option can be used to specify the PIN value
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>

126
doc/tools/goid-tool.1.xml Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<refentry id="goid-tool">
<refmeta>
<refentrytitle>goid-tool</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="productname">OpenSC</refmiscinfo>
<refmiscinfo class="manual">OpenSC Tools</refmiscinfo>
<refmiscinfo class="source">opensc</refmiscinfo>
</refmeta>
<refnamediv>
<refname>goid-tool</refname>
<refpurpose>???</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>goid-tool</command>
<arg choice="opt"><replaceable class="option">OPTIONS</replaceable></arg>
<arg><replaceable class="option">mode</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>goid-tool</command> utility can be used from
the command line to ???
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term>
<option>--help</option>,
<option>-h</option>
</term>
<listitem><para>Print help message on screen.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--version</option>,
<option>-V</option>
</term>
<listitem><para>Print the OpenSC package release version.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--reader</option> <replaceable>string</replaceable>,
<option>-r</option> <replaceable>string</replaceable>
</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--verbose</option>,
<option>-v</option>
</term>
<listitem><para>
Cause <command>goid-tool</command> to be
more verbose. Use it multiple times to be even more
verbose.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--verify-pin</option>,
<option>-p</option>
</term>
<listitem><para>
Verify PIN.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--verify-bio</option>,
<option>-b</option>
</term>
<listitem><para>
Verify finger print.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--verify-pin-or-bio</option>
</term>
<listitem><para>
Verify PIN or finger print (user's choice).
</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<!-- TODO modes -->
<refsect1>
<title>See also</title>
<para>
<citerefentry>
<refentrytitle>pkcs11-tool</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>opensc.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Authors</title>
<para><command>pkcs11-register</command> was written by
Frank Morgner <email>frankmorgner@gmail.com</email>.</para>
</refsect1>
</refentry>

View File

@ -149,14 +149,25 @@
<varlistentry>
<term>
<option>--pin</option> <replaceable>string</replaceable>
<option>--pin</option> <replaceable>pin</replaceable>
</term>
<listitem><para>
The PIN text to verify. If set to
env:<replaceable>VARIABLE</replaceable>, the value of
the environment variable
<replaceable>VARIABLE</replaceable> is used.
</para></listitem>
<listitem>
<para>
This option can be used to specify the PIN value
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -35,7 +35,7 @@
<variablelist>
<varlistentry>
<term>
<option>--version</option>,
<option>--version</option>
</term>
<listitem><para>Print the OpenSC package release version.</para></listitem>
</varlistentry>

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<refentry id="pkcs11-register">
<refmeta>
<refentrytitle>pkcs11-register</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="productname">OpenSC</refmiscinfo>
<refmiscinfo class="manual">OpenSC Tools</refmiscinfo>
<refmiscinfo class="source">opensc</refmiscinfo>
</refmeta>
<refnamediv>
<refname>pkcs11-register</refname>
<refpurpose>Simple tool to install PKCS#11 modules to known applications.</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>pkcs11-register</command>
<arg choice="opt"><replaceable class="option">OPTIONS</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>pkcs11-register</command> utility can be used from
the command line to register PKCS#11 modules to various applications
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term>
<option>--help</option>,
<option>-h</option>
</term>
<listitem><para>Print help message on screen.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--version</option>,
<option>-V</option>
</term>
<listitem><para>Print the OpenSC package release version.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--module</option> <replaceable>filename</replaceable>,
<option>-m</option> <replaceable>filename</replaceable>
</term>
<listitem><para>
Path to the PKCS#11 module to load. The default
is OpenSC PKCS#11 module.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--skip-chrome</option>
</term>
<listitem><para>
Don't install module for Chrome browser. By default,
the tool attempts to install the module for Chrome
browser.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--skip-firefox</option>
</term>
<listitem><para>
Don't install module for Firefox browser. By default,
the tool attempts to install the module for Firefox
browser.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--skip-thunderbird</option>
</term>
<listitem><para>
Don't install module for Thunderbird mail client.
By default, the tool attempts to install the module
for Thunderbird mail client.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--skip-seamonkey</option>
</term>
<listitem><para>
Don't install module for Seamonkey. By default,
the tool attempts to install the module Seamonkey.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<citerefentry>
<refentrytitle>pkcs11-tool</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>opensc.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Authors</title>
<para><command>pkcs11-register</command> was written by
Frank Morgner <email>frankmorgner@gmail.com</email>.</para>
</refsect1>
</refentry>

View File

@ -170,6 +170,13 @@
<listitem><para>Specify 'derive' key usage flag (EC only).</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--usage-wrap</option>
</term>
<listitem><para>Specify 'wrap' key usage flag.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--label</option> <replaceable>name</replaceable>,

View File

@ -348,46 +348,26 @@
<varlistentry>
<term>
<option>--options-file</option> <replaceable>filename</replaceable>
<option>--pin</option> <replaceable>pin</replaceable>,
<option>--puk</option> <replaceable>puk</replaceable>,
<option>--so-pin</option> <replaceable>sopin</replaceable>,
<option>--so-puk</option> <replaceable>sopuk</replaceable>
</term>
<listitem>
<para>
Tells <command>pkcs15-init</command> to read additional options
from <replaceable>filename</replaceable>. The file is supposed to
contain one long option per line, without the leading dashes,
for instance:
<programlisting>
pin 1234
puk 87654321
</programlisting>
These options can be used to specify the PIN/PUK values
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
You can specify <option>--options-file</option> several times.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--pin</option>,
<option>--puk</option>
<option>--so-pin</option>,
<option>--so-puk</option>,
</term>
<listitem>
<para>
These options can be used to specify PIN/PUK values
on the command line. If set to
env:<replaceable>VARIABLE</replaceable>, the value
of the environment variable
<replaceable>VARIABLE</replaceable> 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
<command>ps(1)</command>. Therefore, you should use
these options only on a secured system, or in an
options file specified with
<option>--options-file</option>.
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>

View File

@ -310,16 +310,27 @@
<varlistentry>
<term>
<option>--pin</option> <replaceable>PIN</replaceable>
<option>--pin</option> <replaceable>pin</replaceable>,
<option>--new-pin</option> <replaceable>newpin</replaceable>
<option>--puk</option> <replaceable>puk</replaceable>
</term>
<listitem><para>Specify PIN</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--puk</option> <replaceable>PUK</replaceable>
</term>
<listitem><para>Specify Unblock PIN</para></listitem>
<listitem>
<para>
These options can be used to specify the PIN/PUK values
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -120,26 +120,25 @@
<varlistentry>
<term>
<option>--so-pin</option> <replaceable>value</replaceable>
<option>--pin</option> <replaceable>pin</replaceable>,
<option>--so-pin</option> <replaceable>sopin</replaceable>,
</term>
<listitem>
<para>Define SO-PIN for initialization. If set to
env:<replaceable>VARIABLE</replaceable>, the value of
the environment variable
<replaceable>VARIABLE</replaceable> is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--pin</option> <replaceable>value</replaceable>
</term>
<listitem>
<para>Define user PIN for initialization, wrap or
unwrap operation. If set to
env:<replaceable>VARIABLE</replaceable>, the value of
the environment variable
<replaceable>VARIABLE</replaceable> is used.</para>
<para>
These options can be used to specify the PIN values
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>

View File

@ -115,25 +115,28 @@
<varlistentry>
<term>
<option>--pin-value</option> <replaceable>value</replaceable>,
<option>-x</option> <replaceable>value</replaceable>
<option>--pin-value</option> <replaceable>pin</replaceable>,
<option>-x</option> <replaceable>pin</replaceable>
<option>--puk-value</option> <replaceable>puk</replaceable>,
<option>-y</option> <replaceable>puk</replaceable>
</term>
<listitem><para>Set value of PIN. If set to
env:<replaceable>VARIABLE</replaceable>, the value of
the environment variable
<replaceable>VARIABLE</replaceable> is used.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--puk-value</option> <replaceable>value</replaceable>,
<option>-y</option> <replaceable>value</replaceable>
</term>
<listitem><para>set value of PUK (or value of new PIN for change PIN
command see <option>-n</option>). If set to
env:<replaceable>VARIABLE</replaceable>, the value of
the environment variable
<replaceable>VARIABLE</replaceable> is used.</para></listitem>
<listitem>
<para>
These options can be used to specify the PIN/PUK values
on the command line. If the value is set to
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
of the specified environment variable is used. By default,
the code is prompted on the command line if needed.
</para>
<para>
Note that on most operation systems, any user can
display the command line of any process on the
system using utilities such as
<command>ps(1)</command>. Therefore, you should prefer
passing the codes via an environment variable
on an unsecured system.
</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -31,7 +31,7 @@
#include "config.h"
#endif
#ifndef HAVE_STRLCAT
#if !defined(HAVE_DECL_STRLCAT) || !HAVE_DECL_STRLCAT
#include <sys/types.h>
#include <string.h>

View File

@ -10,9 +10,11 @@
#include "config.h"
#endif
#ifndef HAVE_STRLCAT
#if !defined(HAVE_DECL_STRLCAT) || !HAVE_DECL_STRLCAT
#include <stddef.h>
size_t strlcat(char *dst, const char *src, size_t siz);
#else
#include <string.h>
#endif
#endif

View File

@ -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 <sys/types.h>
#include <string.h>

View File

@ -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 <stddef.h>
size_t strlcpy(char *dst, const char *src, size_t siz);
#else
#include <string.h>
#endif
#endif

View File

@ -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;
}

View File

@ -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 \

View File

@ -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

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -54,6 +54,7 @@
#endif
#include "iso7816.h"
#include "card-cac-common.h"
#include "pkcs15.h"
/*
* CAC hardware and APDU constants

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -0,0 +1,804 @@
/*
* card-idprime.c: Support for Gemalto IDPrime smart cards
*
* Copyright (c) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#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();
}

View File

@ -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",

View File

@ -52,11 +52,15 @@
#include <openssl/sha.h>
#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);

View File

@ -0,0 +1,192 @@
/*
* card-openpgp.h: Support for OpenPGP card
*
* Copyright (C) 2020 Peter Marschall <peter@adpm.de>
*
* 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

View File

@ -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<len> 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<len> 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;

View File

@ -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 */

View File

@ -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;

View File

@ -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
}

View File

@ -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:

View File

@ -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. */

View File

@ -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)

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -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. */

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)) {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 <DEEngert@gmail.com>
* Copyright (C) 2016, Viktor Tarasov <viktor.tarasov@gmail.com>
* Copyright (C) 2004, Bud P. Bruegger <bud@comune.grosseto.it>
* Copyright (C) 2004, Antonino Iacono <ant_iacono@tin.it>
* Copyright (C) 2003, Olaf Kirch <okir@suse.de>
*
* 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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 */

View File

@ -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++;

View File

@ -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;

View File

@ -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 <jjelen@redhat.com>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#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);
}

View File

@ -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 }
};

View File

@ -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;

View File

@ -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 },

View File

@ -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 */

View File

@ -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;

View File

@ -28,10 +28,18 @@
#include <assert.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 },

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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,

View File

@ -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;

View File

@ -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);
}

View File

@ -40,8 +40,13 @@
#ifndef _BSD_SOURCE
#define _BSD_SOURCE /* See feature_test_macros(7) */
#endif
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#endif
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#endif
int get_pace_capabilities(u8 *bitmap)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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) {

View File

@ -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);

View File

@ -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; i<sc_ctx_get_reader_count(context); i++)
initialize_reader(sc_ctx_get_reader(context, i));
card_detect_all();
out:
if (context != NULL)
@ -449,18 +446,23 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese
sc_log(context, "C_GetSlotList(token=%d, %s)", tokenPresent,
pSlotList==NULL_PTR? "plug-n-play":"refresh");
DEBUG_VSS(NULL, "C_GetSlotList before ctx_detect_detect");
/* Slot list can only change in v2.20 */
if (pSlotList == NULL_PTR) {
if (pSlotList == NULL_PTR)
sc_ctx_detect_readers(context);
for (i=0; i<list_size(&virtual_slots); i++) {
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
slot->flags &= ~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; i<list_size(&virtual_slots); i++) {
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
/* the list of available slots contains:
* - if present, virtual hotplug slot;
* - without token(s), at least one empty slot per reader;
* - any slot with token;
* - without token(s), one empty slot per reader;
* - any slot that has already been seen;
*/
if ((!tokenPresent && !slot->reader)
|| (!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; i<list_size(&virtual_slots); i++) {
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
slot->id = (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) {

View File

@ -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 **);

View File

@ -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; i<list_size(&virtual_slots); i++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
if (slot->reader == 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; j<list_size(&virtual_slots); j++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
if (slot->reader == 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; j<list_size(&virtual_slots); j++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
if (slot->reader == 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");

View File

@ -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);

View File

@ -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:

Some files were not shown because too many files have changed in this diff Show More