Merge branch 'master' into recursion
This commit is contained in:
commit
a7d563b657
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
||||
.#*#
|
||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -4,6 +4,7 @@ matrix:
|
|||
include:
|
||||
- compiler: clang
|
||||
os: osx
|
||||
osx_image: xcode9.4
|
||||
env: DO_PUSH_ARTIFACT=yes
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
|
@ -11,13 +12,11 @@ matrix:
|
|||
env:
|
||||
- DO_SIMULATION=javacard
|
||||
- ENABLE_DOC=--enable-doc
|
||||
sudo: true
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
dist: bionic
|
||||
env:
|
||||
- DO_SIMULATION=oseid
|
||||
sudo: true
|
||||
- env:
|
||||
- HOST=x86_64-w64-mingw32
|
||||
- DO_PUSH_ARTIFACT=yes
|
||||
|
@ -30,7 +29,6 @@ matrix:
|
|||
dist: bionic
|
||||
env:
|
||||
- DO_SIMULATION=cac
|
||||
sudo: true
|
||||
|
||||
env:
|
||||
global:
|
||||
|
@ -68,12 +66,17 @@ addons:
|
|||
before_install:
|
||||
# brew install gengetopt help2man cmocka ccache llvm;
|
||||
# export PATH="/usr/local/opt/ccache/libexec:/usr/local/opt/llvm/bin:$PATH";
|
||||
# add magic notarization flags for macOS, see https://github.com/akeru-inc/xcnotary/blob/master/README.md
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update;
|
||||
brew uninstall libtool;
|
||||
brew install libtool;
|
||||
brew install gengetopt help2man cmocka ccache;
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH";
|
||||
openssl aes-256-cbc -K $encrypted_3b9f0b9d36d1_key -iv $encrypted_3b9f0b9d36d1_iv -in .github/secrets.tar.enc -out .github/secrets.tar -d;
|
||||
.github/add_signing_key.sh;
|
||||
export OTHER_CODE_SIGN_FLAGS=--timestamp CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO CODE_SIGN_STYLE=Manual;
|
||||
git clone https://github.com/frankmorgner/OpenSCToken.git;
|
||||
fi
|
||||
- if [ "${DO_SIMULATION}" = "cac" ]; then
|
||||
sudo apt-get install -y libglib2.0-dev libnss3-dev pkgconf libtool make autoconf autoconf-archive automake libsofthsm2-dev softhsm2 softhsm2-common help2man gnutls-bin libcmocka-dev libusb-dev libudev-dev flex libnss3-tools libssl-dev libpcsclite1;
|
||||
|
@ -102,8 +105,11 @@ before_script:
|
|||
if [ ! -f "$(winepath 'C:/Program Files (x86)/Inno Setup 5/ISCC.exe')" ]; then
|
||||
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16;
|
||||
export DISPLAY=:99.0;
|
||||
[ -d isetup ] || mkdir isetup;
|
||||
pushd isetup;
|
||||
[ -f isetup-5.5.6.exe ] || wget http://files.jrsoftware.org/is/5/isetup-5.5.6.exe;
|
||||
wine isetup-5.5.6.exe /SILENT /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART;
|
||||
popd;
|
||||
fi;
|
||||
unset CC;
|
||||
unset CXX;
|
||||
|
@ -283,7 +289,7 @@ script:
|
|||
fi
|
||||
- if [ "${DO_SIMULATION}" = "cac" ]; then
|
||||
cd $TRAVIS_BUILD_DIR;
|
||||
make check && sudo make install || (cat tests/*log && exit);
|
||||
make check && sudo make install || (cat tests/*log src/tests/unittests/*log && exit);
|
||||
export LD_LIBRARY_PATH=/usr/local/lib;
|
||||
cd src/tests/p11test/;
|
||||
./p11test -s 0 -p 12345678 -i &
|
||||
|
@ -309,6 +315,10 @@ after_script:
|
|||
git config --global user.name "Travis CI";
|
||||
.github/push_artifacts.sh "Travis CI build ${TRAVIS_JOB_NUMBER}";
|
||||
fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
.github/remove_signing_key.sh;
|
||||
rm -f .github/secrets.tar;
|
||||
fi
|
||||
|
||||
before_cache:
|
||||
- brew cleanup
|
||||
|
@ -321,5 +331,4 @@ cache:
|
|||
- $HOME/Library/Caches/Homebrew
|
||||
- openssl_bin
|
||||
- openpace_bin
|
||||
files:
|
||||
- isetup-5.5.6.exe
|
||||
- isetup
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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}
|
|
@ -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
|
||||
|
|
|
@ -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/* \
|
||||
|
|
|
@ -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
|
||||
|
|
49
appveyor.yml
49
appveyor.yml
|
@ -11,10 +11,21 @@ configuration:
|
|||
environment:
|
||||
GH_TOKEN:
|
||||
secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY
|
||||
PATH: C:\cygwin\bin;%PATH%
|
||||
OPENPACE_VER: 1.1.0
|
||||
ZLIB_VER_DOT: 1.2.11
|
||||
matrix:
|
||||
- VSVER: 14
|
||||
- VSVER: 12
|
||||
DO_PUSH_ARTIFACT: yes
|
||||
# not compatible with OpenSSL 1.1.1:
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
# VCVARSALL: "%VS120COMNTOOLS%/../../VC/vcvarsall.bat"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
VCVARSALL: "%VS140COMNTOOLS%/../../VC/vcvarsall.bat"
|
||||
DO_PUSH_ARTIFACT: yes
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat"
|
||||
# not compatible with WiX 3.11.2:
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat"
|
||||
|
||||
install:
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
|
@ -22,26 +33,21 @@ install:
|
|||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
- date /T & time /T
|
||||
- set PATH=C:\cygwin\bin;%PATH%
|
||||
- set OPENPACE_VER=1.1.0
|
||||
- set ZLIB_VER_DOT=1.2.11
|
||||
- ps: $env:PACKAGE_NAME=(git describe --tags --abbrev=0)
|
||||
- ps: >-
|
||||
If ($env:Platform -Match "x86") {
|
||||
$env:VCVARS_PLATFORM="x86"
|
||||
$env:OPENSSL_PF="Win32"
|
||||
$env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win32"
|
||||
} Else {
|
||||
$env:VCVARS_PLATFORM="amd64"
|
||||
$env:OPENSSL_PF="Win64"
|
||||
$env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win64"
|
||||
}
|
||||
- ps: >-
|
||||
If ($env:Configuration -Like "*Light*") {
|
||||
$env:ARTIFACT="${env:ARTIFACT}-Light"
|
||||
$env:ARTIFACT+="-Light"
|
||||
} Else {
|
||||
$env:NMAKE_EXTRA="OPENSSL_DEF=/DENABLE_OPENSSL ${env:NMAKE_EXTRA}"
|
||||
$env:NMAKE_EXTRA="OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536 ${env:NMAKE_EXTRA}"
|
||||
$env:NMAKE_EXTRA+=" OPENSSL_DEF=/DENABLE_OPENSSL OPENSSL_DIR=C:\OpenSSL-v111-${env:OPENSSL_PF}"
|
||||
$env:NMAKE_EXTRA+=" OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536"
|
||||
If (!(Test-Path C:\zlib )) {
|
||||
appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip
|
||||
7z x zlib.zip -oC:\
|
||||
|
@ -56,9 +62,8 @@ install:
|
|||
If (!(Test-Path cngsdk.msi )) {
|
||||
appveyor DownloadFile "http://download.microsoft.com/download/2/C/9/2C93059C-0532-42DF-8C24-9AEAFF00768E/cngsdk.msi"
|
||||
}
|
||||
- ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
|
||||
- echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%"
|
||||
- call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM%
|
||||
- echo "Using %APPVEYOR_BUILD_WORKER_IMAGE% with %VCVARSALL%"
|
||||
- call "%VCVARSALL%" %Platform%
|
||||
- cngsdk.msi /quiet
|
||||
- uname -a
|
||||
- set
|
||||
|
@ -71,21 +76,23 @@ build_script:
|
|||
xcopy C:\zlib C:\zlib-${env:OPENSSL_PF} /e /i /y /s
|
||||
cd C:\zlib-${env:OPENSSL_PF}
|
||||
(Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc
|
||||
nmake -f win32/Makefile.msc zlib.lib
|
||||
nmake /nologo -f win32/Makefile.msc zlib.lib
|
||||
}
|
||||
$env:NMAKE_EXTRA="ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib ${env:NMAKE_EXTRA}"
|
||||
$env:NMAKE_EXTRA+=" ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib"
|
||||
If (!(Test-Path -Path "C:\openpace-${env:OPENSSL_PF}" )) {
|
||||
# build libeac.lib as a static library
|
||||
xcopy C:\openpace C:\openpace-${env:OPENSSL_PF} /e /i /y /s
|
||||
cd C:\openpace-${env:OPENSSL_PF}\src
|
||||
# OpenSSL 1.1.0
|
||||
#cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
|
||||
#cl /nologo /IC:\OpenSSL-v110-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
|
||||
# OpenSSL 1.1.1
|
||||
cl /nologo /IC:\OpenSSL-v111-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /DHAVE_EC_POINT_GET_AFFINE_COORDINATES=1 /DHAVE_EC_POINT_SET_AFFINE_COORDINATES=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
|
||||
# OpenSSL 1.0.2
|
||||
cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
|
||||
lib /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj
|
||||
#cl /nologo /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
|
||||
lib /nologo /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj
|
||||
cd C:\projects\OpenSC
|
||||
}
|
||||
$env:NMAKE_EXTRA="OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF} ${env:NMAKE_EXTRA}"
|
||||
$env:NMAKE_EXTRA+=" OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF}"
|
||||
}
|
||||
- bash -c "exec 0</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
|
||||
|
|
17
configure.ac
17
configure.ac
|
@ -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
|
||||
])
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#endif
|
||||
#include "iso7816.h"
|
||||
#include "card-cac-common.h"
|
||||
#include "pkcs15.h"
|
||||
|
||||
/*
|
||||
* CAC hardware and APDU constants
|
||||
|
|
|
@ -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
|
||||
|| 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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 **);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue