Merge branch 'master' into ecc-fixes

This commit is contained in:
Alexander Paetzelt 2020-03-19 11:54:18 +01:00 committed by GitHub
commit e45712bd29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 6584 additions and 2292 deletions

View File

@ -9,7 +9,7 @@ git clone --single-branch https://${GH_TOKEN}@github.com/OpenSC/Nightly.git > /d
cd Nightly
git checkout -b "${BRANCH}"
for file in ${BUILDPATH}/win32/Output/OpenSC*.exe ${BUILDPATH}/opensc*.tar.gz ${BUILDPATH}/OpenSC*.dmg ${BUILDPATH}/OpenSC*.msi ${BUILDPATH}/OpenSC*.zip
for file in ${BUILDPATH}/win32/Output/OpenSC*.exe ${BUILDPATH}/opensc*.tar.gz ${BUILDPATH}/OpenSC*.dmg ${BUILDPATH}/OpenSC*.msi ${BUILDPATH}/OpenSC*.zip ${BUILDPATH}/*.pkg
do
if [ -f ${file} ]
then
@ -19,9 +19,10 @@ do
done
git commit --message "$1"
if ! git push --quiet --set-upstream origin "${BRANCH}"
then
i=0
while [ $i -le 10 ] && ! git push --quiet --set-upstream origin "${BRANCH}"
do
sleep $[ ( $RANDOM % 32 ) + 1 ]s
git pull --rebase origin "${BRANCH}"
git push --quiet --set-upstream origin "${BRANCH}"
fi
i=$(( $i + 1 ))
done

3
.gitignore vendored
View File

@ -115,5 +115,8 @@ src/tests/p11test/p11test
tests/*.log
tests/*.trs
src/tests/unittests/*.log
src/tests/unittests/*.trs
src/tests/unittests/asn1
version.m4.ci

View File

@ -11,13 +11,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 +28,6 @@ matrix:
dist: bionic
env:
- DO_SIMULATION=cac
sudo: true
env:
global:
@ -102,8 +99,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 +283,7 @@ script:
fi
- if [ "${DO_SIMULATION}" = "cac" ]; then
cd $TRAVIS_BUILD_DIR;
make check && sudo make install;
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 &
@ -321,5 +321,4 @@ cache:
- $HOME/Library/Caches/Homebrew
- openssl_bin
- openpace_bin
files:
- isetup-5.5.6.exe
- isetup

37
COPYING
View File

@ -1,8 +1,8 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -10,7 +10,7 @@
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
@ -111,8 +111,8 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
@ -158,7 +158,7 @@ Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
@ -267,7 +267,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@ -455,8 +455,8 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
@ -485,7 +485,7 @@ convey the exclusion of warranty; and each file should have at least the
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
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
@ -501,4 +501,3 @@ necessary. Here is a sample; alter the names:
That's all there is to it!

View File

@ -9,20 +9,57 @@ https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/D
<background file="background.jpg" mime-type="image/jpeg" scaling="tofit"/>
<welcome file="Welcome.html" mime-type="text/html"/>
<title>@PACKAGE_STRING@</title>
<options customize="allow" require-scripts="false"/>
<options customize="allow" require-scripts="false" rootVolumeOnly="true"/>
<script>
<![CDATA[
function osx_before_catalina() {
if((system.compareVersions(system.version.ProductVersion, '10.15')) == -1)
{
return true;
}
else
{
return false;
}
}
function osx_after_catalina() {
if((system.compareVersions(system.version.ProductVersion, '10.15')) >= 0)
{
return true;
}
else
{
return false;
}
}
function osx_after_yosemite() {
if((system.compareVersions(system.version.ProductVersion, '10.12')) >= 0)
{
return true;
}
else
{
return false;
}
}
]]>
</script>
<choices-outline>
<line choice="default">
<line choice="tokend" />
<line choice="startup" />
</line>
<line choice="default" />
<line choice="startup" />
<line choice="tokend" />
<line choice="token" />
</choices-outline>
<choice id="default" title="OpenSC PKCS11 and tools" enabled="false">
<choice id="default" title="PKCS#11 module and smart card tools" enabled="false">
<pkg-ref id="org.opensc-project.mac">OpenSC.pkg</pkg-ref>
</choice>
<choice id="tokend" title="OpenSC tokend">
<choice id="tokend" title="TokenD-based smart card driver" start_selected="osx_before_catalina()">
<pkg-ref id="org.opensc-project.tokend">OpenSC-tokend.pkg</pkg-ref>
</choice>
<choice id="startup" title="OpenSC startup icons">
<choice id="token" title="CryptoTokenKit-based smart card driver" visible="osx_after_yosemite()" start_selected="osx_after_catalina()">
<pkg-ref id="org.opensc-project.mac.opensctoken">OpenSCToken.pkg</pkg-ref>
</choice>
<choice id="startup" title="Automatic startup items">
<pkg-ref id="org.opensc-project.startup">OpenSC-startup.pkg</pkg-ref>
</choice>
</installer-gui-script>

View File

@ -1,5 +1,5 @@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
EXTRA_DIST = build build-package.in Distribution.xml.in libtool-bundle opensc-uninstall \
EXTRA_DIST = build build-package.in build-package-from-ci.in Distribution.xml.in libtool-bundle opensc-uninstall \
resources \
resources/background.jpg \
resources/Welcome.html.in \

80
MacOSX/build-package-from-ci.in Executable file
View File

@ -0,0 +1,80 @@
#!/bin/bash
# temporary build script until we've fixed the CI to include CTK
# You need to install the following packages from homebrew or macports or fink:
# autoconf automake libtool pkg-config help2man gengetopt
export MACOSX_DEPLOYMENT_TARGET="10.10"
set -ex
test -x ./configure || ./bootstrap
BUILDPATH=${PWD}
# Locate the latest OSX SDK
SDK_PATH=$(xcrun --sdk macosx --show-sdk-path)
# Set SDK path
export CFLAGS="$CFLAGS -isysroot $SDK_PATH -arch x86_64"
# Build OpenSCToken
if ! test -e OpenSCToken; then
git clone --depth=1 https://github.com/frankmorgner/OpenSCToken.git
fi
cd OpenSCToken
# make sure OpenSCToken builds with the same dependencies as before
if ! test -e OpenSC; then
git clone --depth=1 ../../OpenSC
else
cd OpenSC && git pull && cd ..
fi
if ! test -e openssl; then
git clone --depth=1 https://github.com/openssl/openssl.git -b OpenSSL_1_0_2-stable
else
cd openssl && git pull && cd ..
fi
if ! test -e openpace; then
git clone --depth=1 https://github.com/frankmorgner/openpace.git -b 1.1.0
else
cd openpace && git pull && cd ..
fi
BP=${BUILDPATH}
. ./bootstrap
BUILDPATH=${BP}
xcodebuild -target OpenSCTokenApp -configuration Debug -project OpenSCTokenApp.xcodeproj install DSTROOT=${BUILDPATH}/target_token
cd ..
imagedir=$(mktemp -d)
# Get name of branch in Nightly which corresponds to the latest commit in OpenSC
BRANCH=`git log --max-count=1 --date=short --abbrev=8 --pretty=format:"%cd_%h"`
if ! test -e Nightly-${BRANCH}; then
# Download the build
curl -L https://github.com/OpenSC/Nightly/archive/${BRANCH}.zip > ${BRANCH}.zip
# Unpack the build
unzip ${BRANCH}.zip
fi
cp Nightly-${BRANCH}/OpenSC-startup.pkg .
cp Nightly-${BRANCH}/OpenSC-tokend.pkg .
cp Nightly-${BRANCH}/OpenSC.pkg .
# Build package
pkgbuild --root ${BUILDPATH}/target_token --identifier org.opensc-project.mac.opensctoken --version @PACKAGE_VERSION@ --install-location / OpenSCToken.pkg
# Build product
productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION@.pkg"
# Build "Uninstaller"
osacompile -o "${imagedir}/OpenSC Uninstaller.app" "MacOSX/OpenSC_Uninstaller.applescript"
# Create .dmg
rm -f OpenSC-@PACKAGE_VERSION@.dmg
i=0
while ! hdiutil create -srcfolder "${imagedir}" -volname "@PACKAGE_NAME@" -fs JHFS+ OpenSC-@PACKAGE_VERSION@.dmg
do
i=$[$i+1]
if [ $i -gt 2 ]
then
exit 1
fi
done
rm -rf ${imagedir}

View File

@ -28,15 +28,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 +47,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
@ -87,16 +86,31 @@ if ! test -e ${BUILDPATH}/target/$PREFIX/lib/pkgconfig; then
./MacOSX/libtool-bundle ${BUILDPATH}/target/$PREFIX/lib/opensc-pkcs11.so ${BUILDPATH}/target/$PREFIX/lib
fi
# Check out OpenSC.tokend, if not already fetched.
if ! test -e OpenSC.tokend; then
git clone http://github.com/OpenSC/OpenSC.tokend.git
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/
mkdir -p "$BUILDPATH/target/Applications"
osacompile -o "$BUILDPATH/target/Applications/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript"
# Create the symlink to OpenSC sources
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
# Build OpenSC.tokend when XCode version < 10
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
fi
# Create the symlink to OpenSC sources
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
else
# https://github.com/OpenSC/OpenSC.tokend/issues/33
mkdir -p ${BUILDPATH}/target_tokend
fi
#if ! test -e $BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications/terminal-notifier.app; then
#if ! test -e terminal-notifier-1.7.1.zip; then
@ -109,13 +123,6 @@ xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Token
#cp -r terminal-notifier-1.7.1/terminal-notifier.app $BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/Applications
#fi
if ! test -e NotificationProxy; then
git clone http://github.com/frankmorgner/NotificationProxy.git
fi
xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target_tokend/Library/Security/tokend/OpenSC.tokend/Contents/Resources/
mkdir -p "$BUILDPATH/target/Applications"
osacompile -o "$BUILDPATH/target/Applications/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript"
imagedir=$(mktemp -d)
# Prepare target root
@ -127,10 +134,41 @@ mkdir -p ${BUILDPATH}/target_startup/Library/LaunchAgents
cp src/tools/pkcs11-register.plist ${BUILDPATH}/target_startup/Library/LaunchAgents
cp src/tools/opensc-notify.plist ${BUILDPATH}/target_startup/Library/LaunchAgents
# Build OpenSCToken if possible
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
else
cd OpenSC && git pull && cd ..
fi
if ! test -e openssl; then
git clone --depth=1 ../openssl
else
cd openssl && git pull && cd ..
fi
if ! test -e openpace; then
git clone --depth=1 ../openpace
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 ..
else
# if no OpenSCToken is checked out, then we create a dummy package
mkdir -p ${BUILDPATH}/target_token
fi
# Build package
pkgbuild --root ${BUILDPATH}/target --scripts MacOSX/scripts --identifier org.opensc-project.mac --version @PACKAGE_VERSION@ --install-location / OpenSC.pkg
pkgbuild --root ${BUILDPATH}/target_tokend --identifier org.opensc-project.tokend --version @PACKAGE_VERSION@ --install-location / OpenSC-tokend.pkg
pkgbuild --root ${BUILDPATH}/target_token --identifier org.opensc-project.mac.opensctoken --version @PACKAGE_VERSION@ --install-location / OpenSCToken.pkg
pkgbuild --root ${BUILDPATH}/target_startup --identifier org.opensc-project.startup --version @PACKAGE_VERSION@ --install-location / OpenSC-startup.pkg
# Build product
productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION@.pkg"

View File

@ -6,6 +6,8 @@ if [ "$(id -u)" != "0" ]; then
exit 1
fi
pluginkit -r -i org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken
for f in \
/Library/OpenSC/bin/* \
/Library/OpenSC/etc/bash_completion.d/* \
@ -24,14 +26,23 @@ rm -f /usr/local/lib/opensc-pkcs11.so
rm -f /usr/local/lib/onepin-opensc-pkcs11.so
# Remove installed files
rm -rf /Applications/OpenSCTokenApp.app
rm -rf "/Applications/OpenSC Notify.app"
rm -rf /Library/OpenSC
rm -rf /Library/Security/tokend/OpenSC.tokend
rm -f /Library/LaunchAgents/pkcs11-register.plist
rm -f /Library/LaunchAgents/opensc-notify.plist
rm -rf /System/Library/Security/tokend/OpenSC.tokend
# Unload launchagents
launchctl remove pkcs11-register
launchctl remove opensc-notify
# delete receipts on 10.6+
pkgutil --forget org.opensc-project.mac > /dev/null
pkgutil --forget org.opensc-project.tokend > /dev/null
pkgutil --forget org.opensc-project.mac.opensctoken > /dev/null
pkgutil --forget org.opensc-project.startup > /dev/null
# remove this script
rm -f /usr/local/bin/opensc-uninstall

View File

@ -40,4 +40,8 @@ do
fi
done
if [ -e /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex ]
sudo -u _securityagent pluginkit -a /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex
fi
exit 0

View File

@ -28,6 +28,10 @@ dist_noinst_DATA = README \
packaging/debian.templates/rules
dist_doc_DATA = NEWS
include $(top_srcdir)/aminclude_static.am
clean-local: code-coverage-clean
distclean-local: code-coverage-dist-clean
Generate-ChangeLog:
rm -f ChangeLog.tmp "$(srcdir)/ChangeLog"
test -n "$(GIT)"

106
NEWS
View File

@ -1,5 +1,111 @@
NEWS for OpenSC -- History of user visible changes
# New in 0.20.0; 2019-12-29
## General Improvements
* fixed security problems
* CVE-2019-6502 (#1586)
* CVE-2019-15946 (a3fc769)
* CVE-2019-15945 (412a614)
* CVE-2019-19480 (6ce6152284c47ba9b1d4fe8ff9d2e6a3f5ee02c7)
* CVE-2019-19481 (b75c002cfb1fd61cd20ec938ff4937d7b1a94278)
* CVE-2019-19479 (c3f23b836e5a1766c36617fe1da30d22f7b63de2)
* Support RSA-PSS signature mechanisms using RSA-RAW (#1435)
* Added memory locking for secrets (#1491)
* added support for terminal colors (#1534)
* PC/SC driver: Fixed error handling in case of changing (#1537) or removing the card reader (#1615)
* macOS installer
* Add installer option to deselect tokend (#1607)
* Make OpenSCToken available on 10.12+ and the default on 10.15+ (2017626ed237dbdd4683a4b9410fc610618200c5)
* Configuration
* rename `md_read_only` to `read_only` and use it for PKCS#11 and Minidriver (#1467)
* allow global use of ignore_private_certificate (#1623)
* Build Environment
* Bump openssl requirement to 0.9.8 (##1459)
* Added support for fuzzing with AFL (#1580) and libFuzzer/OSS-Fuzz (#1697)
* Added CI tests for simulating GIDS, OpenPGP, PIV, IsoApplet (#1568) and MyEID (#1677) and CAC (#1757)
* Integrate clang-tidy with `make check` (#1673)
* Added support for reproducible builds (#1839)
## PKCS#11
* Implement write protection (CKF_WRITE_PROTECTED) based on the card profile (#1467)
* Added C_WrapKey and C_UnwrapKey implementations (#1393)
* Handle CKA_ALWAYS_AUTHENTICATE when creating key objects. (#1539)
* Truncate long PKCS#11 labels with ... (#1629)
* Fixed recognition of a token when being unplugged and reinserted (#1875)
## Minidriver
* Register for CardOS5 cards (#1750)
* Add support for RSA-PSS (263b945)
## OpenSC tools
* Harmonize the use of option `-r`/`--reader` (#1548)
* `goid-tool`: GoID personalization with fingerprint
* `openpgp-tool`
* replace the options `-L`/` --key-length` with `-t`/`--key-type` (#1508)
* added options `-C`/`--card-info` and `-K`/`--key-info` (#1508)
* `opensc-explorer`
* add command `pin_info` (#1487)
* extend `random` to allow writing to a file (#1487)
* `opensc-minidriver-test.exe`: Tests for Microsoft CryptoAPI (#1510)
* `opensc-notify`: Autostart on Windows
* `pkcs11-register`:
* Auto-configuration of applications for use of OpenSC PKCS#11 (#1644)
* Autostart on Windows, macOS and Linux (#1644)
* `opensc-tool`: Show ATR also for cards not recognized by OpenSC (#1625)
* `pkcs11-spy`:
* parse CKM_AES_GCM
* Add support for CKA_OTP_* and CKM_*_PSS values
* parse EC Derive parameters (#1677)
* `pkcs11-tool`
* Support for signature verification via `--verify` (#1435)
* Add object type `secrkey` for `--type` option (#1575)
* Implement Secret Key write object (#1648)
* Add GOSTR3410-2012 support (#1654)
* Add support for testing CKM_RSA_PKCS_OAEP (#1600)
* Add extractable option to key import (#1674)
* list more key access flags when listing keys (#1653)
* Add support for `CKA_ALLOWED_MECHANISMS` when creating new objects and listing keys (#1628)
* `pkcs15-crypt`: * Handle keys with user consent (#1529)
## CAC1
New separate CAC1 driver using the old CAC specification (#1502)
## CardOS
* Add support for 4K RSA keys in CardOS 5 (#1776)
* Fixed decryption with CardOS 5 (#1867)
## Coolkey
* Enable CoolKey driver to handle 2048-bit keys. (#1532)
## EstEID
* adds support for a minimalistic, small and fast card profile based on IAS-ECC issued since December 2018 (#1635)
## GIDS
* GIDS Decipher fix (#1881)
* Allow RSA 4K support (#1891)
## MICARDO
* Remove long expired EstEID 1.0/1.1 card support (#1470)
## MyEID
* Add support for unwrapping a secret key with an RSA key or secret key (#1393)
* Add support for wrapping a secret key with a secret key (#1393)
* Support for MyEID 4K RSA (#1657)
* Support for OsEID (#1677).
## Gemalto GemSafe
* add new PTeID ATRs (#1683)
* Add support for 4K RSA keys (#1863, #1872)
## OpenPGP
* OpenPGP Card v3 ECC support (#1506)
## Rutoken
* Add Rutoken ECP SC (#1652)
* Add Rutoken Lite (#1728)
## SC-HSM
* Add SmartCard-HSM 4K ATR (#1681)
* Add missing secp384r1 curve parameter (#1696)
## Starcos
* Fixed decipher with 2.3 (#1496)
* Added ATR for 2nd gen. eGK (#1668)
* Added new ATR for 3.5 (#1882)
* Detect and allow Globalplatform PIN encoding (#1882)
## TCOS
* Fix TCOS IDKey support (#1880)
* add encryption certificate for IDKey (#1892)
## Infocamere, Postecert, Cnipa
* Removed profiles (#1584)
## ACS ACOS5
* Remove incomplete acos5 driver (#1622).
# New in 0.19.0; 2018-09-13
## General Improvements
* fixed multiple security problems (out of bound writes/reads, #1447):

View File

@ -4,7 +4,7 @@ Wiki is [available online](https://github.com/OpenSC/OpenSC/wiki)
Please take a look at the documentation before trying to use OpenSC.
[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC/branches) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/OpenSC/OpenSC.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenSC/OpenSC/context:cpp)
[![Travis CI Build Status](https://travis-ci.org/OpenSC/OpenSC.svg)](https://travis-ci.org/OpenSC/OpenSC/branches) [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master) [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/OpenSC/OpenSC.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenSC/OpenSC/context:cpp) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/opensc.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:opensc)
Build and test status of specific cards:

View File

@ -1,5 +1,13 @@
version: 0.20.0.{build}
image:
# not compatible with OpenSSL 1.1.1:
# - Visual Studio 2013
# not compatible with WiX 3.11.2:
# - Visual Studio 2019
- Visual Studio 2015
- Visual Studio 2017
platform:
- x86
- x64
@ -11,10 +19,6 @@ configuration:
environment:
GH_TOKEN:
secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY
matrix:
- VSVER: 14
- VSVER: 12
DO_PUSH_ARTIFACT: yes
install:
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
@ -40,7 +44,7 @@ install:
If ($env:Configuration -Like "*Light*") {
$env:ARTIFACT="${env:ARTIFACT}-Light"
} Else {
$env:NMAKE_EXTRA="OPENSSL_DEF=/DENABLE_OPENSSL ${env:NMAKE_EXTRA}"
$env:NMAKE_EXTRA="OPENSSL_DEF=/DENABLE_OPENSSL OPENSSL_DIR=C:\OpenSSL-v111-${env:OPENSSL_PF} ${env:NMAKE_EXTRA}"
$env:NMAKE_EXTRA="OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536 ${env:NMAKE_EXTRA}"
If (!(Test-Path C:\zlib )) {
appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip
@ -56,9 +60,19 @@ 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%
- ps: >-
If ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {
$env:VCVARSALL="${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat"
} ElseIf ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2017") {
$env:VCVARSALL="${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat"
} ElseIf ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") {
$env:VCVARSALL="${env:VS140COMNTOOLS}\..\..\VC\vcvarsall.bat"
$env:DO_PUSH_ARTIFACT="yes"
} ElseIf ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2013") {
$env:VCVARSALL="${env:VS120COMNTOOLS}\..\..\VC\vcvarsall.bat"
}
- echo "Using %APPVEYOR_BUILD_WORKER_IMAGE% with %VCVARSALL%"
- call "%VCVARSALL%" %VCVARS_PLATFORM%
- cngsdk.msi /quiet
- uname -a
- set
@ -79,9 +93,11 @@ build_script:
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 /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 /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 /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
#cl /IC:\OpenSSL-v111-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
lib /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj
cd C:\projects\OpenSC
}
@ -95,7 +111,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 /f Makefile.mak %NMAKE_EXTRA% OpenSC.msi && cd ..
- move win32\OpenSC.msi %ARTIFACT%.msi
# put all pdb files for dump analysis, but this consumes approx 100 MB per build
- md %ARTIFACT%-Debug

View File

@ -21,6 +21,8 @@ define([VS_FF_PRODUCT_URL], [https://github.com/OpenSC/OpenSC])
m4_sinclude(version.m4.ci)
m4_define([openssl_minimum_version], [1.0.1])
AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX],[PRODUCT_BUGREPORT],[PRODUCT_TARNAME],[PRODUCT_URL])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_HEADERS([config.h])
@ -129,6 +131,8 @@ case "${host}" in
;;
esac
AX_CODE_COVERAGE()
AX_CHECK_COMPILE_FLAG([-Wunknown-warning-option], [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"], [-Werror])
AM_CONDITIONAL([HAVE_UNKNOWN_WARNING_OPTION], [test "${have_unknown_warning_option}" = "yes"])
@ -411,7 +415,7 @@ AC_FUNC_STAT
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([ \
getpass gettimeofday getline memset mkdir \
strdup strerror \
strdup strerror memset_s explicit_bzero \
strlcpy strlcat strnlen sigaction
])
AC_CHECK_SIZEOF(void *)
@ -632,7 +636,7 @@ fi
PKG_CHECK_MODULES(
[OPENSSL],
[libcrypto >= 0.9.8],
[libcrypto >= openssl_minimum_version],
[have_openssl="yes"],
[AC_CHECK_LIB(
[crypto],
@ -1068,10 +1072,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([
@ -1096,6 +1100,7 @@ AC_CONFIG_FILES([
src/tests/regression/Makefile
src/tests/p11test/Makefile
src/tests/fuzzing/Makefile
src/tests/unittests/Makefile
src/tools/Makefile
src/tools/versioninfo-tools.rc
src/tools/versioninfo-opensc-notify.rc
@ -1111,6 +1116,7 @@ AC_CONFIG_FILES([
win32/OpenSC.wxs
MacOSX/Makefile
MacOSX/build-package
MacOSX/build-package-from-ci
MacOSX/Distribution.xml
MacOSX/resources/Welcome.html
])
@ -1157,6 +1163,7 @@ SM default module: ${DEFAULT_SM_MODULE}
SM default path: $(eval eval eval echo "${DEFAULT_SM_MODULE_PATH}")
DNIe UI support: ${enable_dnie_ui}
Notification support: ${enable_notify}
Code coverage: ${enable_code_coverage}
PC/SC default provider: ${DEFAULT_PCSC_PROVIDER}
PKCS11 default provider: $(eval eval eval echo "${DEFAULT_PKCS11_PROVIDER}")

View File

@ -5,6 +5,7 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="docbook.xsl"/>
<xsl:param name="toc.section.depth" select="0"/>
<xsl:param name="generate.consistent.ids" select="1"/>
<xsl:template name="user.head.content">
<style type="text/css">
<xsl:comment>

View File

@ -33,13 +33,6 @@ smart cards and similar security tokens based on Siemens Card/OS M4.
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term>
<option>--card-driver</option> <replaceable>name</replaceable>,
<option>-c</option> <replaceable>name</replaceable></term>
<listitem><para>Use the card driver specified by <replaceable>name</replaceable>.
The default is to auto-detect the correct card driver.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--format</option>,

View File

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

View File

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

View File

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

View File

@ -55,8 +55,11 @@
<option>-c</option> <replaceable>driver</replaceable>
</term>
<listitem><para>
Use the given card driver. The default is
auto-detected.
Use the given card driver.
The default is to auto-detect the correct card driver.
The literal value <literal>?</literal> lists
all available card drivers and terminates
<command>opensc-explorer</command>.
</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -52,8 +52,12 @@
<option>--card-driver</option> <replaceable>driver</replaceable>,
<option>-c</option> <replaceable>driver</replaceable>
</term>
<listitem><para>Use the given card driver.
The default is auto-detected.</para></listitem>
<listitem><para>
Use the given card driver.
The default is to auto-detect the correct card driver.
The literal value <literal>?</literal> lists
all available card drivers.
</para></listitem>
</varlistentry>
<varlistentry>
<term>

View File

@ -163,14 +163,6 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--card-driver</option> <replaceable>driver</replaceable>,
<option>-c</option> <replaceable>driver</replaceable>
</term>
<listitem><para>Use the given card driver.
The default is auto-detected.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--wait</option>,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,32 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_ac_append_to_file.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AC_APPEND_TO_FILE([FILE],[DATA])
#
# DESCRIPTION
#
# Appends the specified data to the specified Autoconf is run. If you want
# to append to a file when configure is run use AX_APPEND_TO_FILE instead.
#
# LICENSE
#
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_AC_APPEND_TO_FILE],[
AC_REQUIRE([AX_FILE_ESCAPES])
m4_esyscmd(
AX_FILE_ESCAPES
[
printf "%s" "$2" >> "$1"
])
])

32
m4/ax_ac_print_to_file.m4 Normal file
View File

@ -0,0 +1,32 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_ac_print_to_file.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AC_PRINT_TO_FILE([FILE],[DATA])
#
# DESCRIPTION
#
# Writes the specified data to the specified file when Autoconf is run. If
# you want to print to a file when configure is run use AX_PRINT_TO_FILE
# instead.
#
# LICENSE
#
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_AC_PRINT_TO_FILE],[
m4_esyscmd(
AC_REQUIRE([AX_FILE_ESCAPES])
[
printf "%s" "$2" > "$1"
])
])

View File

@ -0,0 +1,28 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_add_am_macro_static.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_ADD_AM_MACRO_STATIC([RULE])
#
# DESCRIPTION
#
# Adds the specified rule to $AMINCLUDE.
#
# LICENSE
#
# Copyright (c) 2009 Tom Howard <tomhoward@users.sf.net>
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AC_DEFUN([AX_ADD_AM_MACRO_STATIC],[
AC_REQUIRE([AX_AM_MACROS_STATIC])
AX_AC_APPEND_TO_FILE(AMINCLUDE_STATIC,[$1])
])

38
m4/ax_am_macros_static.m4 Normal file
View File

@ -0,0 +1,38 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_am_macros_static.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AM_MACROS_STATIC
#
# DESCRIPTION
#
# Adds support for macros that create Automake rules. You must manually
# add the following line
#
# include $(top_srcdir)/aminclude_static.am
#
# to your Makefile.am files.
#
# LICENSE
#
# Copyright (c) 2009 Tom Howard <tomhoward@users.sf.net>
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
AC_DEFUN([AMINCLUDE_STATIC],[aminclude_static.am])
AC_DEFUN([AX_AM_MACROS_STATIC],
[
AX_AC_PRINT_TO_FILE(AMINCLUDE_STATIC,[
# ]AMINCLUDE_STATIC[ generated automatically by Autoconf
# from AX_AM_MACROS_STATIC on ]m4_esyscmd([LC_ALL=C date])[
])
])

95
m4/ax_check_gnu_make.m4 Normal file
View File

@ -0,0 +1,95 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_gnu_make.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_GNU_MAKE([run-if-true],[run-if-false])
#
# DESCRIPTION
#
# This macro searches for a GNU version of make. If a match is found:
#
# * The makefile variable `ifGNUmake' is set to the empty string, otherwise
# it is set to "#". This is useful for including a special features in a
# Makefile, which cannot be handled by other versions of make.
# * The makefile variable `ifnGNUmake' is set to #, otherwise
# it is set to the empty string. This is useful for including a special
# features in a Makefile, which can be handled
# by other versions of make or to specify else like clause.
# * The variable `_cv_gnu_make_command` is set to the command to invoke
# GNU make if it exists, the empty string otherwise.
# * The variable `ax_cv_gnu_make_command` is set to the command to invoke
# GNU make by copying `_cv_gnu_make_command`, otherwise it is unset.
# * If GNU Make is found, its version is extracted from the output of
# `make --version` as the last field of a record of space-separated
# columns and saved into the variable `ax_check_gnu_make_version`.
# * Additionally if GNU Make is found, run shell code run-if-true
# else run shell code run-if-false.
#
# Here is an example of its use:
#
# Makefile.in might contain:
#
# # A failsafe way of putting a dependency rule into a makefile
# $(DEPEND):
# $(CC) -MM $(srcdir)/*.c > $(DEPEND)
#
# @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND)))
# @ifGNUmake@ include $(DEPEND)
# @ifGNUmake@ else
# fallback code
# @ifGNUmake@ endif
#
# Then configure.in would normally contain:
#
# AX_CHECK_GNU_MAKE()
# AC_OUTPUT(Makefile)
#
# Then perhaps to cause gnu make to override any other make, we could do
# something like this (note that GNU make always looks for GNUmakefile
# first):
#
# if ! test x$_cv_gnu_make_command = x ; then
# mv Makefile GNUmakefile
# echo .DEFAULT: > Makefile ;
# echo \ $_cv_gnu_make_command \$@ >> Makefile;
# fi
#
# Then, if any (well almost any) other make is called, and GNU make also
# exists, then the other make wraps the GNU make.
#
# LICENSE
#
# Copyright (c) 2008 John Darrington <j.darrington@elvis.murdoch.edu.au>
# Copyright (c) 2015 Enrico M. Crisostomo <enrico.m.crisostomo@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 12
AC_DEFUN([AX_CHECK_GNU_MAKE],dnl
[AC_PROG_AWK
AC_CACHE_CHECK([for GNU make],[_cv_gnu_make_command],[dnl
_cv_gnu_make_command="" ;
dnl Search all the common names for GNU make
for a in "$MAKE" make gmake gnumake ; do
if test -z "$a" ; then continue ; fi ;
if "$a" --version 2> /dev/null | grep GNU 2>&1 > /dev/null ; then
_cv_gnu_make_command=$a ;
AX_CHECK_GNU_MAKE_HEADLINE=$("$a" --version 2> /dev/null | grep "GNU Make")
ax_check_gnu_make_version=$(echo ${AX_CHECK_GNU_MAKE_HEADLINE} | ${AWK} -F " " '{ print $(NF); }')
break ;
fi
done ;])
dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifGNUmake], ["#"])], [AS_VAR_SET([ifGNUmake], [""])])
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifnGNUmake], [""])], [AS_VAR_SET([ifnGNUmake], ["#"])])
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_UNSET(ax_cv_gnu_make_command)], [AS_VAR_SET([ax_cv_gnu_make_command], [${_cv_gnu_make_command}])])
AS_VAR_IF([_cv_gnu_make_command], [""],[$2],[$1])
AC_SUBST([ifGNUmake])
AC_SUBST([ifnGNUmake])
])

272
m4/ax_code_coverage.m4 Normal file
View File

@ -0,0 +1,272 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CODE_COVERAGE()
#
# DESCRIPTION
#
# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included
# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every
# build target (program or library) which should be built with code
# coverage support. Also add rules using AX_ADD_AM_MACRO_STATIC; and
# $enable_code_coverage which can be used in subsequent configure output.
# CODE_COVERAGE_ENABLED is defined and substituted, and corresponds to the
# value of the --enable-code-coverage option, which defaults to being
# disabled.
#
# Test also for gcov program and create GCOV variable that could be
# substituted.
#
# Note that all optimization flags in CFLAGS must be disabled when code
# coverage is enabled.
#
# Usage example:
#
# configure.ac:
#
# AX_CODE_COVERAGE
#
# Makefile.am:
#
# include $(top_srcdir)/aminclude_static.am
#
# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...
# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
#
# clean-local: code-coverage-clean
# distclean-local: code-coverage-dist-clean
#
# This results in a "check-code-coverage" rule being added to any
# Makefile.am which do "include $(top_srcdir)/aminclude_static.am"
# (assuming the module has been configured with --enable-code-coverage).
# Running `make check-code-coverage` in that directory will run the
# module's test suite (`make check`) and build a code coverage report
# detailing the code which was touched, then print the URI for the report.
#
# This code was derived from Makefile.decl in GLib, originally licensed
# under LGPLv2.1+.
#
# LICENSE
#
# Copyright (c) 2012, 2016 Philip Withnall
# Copyright (c) 2012 Xan Lopez
# Copyright (c) 2012 Christian Persch
# Copyright (c) 2012 Paolo Borelli
# Copyright (c) 2012 Dan Winship
# Copyright (c) 2015,2018 Bastien ROUCARIES
#
# 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 program. If not, see <https://www.gnu.org/licenses/>.
#serial 32
m4_define(_AX_CODE_COVERAGE_RULES,[
AX_ADD_AM_MACRO_STATIC([
# Code coverage
#
# Optional:
# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
# Multiple directories may be specified, separated by whitespace.
# (Default: \$(top_builddir))
# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
# by lcov for code coverage. (Default:
# \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage.info)
# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
# reports to be created. (Default:
# \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage)
# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
# set to 0 to disable it and leave empty to stay with the default.
# (Default: empty)
# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
# lcov instance. (Default: empty)
# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
#
# The generated report will be titled using the \$(PACKAGE_NAME) and
# \$(PACKAGE_VERSION). In order to add the current git hash to the title,
# use the git-version-gen script, available online.
# Optional variables
# run only on top dir
if CODE_COVERAGE_ENABLED
ifeq (\$(abs_builddir), \$(abs_top_builddir))
CODE_COVERAGE_DIRECTORY ?= \$(top_builddir)
CODE_COVERAGE_OUTPUT_FILE ?= \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage.info
CODE_COVERAGE_OUTPUT_DIRECTORY ?= \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage
CODE_COVERAGE_BRANCH_COVERAGE ?=
CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= \$(if \$(CODE_COVERAGE_BRANCH_COVERAGE),\
--rc lcov_branch_coverage=\$(CODE_COVERAGE_BRANCH_COVERAGE))
CODE_COVERAGE_LCOV_SHOPTS ?= \$(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool \"\$(GCOV)\"
CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= \$(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
CODE_COVERAGE_LCOV_OPTIONS ?= \$(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
CODE_COVERAGE_LCOV_RMOPTS ?= \$(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
\$(if \$(CODE_COVERAGE_BRANCH_COVERAGE),\
--rc genhtml_branch_coverage=\$(CODE_COVERAGE_BRANCH_COVERAGE))
CODE_COVERAGE_GENHTML_OPTIONS ?= \$(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
CODE_COVERAGE_IGNORE_PATTERN ?=
GITIGNOREFILES = \$(GITIGNOREFILES) \$(CODE_COVERAGE_OUTPUT_FILE) \$(CODE_COVERAGE_OUTPUT_DIRECTORY)
code_coverage_v_lcov_cap = \$(code_coverage_v_lcov_cap_\$(V))
code_coverage_v_lcov_cap_ = \$(code_coverage_v_lcov_cap_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_lcov_cap_0 = @echo \" LCOV --capture\" \$(CODE_COVERAGE_OUTPUT_FILE);
code_coverage_v_lcov_ign = \$(code_coverage_v_lcov_ign_\$(V))
code_coverage_v_lcov_ign_ = \$(code_coverage_v_lcov_ign_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_lcov_ign_0 = @echo \" LCOV --remove /tmp/*\" \$(CODE_COVERAGE_IGNORE_PATTERN);
code_coverage_v_genhtml = \$(code_coverage_v_genhtml_\$(V))
code_coverage_v_genhtml_ = \$(code_coverage_v_genhtml_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_genhtml_0 = @echo \" GEN \" \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\";
code_coverage_quiet = \$(code_coverage_quiet_\$(V))
code_coverage_quiet_ = \$(code_coverage_quiet_\$(AM_DEFAULT_VERBOSITY))
code_coverage_quiet_0 = --quiet
# sanitizes the test-name: replaces with underscores: dashes and dots
code_coverage_sanitize = \$(subst -,_,\$(subst .,_,\$(1)))
# Use recursive makes in order to ignore errors during check
check-code-coverage:
-\$(AM_V_at)\$(MAKE) \$(AM_MAKEFLAGS) -k check
\$(AM_V_at)\$(MAKE) \$(AM_MAKEFLAGS) code-coverage-capture
# Capture code coverage data
code-coverage-capture: code-coverage-capture-hook
\$(code_coverage_v_lcov_cap)\$(LCOV) \$(code_coverage_quiet) \$(addprefix --directory ,\$(CODE_COVERAGE_DIRECTORY)) --capture --output-file \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" --test-name \"\$(call code_coverage_sanitize,\$(PACKAGE_NAME)-\$(PACKAGE_VERSION))\" --no-checksum --compat-libtool \$(CODE_COVERAGE_LCOV_SHOPTS) \$(CODE_COVERAGE_LCOV_OPTIONS)
\$(code_coverage_v_lcov_ign)\$(LCOV) \$(code_coverage_quiet) \$(addprefix --directory ,\$(CODE_COVERAGE_DIRECTORY)) --remove \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" \"/tmp/*\" \$(CODE_COVERAGE_IGNORE_PATTERN) --output-file \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \$(CODE_COVERAGE_LCOV_SHOPTS) \$(CODE_COVERAGE_LCOV_RMOPTS)
-@rm -f \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\"
\$(code_coverage_v_genhtml)LANG=C \$(GENHTML) \$(code_coverage_quiet) \$(addprefix --prefix ,\$(CODE_COVERAGE_DIRECTORY)) --output-directory \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\" --title \"\$(PACKAGE_NAME)-\$(PACKAGE_VERSION) Code Coverage\" --legend --show-details \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \$(CODE_COVERAGE_GENHTML_OPTIONS)
@echo \"file://\$(abs_builddir)/\$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html\"
code-coverage-clean:
-\$(LCOV) --directory \$(top_builddir) -z
-rm -rf \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\"
-find . \\( -name \"*.gcda\" -o -name \"*.gcno\" -o -name \"*.gcov\" \\) -delete
code-coverage-dist-clean:
A][M_DISTCHECK_CONFIGURE_FLAGS = \$(A][M_DISTCHECK_CONFIGURE_FLAGS) --disable-code-coverage
else # ifneq (\$(abs_builddir), \$(abs_top_builddir))
check-code-coverage:
code-coverage-capture: code-coverage-capture-hook
code-coverage-clean:
code-coverage-dist-clean:
endif # ifeq (\$(abs_builddir), \$(abs_top_builddir))
else #! CODE_COVERAGE_ENABLED
# Use recursive makes in order to ignore errors during check
check-code-coverage:
@echo \"Need to reconfigure with --enable-code-coverage\"
# Capture code coverage data
code-coverage-capture: code-coverage-capture-hook
@echo \"Need to reconfigure with --enable-code-coverage\"
code-coverage-clean:
code-coverage-dist-clean:
endif #CODE_COVERAGE_ENABLED
# Hook rule executed before code-coverage-capture, overridable by the user
code-coverage-capture-hook:
.PHONY: check-code-coverage code-coverage-capture code-coverage-dist-clean code-coverage-clean code-coverage-capture-hook
])
])
AC_DEFUN([_AX_CODE_COVERAGE_ENABLED],[
AX_CHECK_GNU_MAKE([],[AC_MSG_ERROR([not using GNU make that is needed for coverage])])
AC_REQUIRE([AX_ADD_AM_MACRO_STATIC])
# check for gcov
AC_CHECK_TOOL([GCOV],
[$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
[:])
AS_IF([test "X$GCOV" = "X:"],
[AC_MSG_ERROR([gcov is needed to do coverage])])
AC_SUBST([GCOV])
dnl Check if gcc is being used
AS_IF([ test "$GCC" = "no" ], [
AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
])
AC_CHECK_PROG([LCOV], [lcov], [lcov])
AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
AS_IF([ test x"$LCOV" = x ], [
AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])
])
AS_IF([ test x"$GENHTML" = x ], [
AC_MSG_ERROR([Could not find genhtml from the lcov package])
])
dnl Build the code coverage flags
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
CODE_COVERAGE_LIBS="-lgcov"
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
AC_SUBST([CODE_COVERAGE_CFLAGS])
AC_SUBST([CODE_COVERAGE_CXXFLAGS])
AC_SUBST([CODE_COVERAGE_LIBS])
])
AC_DEFUN([AX_CODE_COVERAGE],[
dnl Check for --enable-code-coverage
# allow to override gcov location
AC_ARG_WITH([gcov],
[AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
AC_MSG_CHECKING([whether to build with code coverage support])
AC_ARG_ENABLE([code-coverage],
AS_HELP_STRING([--enable-code-coverage],
[Whether to enable code coverage support]),,
enable_code_coverage=no)
AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test "x$enable_code_coverage" = xyes])
AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
AC_MSG_RESULT($enable_code_coverage)
AS_IF([ test "x$enable_code_coverage" = xyes ], [
_AX_CODE_COVERAGE_ENABLED
])
_AX_CODE_COVERAGE_RULES
])

30
m4/ax_file_escapes.m4 Normal file
View File

@ -0,0 +1,30 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_file_escapes.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_FILE_ESCAPES
#
# DESCRIPTION
#
# Writes the specified data to the specified file.
#
# LICENSE
#
# Copyright (c) 2008 Tom Howard <tomhoward@users.sf.net>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AC_DEFUN([AX_FILE_ESCAPES],[
AX_DOLLAR="\$"
AX_SRB="\\135"
AX_SLB="\\133"
AX_BS="\\\\"
AX_DQ="\""
])

View File

@ -100,7 +100,6 @@ C_UnloadModule(void *module)
if (mod->handle != NULL && sc_dlclose(mod->handle) < 0)
return CKR_FUNCTION_FAILED;
memset(mod, 0, sizeof(*mod));
free(mod);
return CKR_OK;
}

View File

@ -71,8 +71,10 @@
/* disable asserts */
#ifndef SIMCLIST_DEBUG
#ifndef NDEBUG
#define NDEBUG
#endif
#endif
#include <assert.h>

View File

@ -12,7 +12,8 @@ noinst_HEADERS = cards.h ctbcs.h internal.h muscle.h muscle-filesystem.h \
errors.h types.h compression.h itacns.h iso7816.h \
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \
pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h \
jpki.h sc-ossl-compat.h card-npa.h ccid-types.h reader-tr03119.h \
jpki.h sc-ossl-compat.h card-npa.h card-openpgp.h \
ccid-types.h reader-tr03119.h \
card-cac-common.h
AM_CPPFLAGS = -D'OPENSC_CONF_PATH="$(sysconfdir)/opensc.conf"' \
@ -48,14 +49,14 @@ libopensc_la_SOURCES_BASE = \
card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \
card-dnie.c cwa14890.c cwa-dnie.c \
card-isoApplet.c card-masktech.c card-gids.c card-jpki.c \
card-npa.c card-esteid2018.c \
card-npa.c card-esteid2018.c card-idprime.c \
\
pkcs15-openpgp.c pkcs15-starcert.c \
pkcs15-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
@ -131,14 +132,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-tcos.c pkcs15-esteid.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c \
pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \
pkcs15-oberthur.c pkcs15-itacns.c pkcs15-sc-hsm.c \
pkcs15-coolkey.c pkcs15-din-66291.c \
pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \
pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \
compression.c p15card-helper.c sm.c \
aux-data.c \

View File

@ -27,7 +27,7 @@ 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-tcos.obj pkcs15-esteid.obj pkcs15-gemsafeGPK.obj \
@ -35,7 +35,7 @@ OBJECTS = \
pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \
pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \
pkcs15-esteid2018.obj \
pkcs15-esteid2018.obj pkcs15-idprime.obj \
compression.obj p15card-helper.obj sm.obj \
aux-data.obj \
$(TOPDIR)\win32\versioninfo.res

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "internal.h"
#include "asn1.h"
@ -67,7 +68,7 @@ int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out,
*buf = NULL;
if (left == 0)
if (left == 0 || !p)
return SC_ERROR_INVALID_ASN1_OBJECT;
if (*p == 0xff || *p == 0) {
/* end of data reached */
@ -373,7 +374,7 @@ static void print_tags_recursive(const u8 * buf0, const u8 * buf,
size_t len;
r = sc_asn1_read_tag(&tagp, bytesleft, &cla, &tag, &len);
if (r != SC_SUCCESS || tagp == NULL) {
if (r != SC_SUCCESS || (tagp == NULL && tag != SC_ASN1_TAG_EOC)) {
printf("Error in decoding.\n");
return;
}
@ -576,6 +577,13 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
if (inlen < 1)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* 8.6.2.3 If the bitstring is empty, there shall be no subsequent octets,
* and the initial octet shall be zero. */
if (inlen == 1 && *in != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* ITU-T Rec. X.690 8.6.2.2: The number shall be in the range zero to seven. */
if ((*in & ~0x07) != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
memset(outbuf, 0, outlen);
zero_bits = *in & 0x07;
in++;
@ -590,9 +598,13 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
int bits_to_go;
*out = 0;
if (octets_left == 1)
if (octets_left == 1 && zero_bits > 0) {
bits_to_go = 8 - zero_bits;
else
/* Verify the padding is zero bits */
if (*in & (1 << (zero_bits-1))) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
} else
bits_to_go = 8;
if (invert)
for (i = 0; i < bits_to_go; i++) {
@ -677,7 +689,7 @@ static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t
return n;
for (i = 0; i < n; i += 8) {
field |= (data[i/8] << i);
field |= ((unsigned int) data[i/8] << i);
}
memcpy(outbuf, &field, outlen);
return 0;
@ -705,21 +717,44 @@ static int encode_bit_field(const u8 *inbuf, size_t inlen,
return encode_bit_string(data, bits, outbuf, outlen, 1);
}
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out)
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict)
{
int a = 0, is_negative = 0;
size_t i;
size_t i = 0;
if (inlen > sizeof(int) || inlen == 0)
if (inlen == 0) {
return SC_ERROR_INVALID_ASN1_OBJECT;
if (inbuf[0] & 0x80)
is_negative = 1;
for (i = 0; i < inlen; i++) {
a <<= 8;
a |= *inbuf++;
}
if (is_negative)
a *= -1;
if (inlen > sizeof(int)) {
return SC_ERROR_NOT_SUPPORTED;
}
if (inbuf[0] & 0x80) {
if (strict && inlen > 1 && inbuf[0] == 0xff && (inbuf[1] & 0x80)) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
is_negative = 1;
a |= 0xff^(*inbuf++);
i = 1;
} else {
if (strict && inlen > 1 && inbuf[0] == 0x00 && (inbuf[1] & 0x80) == 0) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
}
for (; i < inlen; i++) {
if (a > (INT_MAX >> 8) || a < (INT_MIN + (1<<8))) {
return SC_ERROR_NOT_SUPPORTED;
}
a <<= 8;
if (is_negative) {
a |= 0xff^(*inbuf++);
} else {
a |= *inbuf++;
}
}
if (is_negative) {
/* Calculate Two's complement from previously positive number */
a = (-1 * a) - 1;
}
*out = a;
return 0;
}
@ -784,7 +819,8 @@ static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize)
int
sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id)
{
int a;
int large_second_octet = 0;
unsigned int a = 0;
const u8 *p = inbuf;
int *octet;
@ -794,27 +830,64 @@ sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id)
sc_init_oid(id);
octet = id->value;
a = *p;
*octet++ = a / 40;
*octet++ = a % 40;
inlen--;
/* The first octet can be 0, 1 or 2 and is derived from the first byte */
a = MIN(*p / 40, 2);
*octet++ = a;
/* The second octet fits here if the previous was 0 or 1 and second one is smaller than 40.
* for the value 2 we can go up to 47. Otherwise the first bit needs to be set
* and we continue reading further */
if ((*p & 0x80) == 0) {
*octet++ = *p - (a * 40);
inlen--;
} else {
large_second_octet = 1;
}
while (inlen) {
p++;
if (!large_second_octet)
p++;
/* This signalizes empty most significant bits, which means
* the unsigned integer encoding is not minimal */
if (*p == 0x80) {
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
/* Use unsigned type here so we can process the whole INT range.
* Values can not be negative */
a = *p & 0x7F;
inlen--;
while (inlen && *p & 0x80) {
/* Limit the OID values to int size and do not overflow */
if (a > (UINT_MAX>>7)) {
sc_init_oid(id);
return SC_ERROR_NOT_SUPPORTED;
}
p++;
a <<= 7;
a |= *p & 0x7F;
inlen--;
}
if (*p & 0x80) {
/* We dropped out from previous cycle on the end of
* data while still expecting continuation of value */
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
if (large_second_octet) {
a -= (2 * 40);
}
if (a > INT_MAX) {
sc_init_oid(id);
return SC_ERROR_NOT_SUPPORTED;
}
*octet++ = a;
if (octet - id->value >= SC_MAX_OBJECT_ID_OCTETS) {
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
};
large_second_octet = 0;
}
return 0;
}
@ -846,10 +919,13 @@ sc_asn1_encode_object_id(u8 **buf, size_t *buflen, const struct sc_object_id *id
*p = k * 40;
break;
case 1:
if (k > 39)
if (k > 39 && id->value[0] < 2) {
return SC_ERROR_INVALID_ARGUMENTS;
*p++ += k;
break;
}
/* We can encode larger IDs to multiple bytes
* similarly as the following IDs */
k += *p;
/* fall through */
default:
shift = 28;
while (shift && (k >> shift) == 0)
@ -1029,7 +1105,9 @@ static int asn1_write_element(sc_context_t *ctx, unsigned int tag,
else {
*p++ = datalen & 0x7F;
}
memcpy(p, data, datalen);
if (datalen && data) {
memcpy(p, data, datalen);
}
return SC_SUCCESS;
}
@ -1428,7 +1506,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);
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm, 1);
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s' returned %d\n", depth, depth, "",
entry->name, *((int *) entry->parm));
}
@ -1444,10 +1522,12 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
}
if (entry->flags & SC_ASN1_ALLOC) {
u8 **buf = (u8 **) parm;
*buf = malloc(objlen-1);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
if (objlen > 1) {
*buf = malloc(objlen-1);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
}
}
*len = objlen-1;
parm = *buf;
@ -1478,10 +1558,12 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
/* Allocate buffer if needed */
if (entry->flags & SC_ASN1_ALLOC) {
u8 **buf = (u8 **) parm;
*buf = malloc(objlen);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
if (objlen > 0) {
*buf = malloc(objlen);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
}
}
c = *len = objlen;
parm = *buf;
@ -1498,10 +1580,12 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
assert(len != NULL);
if (entry->flags & SC_ASN1_ALLOC) {
u8 **buf = (u8 **) parm;
*buf = malloc(objlen);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
if (objlen > 0) {
*buf = malloc(objlen);
if (*buf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
break;
}
}
c = *len = objlen;
parm = *buf;
@ -2047,7 +2131,7 @@ sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, const unsigned char *in
struct sc_asn1_entry asn1_sig_value[C_ASN1_SIG_VALUE_SIZE];
struct sc_asn1_entry asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE];
unsigned char *r = NULL, *s = NULL;
size_t r_len, s_len, halflen = buflen/2;
size_t r_len = 0, s_len = 0, halflen = buflen/2;
int rv;
LOG_FUNC_CALLED(ctx);
@ -2070,8 +2154,10 @@ sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, const unsigned char *in
}
memset(buf, 0, buflen);
memcpy(buf + (halflen - r_len), r, r_len);
memcpy(buf + (buflen - s_len), s, s_len);
if (r_len > 0)
memcpy(buf + (halflen - r_len), r, r_len);
if (s_len > 0)
memcpy(buf + (buflen - s_len), s, s_len);
sc_log(ctx, "r(%"SC_FORMAT_LEN_SIZE_T"u): %s", halflen,
sc_dump_hex(buf, halflen));

View File

@ -100,7 +100,7 @@ int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen,
/* non-inverting version */
int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen);
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out);
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict);
int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen,
struct sc_object_id *id);
int sc_asn1_encode_object_id(u8 **buf, size_t *buflen,

View File

@ -123,7 +123,7 @@ static int atrust_acos_init(struct sc_card *card)
| SC_ALGORITHM_RSA_HASH_RIPEMD160
| SC_ALGORITHM_RSA_HASH_MD5_SHA1;
if (!strcmp(card->name, ACOS_EMV_A05))
if (card->name != NULL && !strcmp(card->name, ACOS_EMV_A05))
flags |= SC_ALGORITHM_RSA_HASH_SHA256;
_sc_card_add_rsa_alg(card, 1536, flags, 0x10001);

View File

@ -54,6 +54,7 @@
#endif
#include "iso7816.h"
#include "card-cac-common.h"
#include "pkcs15.h"
/*
* CAC hardware and APDU constants
@ -105,6 +106,8 @@
#define CAC_ACR_AMP 0x20
#define CAC_ACR_SERVICE 0x21
#define CAC_MAX_CCC_DEPTH 16
/* hardware data structures (returned in the CCC) */
/* part of the card_url */
typedef struct cac_access_profile {
@ -1090,10 +1093,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,6 +1411,7 @@ static int cac_parse_cuid(sc_card_t *card, cac_private_data_t *priv, cac_cuid_t
sc_dump_hex(&val->card_id, card_id_len),
card_id_len);
priv->cuid = *val;
free(priv->cac_id);
priv->cac_id = malloc(card_id_len);
if (priv->cac_id == NULL) {
return SC_ERROR_OUT_OF_MEMORY;
@ -1418,10 +1420,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;
@ -1518,7 +1520,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;
@ -1531,12 +1534,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)
@ -1546,7 +1553,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);
@ -1704,6 +1711,7 @@ static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t *
if (r > 0) {
#ifdef ENABLE_OPENSSL
size_t val_len = r;
free(priv->cac_id);
priv->cac_id = malloc(20);
if (priv->cac_id == NULL) {
return SC_ERROR_OUT_OF_MEMORY;
@ -1772,7 +1780,7 @@ static int cac_find_and_initialize(sc_card_t *card, int initialize)
priv = cac_new_private_data();
if (!priv)
return SC_ERROR_OUT_OF_MEMORY;
r = cac_process_CCC(card, priv);
r = cac_process_CCC(card, priv, 0);
if (r == SC_SUCCESS) {
card->type = SC_CARD_TYPE_CAC_II;
card->drv_data = priv;

View File

@ -54,6 +54,7 @@
#endif
#include "iso7816.h"
#include "card-cac-common.h"
#include "pkcs15.h"
/*
* CAC hardware and APDU constants
@ -69,7 +70,7 @@ static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_l
u8 *out_ptr;
size_t size = 0;
size_t left = 0;
size_t len, next_len;
size_t len;
sc_apdu_t apdu;
int r = SC_SUCCESS;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@ -77,9 +78,8 @@ static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_l
size = left = *out_buf ? *out_len : sizeof(buf);
out_ptr = *out_buf ? *out_buf : buf;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 );
next_len = MIN(left, 100);
for (; left > 0; left -= len, out_ptr += len) {
len = next_len;
len = MIN(left, 100);
while (left > 0) {
apdu.resp = out_ptr;
apdu.le = len;
apdu.resplen = left;
@ -98,7 +98,10 @@ static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_l
left -= len;
break;
}
next_len = MIN(left, apdu.sw2);
/* Adjust the lengths */
left -= len;
out_ptr += len;
len = MIN(left, apdu.sw2);
}
if (r < 0) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
@ -128,7 +131,7 @@ static int cac_read_binary(sc_card_t *card, unsigned int idx,
int r = 0;
u8 *val = NULL;
u8 *cert_ptr;
size_t val_len;
size_t val_len = 0;
size_t len, cert_len;
u8 cert_type;

View File

@ -161,7 +161,7 @@ static int cardos_have_2048bit_package(sc_card_t *card)
static int cardos_init(sc_card_t *card)
{
unsigned long flags, rsa_2048 = 0;
unsigned long flags = 0, rsa_2048 = 0;
size_t data_field_length;
sc_apdu_t apdu;
u8 rbuf[2];
@ -171,12 +171,15 @@ static int cardos_init(sc_card_t *card)
card->cla = 0x00;
/* Set up algorithm info. */
flags = SC_ALGORITHM_RSA_RAW
| SC_ALGORITHM_RSA_HASH_NONE
| SC_ALGORITHM_ONBOARD_KEY_GEN
;
if (card->type != SC_CARD_TYPE_CARDOS_V5_0)
flags |= SC_ALGORITHM_NEED_USAGE;
flags = 0;
if (card->type == SC_CARD_TYPE_CARDOS_V5_0) {
flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
} else {
flags |= SC_ALGORITHM_RSA_RAW
| SC_ALGORITHM_RSA_HASH_NONE
| SC_ALGORITHM_NEED_USAGE
| SC_ALGORITHM_ONBOARD_KEY_GEN;
}
if (card->type == SC_CARD_TYPE_CARDOS_M4_2) {
r = cardos_have_2048bit_package(card);
@ -378,8 +381,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;
@ -771,7 +773,7 @@ cardos_set_security_env(sc_card_t *card,
int se_num)
{
sc_apdu_t apdu;
u8 data[3];
u8 data[6];
int key_id, r;
assert(card != NULL && env != NULL);
@ -800,10 +802,22 @@ cardos_set_security_env(sc_card_t *card,
return SC_ERROR_INVALID_ARGUMENTS;
}
data[0] = 0x83;
data[1] = 0x01;
data[2] = key_id;
apdu.lc = apdu.datalen = 3;
if (card->type == SC_CARD_TYPE_CARDOS_V5_0) {
/* Private key reference */
data[0] = 0x84;
data[1] = 0x01;
data[2] = key_id;
/* Usage qualifier byte */
data[3] = 0x95;
data[4] = 0x01;
data[5] = 0x40;
apdu.lc = apdu.datalen = 6;
} else {
data[0] = 0x83;
data[1] = 0x01;
data[2] = key_id;
apdu.lc = apdu.datalen = 3;
}
apdu.data = data;
r = sc_transmit_apdu(card, &apdu);
@ -876,6 +890,7 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
sc_context_t *ctx;
int do_rsa_pure_sig = 0;
int do_rsa_sig = 0;
size_t i;
assert(card != NULL && data != NULL && out != NULL);
@ -897,23 +912,13 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
* and www.crysys.hu/infsec/M40_Manual_E_2001_10.pdf)
*/
if (card->caps & SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED){
sc_log(ctx, "Forcing RAW_HASH_STRIPPED");
do_rsa_sig = 1;
}
else if (card->caps & SC_CARD_CAP_ONLY_RAW_HASH){
sc_log(ctx, "Forcing RAW_HASH");
do_rsa_sig = 1;
}
else {
/* check the the algorithmIDs from the AlgorithmInfo */
size_t i;
for(i=0; i<algorithm_ids_in_tokeninfo_count;++i){
unsigned int id = algorithm_ids_in_tokeninfo[i];
if(id == 0x86 || id == 0x88)
do_rsa_sig = 1;
else if(id == 0x8C || id == 0x8A)
do_rsa_pure_sig = 1;
/* 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];
if (id == 0x86 || id == 0x88) {
do_rsa_sig = 1;
} else if (id == 0x8C || id == 0x8A) {
do_rsa_pure_sig = 1;
}
}
@ -955,18 +960,11 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
--stripped_datalen;
}
}
if (!(card->caps & (SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED | SC_CARD_CAP_ONLY_RAW_HASH)) || card->caps & SC_CARD_CAP_ONLY_RAW_HASH ) {
sc_log(ctx, "trying to sign raw hash value with prefix");
r = do_compute_signature(card, stripped_data, stripped_datalen, out, outlen);
if (r >= SC_SUCCESS) {
free(buf);
LOG_FUNC_RETURN(ctx, r);
}
}
if (card->caps & SC_CARD_CAP_ONLY_RAW_HASH) {
sc_log(ctx, "Failed to sign raw hash value with prefix when forcing");
sc_log(ctx, "trying to sign raw hash value with prefix");
r = do_compute_signature(card, stripped_data, stripped_datalen, out, outlen);
if (r >= SC_SUCCESS) {
free(buf);
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
LOG_FUNC_RETURN(ctx, r);
}
sc_log(ctx, "trying to sign stripped raw hash value (card is responsible for prefix)");
r = sc_pkcs1_strip_digest_info_prefix(NULL, stripped_data, stripped_datalen, stripped_data, &stripped_datalen);

View File

@ -72,12 +72,10 @@
/* ISO 7816 CLA values used by COOLKEY */
#define ISO7816_CLASS 0x00
#define GLOBAL_PLATFORM_CLASS 0x80
#define COOLKEY_CLASS 0xb0
/* ISO 71816 INS values used by COOLKEY */
#define ISO7816_INS_SELECT_FILE 0xa4
#define ISO7816_INS_GET_DATA 0xca
/* COOLKEY specific INS values (public) */
#define COOLKEY_INS_GET_LIFE_CYCLE 0xf2
@ -137,30 +135,6 @@ typedef struct coolkey_status {
u8 logged_in_identities[2];
} coolkey_status_t;
/* returned by the iso get status apdu with the global platform cplc data parameters */
typedef struct global_platform_cplc_data {
u8 tag[2];
u8 length;
u8 ic_fabricator[2];
u8 ic_type[2];
u8 os_id[2];
u8 os_date[2];
u8 os_level[2];
u8 fabrication_data[2];
u8 ic_serial_number[4];
u8 ic_batch[2];
u8 module_fabricator[2];
u8 packing_data[2];
u8 icc_manufacturer[2];
u8 ic_embedding_data[2];
u8 pre_personalizer[2];
u8 ic_pre_personalization_data[2];
u8 ic_pre_personalization_id[4];
u8 ic_personalizaer[2];
u8 ic_personalization_data[2];
u8 ic_personalization_id[4];
} global_platform_cplc_data_t;
/* format of the coolkey_cuid, either constructed from cplc data or read from the combined object */
typedef struct coolkey_cuid {
u8 ic_fabricator[2];
@ -549,6 +523,9 @@ coolkey_v0_get_attribute_data(const u8 *attr, size_t buf_len, sc_cardctl_coolkey
if (r < 0) {
return r;
}
if (len + sizeof(coolkey_v0_attribute_header_t) > buf_len) {
return SC_ERROR_CORRUPTED_DATA;
}
if ((attr_type == CKA_CLASS) || (attr_type == CKA_CERTIFICATE_TYPE)
|| (attr_type == CKA_KEY_TYPE)) {
if (len != 4) {
@ -558,7 +535,7 @@ coolkey_v0_get_attribute_data(const u8 *attr, size_t buf_len, sc_cardctl_coolkey
}
/* return the length and the data */
attr_out->attribute_length = len;
attr_out->attribute_value = attr+sizeof(coolkey_v0_attribute_header_t);
attr_out->attribute_value = attr + sizeof(coolkey_v0_attribute_header_t);
return SC_SUCCESS;
}
@ -776,7 +753,7 @@ coolkey_compare_id(const void * a, const void *b)
if (a == NULL || b == NULL)
return 1;
return ((sc_cardctl_coolkey_object_t *)a)->id
== ((sc_cardctl_coolkey_object_t *)b)->id;
!= ((sc_cardctl_coolkey_object_t *)b)->id;
}
/* For SimCList autocopy, we need to know the size of the data elements */
@ -897,7 +874,7 @@ static int coolkey_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
sc_log(card->ctx,
"sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
if (sw1 == 0x90)
if (sw1 == 0x90 && sw2 == 0x00)
return SC_SUCCESS;
if (sw1 == 0x9c) {
@ -1052,30 +1029,36 @@ coolkey_get_life_cycle(sc_card_t *card, coolkey_life_cycle_t *life_cycle)
{
coolkey_status_t status;
u8 *receive_buf;
size_t len;
int r;
size_t receive_len;
int len;
len = sizeof(*life_cycle);
receive_len = sizeof(*life_cycle);
receive_buf = (u8 *)life_cycle;
r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_LIFE_CYCLE, 0, 0,
NULL, 0, &receive_buf, &len, NULL, 0);
if (r == sizeof(*life_cycle)) {
len = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_LIFE_CYCLE, 0, 0,
NULL, 0, &receive_buf, &receive_len, NULL, 0);
if (len == sizeof(*life_cycle)) {
return SC_SUCCESS;
}
len = 1;
receive_len = 1;
receive_buf = &life_cycle->life_cycle;
r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_LIFE_CYCLE, 0, 0,
NULL, 0, &receive_buf, &len, NULL, 0);
if (r < 0) {
return r;
len = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_LIFE_CYCLE, 0, 0,
NULL, 0, &receive_buf, &receive_len, NULL, 0);
if (len < 0) { /* Error from the trasmittion */
return len;
}
len = sizeof(status);
if (len != 1) { /* The returned data is invalid */
return SC_ERROR_INTERNAL;
}
receive_len = sizeof(status);
receive_buf = (u8 *)&status;
r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_STATUS, 0, 0,
NULL, 0, &receive_buf, &len, NULL, 0);
if (r < 0) {
return r;
len = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_STATUS, 0, 0,
NULL, 0, &receive_buf, &receive_len, NULL, 0);
if (len < 0) { /* Error from the trasmittion */
return len;
}
if (len != sizeof(status)) { /* The returned data is invalid */
return SC_ERROR_INTERNAL;
}
life_cycle->protocol_version_major = status.protocol_version_major;
life_cycle->protocol_version_minor = status.protocol_version_minor;
@ -1083,17 +1066,6 @@ coolkey_get_life_cycle(sc_card_t *card, coolkey_life_cycle_t *life_cycle)
return SC_SUCCESS;
}
/* should be general global platform call */
static int
coolkey_get_cplc_data(sc_card_t *card, global_platform_cplc_data_t *cplc_data)
{
size_t len = sizeof(global_platform_cplc_data_t);
u8 *receive_buf = (u8 *)cplc_data;
return coolkey_apdu_io(card, GLOBAL_PLATFORM_CLASS, ISO7816_INS_GET_DATA, 0x9f, 0x7f,
NULL, 0, &receive_buf, &len, NULL, 0);
}
/* select the coolkey applet */
static int coolkey_select_applet(sc_card_t *card)
{
@ -1129,6 +1101,8 @@ static int coolkey_read_object(sc_card_t *card, unsigned long object_id, size_t
size_t len;
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
ulong2bebytes(&params.object_id[0], object_id);
out_ptr = out_buf;
@ -1155,7 +1129,7 @@ static int coolkey_read_object(sc_card_t *card, unsigned long object_id, size_t
return out_len;
fail:
return r;
LOG_FUNC_RETURN(card->ctx, r);
}
/*
@ -1236,7 +1210,7 @@ static int coolkey_read_binary(sc_card_t *card, unsigned int idx,
r = coolkey_read_object(card, priv->obj->id, 0, data, priv->obj->length,
priv->nonce, sizeof(priv->nonce));
priv->nonce, sizeof(priv->nonce));
if (r < 0)
goto done;
@ -1395,6 +1369,8 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj)
sc_cardctl_coolkey_object_t *obj_entry;
coolkey_private_data_t * priv = COOLKEY_DATA(card);
LOG_FUNC_CALLED(card->ctx);
if (obj->data != NULL) {
return SC_SUCCESS;
}
@ -1406,7 +1382,10 @@ 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);
return SC_ERROR_CORRUPTED_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);
if (obj_entry == NULL) {
@ -1417,9 +1396,15 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj)
free(new_obj_data);
return SC_ERROR_INTERNAL; /* shouldn't happen */
}
/* Make sure we will not go over the allocated limits in the other
* objects if they somehow got different lengths in matching objects */
if (obj_entry->length != obj->length) {
free(new_obj_data);
return SC_ERROR_INTERNAL; /* shouldn't happen */
}
obj_entry->data = new_obj_data;
obj->data = new_obj_data;
return SC_SUCCESS;
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/*
@ -1441,6 +1426,8 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
attribute->attribute_length = 0;
attribute->attribute_value = NULL;
LOG_FUNC_CALLED(card->ctx);
if (obj == NULL) {
/* cast away const so we can cache the data value */
int r = coolkey_fill_object(card, (sc_cardctl_coolkey_object_t *)attribute->object);
@ -1466,7 +1453,6 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
return SC_ERROR_CORRUPTED_DATA;
}
/*
* now loop through all the attributes in the list. first find the start of the list
*/
@ -1482,7 +1468,7 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
size_t record_len = coolkey_get_attribute_record_len(attr, object_record_type, buf_len);
/* make sure we have the complete record */
if (buf_len < record_len || record_len < 4) {
return SC_ERROR_CORRUPTED_DATA;
return SC_ERROR_CORRUPTED_DATA;
}
/* does the attribute match the one we are looking for */
if (attr_type == coolkey_get_attribute_type(attr, object_record_type, record_len)) {
@ -1499,7 +1485,7 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
return coolkey_get_attribute_data_fixed(attr_type, fixed_attributes, attribute);
}
return SC_ERROR_DATA_OBJECT_NOT_FOUND;
LOG_FUNC_RETURN(card->ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND);
}
/*
@ -1970,6 +1956,11 @@ coolkey_add_object(coolkey_private_data_t *priv, unsigned long object_id, const
new_object.id = object_id;
new_object.length = object_length;
/* The object ID needs to be unique */
if (coolkey_find_object_by_id(&priv->objects_list, object_id) != NULL) {
return SC_ERROR_INTERNAL;
}
if (object_data) {
new_object.data = malloc(object_length + add_v1_record);
if (new_object.data == NULL) {
@ -2071,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) {
@ -2095,6 +2097,7 @@ coolkey_process_combined_object(sc_card_t *card, coolkey_private_data_t *priv, u
object_offset += current_object_len;
/* record this object */
sc_log(card->ctx, "Add new object id=%ld", object_id);
r = coolkey_add_object(priv, object_id, current_object, current_object_len, 1);
if (r) {
goto done;
@ -2160,12 +2163,24 @@ static int coolkey_initialize(sc_card_t *card)
priv->life_cycle = life_cycle.life_cycle;
/* walk down the list of objects and read them off the token */
for(r=coolkey_list_object(card, COOLKEY_LIST_RESET, &object_info); r >= 0;
r= coolkey_list_object(card, COOLKEY_LIST_NEXT, &object_info)) {
unsigned long object_id = bebytes2ulong(object_info.object_id);
unsigned short object_len = bebytes2ulong(object_info.object_length);
/* also look at the ACL... */
r = coolkey_list_object(card, COOLKEY_LIST_RESET, &object_info);
while (r >= 0) {
unsigned long object_id;
unsigned long object_len;
/* The card did not return what we expected: Lets try other objects */
if ((size_t)r < (sizeof(object_info)))
break;
/* TODO also look at the ACL... */
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
@ -2180,7 +2195,7 @@ static int coolkey_initialize(sc_card_t *card)
break;
}
r = coolkey_read_object(card, COOLKEY_COMBINED_OBJECT_ID, 0, object, object_len,
priv->nonce, sizeof(priv->nonce));
priv->nonce, sizeof(priv->nonce));
if (r < 0) {
free(object);
break;
@ -2191,14 +2206,21 @@ static int coolkey_initialize(sc_card_t *card)
break;
}
combined_processed = 1;
continue;
} else {
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);
}
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);
/* Read next object: error is handled on the cycle condition and below after cycle */
r = coolkey_list_object(card, COOLKEY_LIST_NEXT, &object_info);
}
if (r != SC_ERROR_FILE_END_REACHED) {
/* This means the card does not cooperate at all: bail out */
if (r >= 0) {
r = SC_ERROR_INVALID_CARD;
}
goto cleanup;
}
/* if we didn't pull the cuid from the combined object, then grab it now */
@ -2212,26 +2234,26 @@ static int coolkey_initialize(sc_card_t *card)
goto cleanup;
}
r = coolkey_get_cplc_data(card, &cplc_data);
r = gp_get_cplc_data(card, &cplc_data);
if (r < 0) {
goto cleanup;
}
coolkey_make_cuid_from_cplc(&priv->cuid, &cplc_data);
priv->token_name = (u8 *)strdup("COOLKEY");
if (priv->token_name == NULL) {
r= SC_ERROR_OUT_OF_MEMORY;
r = SC_ERROR_OUT_OF_MEMORY;
goto cleanup;
}
priv->token_name_length = sizeof("COOLKEY")-1;
}
card->drv_data = priv;
return SC_SUCCESS;
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
cleanup:
if (priv) {
coolkey_free_private_data(priv);
}
return r;
LOG_FUNC_RETURN(card->ctx, r);
}

View File

@ -272,14 +272,6 @@ int dnie_ask_user_consent(struct sc_card * card, const char *title, const char *
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
#else
/* check that user_consent_app exists. TODO: check if executable */
res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file);
if (res != 0) {
sc_log(card->ctx, "Invalid pinentry application: %s\n",
GET_DNIE_UI_CTX(card).user_consent_app);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* just a simple bidirectional pipe+fork+exec implementation */
/* In a pipe, xx[0] is for reading, xx[1] is for writing */
if (pipe(srv_send) < 0) {
@ -304,10 +296,17 @@ int dnie_ask_user_consent(struct sc_card * card, const char *title, const char *
close(srv_send[1]);
close(srv_recv[0]);
close(srv_recv[1]);
/* call exec() with proper user_consent_app from configuration */
/* if ok should never return */
execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL);
sc_log(card->ctx, "execlp() error");
/* check that user_consent_app exists. TODO: check if executable */
res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file);
if (res != 0) {
sc_log(card->ctx, "Invalid pinentry application: %s\n",
GET_DNIE_UI_CTX(card).user_consent_app);
} else {
/* call exec() with proper user_consent_app from configuration */
/* if ok should never return */
execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL);
sc_log(card->ctx, "execlp() error");
}
abort();
default: /* parent */
/* Close the pipe ends that the child uses to read from / write to
@ -904,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.
*
@ -945,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 */
@ -961,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:
@ -1162,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)
@ -1200,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);
}
@ -1908,8 +1892,8 @@ static int dnie_read_header(struct sc_card *card)
/* check response */
if (apdu.resplen != 8)
goto header_notcompressed;
uncompressed = le2ulong(apdu.resp);
compressed = le2ulong(apdu.resp + 4);
uncompressed = lebytes2ulong(apdu.resp);
compressed = lebytes2ulong(apdu.resp + 4);
if (uncompressed < compressed)
goto header_notcompressed;
if (uncompressed > 32767)

View File

@ -352,10 +352,10 @@ static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu,
size_t cipher_data_size,mac_data_size;
int blocks;
int r=SC_SUCCESS;
u8 *sbuf=NULL;
size_t ssize=0;
u8 *sbuf=NULL;
size_t ssize=0;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
assert(card);
assert(apdu);
@ -363,11 +363,11 @@ static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu,
if((cipher||mac) && (!key||(keylen!=8 && keylen!=16)))
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
r = sc_apdu_get_octets(card->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW);
if (r == SC_SUCCESS)
sc_apdu_log(card->ctx, sbuf, ssize, 1);
if(sbuf)
free(sbuf);
r = sc_apdu_get_octets(card->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW);
if (r == SC_SUCCESS)
sc_apdu_log(card->ctx, sbuf, ssize, 1);
if(sbuf)
free(sbuf);
if(cipher)
{

View File

@ -1157,6 +1157,7 @@ epass2003_init(struct sc_card *card)
unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = { 0 };
size_t datalen = SC_MAX_APDU_BUFFER_SIZE;
epass2003_exdata *exdata = NULL;
void *old_drv_data = card->drv_data;
LOG_FUNC_CALLED(card->ctx);
@ -1171,8 +1172,11 @@ epass2003_init(struct sc_card *card)
exdata->sm = SM_SCP01;
/* decide FIPS/Non-FIPS mode */
if (SC_SUCCESS != get_data(card, 0x86, data, datalen))
if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) {
free(exdata);
card->drv_data = old_drv_data;
return SC_ERROR_INVALID_CARD;
}
if (0x01 == data[2])
exdata->smtype = KEY_TYPE_AES;
@ -1365,7 +1369,7 @@ epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_l
sc_file_t ** file_out)
{
int r;
sc_file_t *file = 0;
sc_file_t *file = NULL;
sc_path_t path;
memset(&path, 0, sizeof(path));
@ -1392,8 +1396,11 @@ epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_l
}
}
if (file_out)
if (file_out) {
*file_out = file;
} else {
sc_file_free(file);
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}

View File

@ -164,7 +164,7 @@ static int esteid_set_security_env(sc_card_t *card, const sc_security_env_t *env
LOG_FUNC_CALLED(card->ctx);
if (card == NULL || env == NULL || env->key_ref_len != 1)
if (env == NULL || env->key_ref_len != 1)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
sc_log(card->ctx, "algo: %d operation: %d keyref: %d", env->algorithm, env->operation, env->key_ref[0]);

View File

@ -32,6 +32,7 @@
#define GEMSAFEV3_ALG_REF_FREEFORM 0x02
#define GEMSAFEV3_ALG_REF_SHA1 0x12
#define GEMSAFEV3_ALG_REF_SHA256 0x42
#define MAX_RESP_BUFFER_SIZE 2048
static struct sc_card_operations gemsafe_ops;
static struct sc_card_operations *iso_ops = NULL;
@ -122,7 +123,7 @@ static int get_conf_aid(sc_card_t *card, u8 *aid, size_t *len)
static int gp_select_applet(sc_card_t *card, const u8 *aid, size_t aid_len)
{
int r;
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
u8 buf[MAX_RESP_BUFFER_SIZE];
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
@ -215,6 +216,8 @@ static int gemsafe_init(struct sc_card *card)
_sc_card_add_rsa_alg(card, 768, flags, 0);
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
_sc_card_add_rsa_alg(card, 3072, flags, 0);
_sc_card_add_rsa_alg(card, 4096, flags, 0);
/* fake algorithm to persuade register_mechanisms()
* to register these hashes */
@ -453,8 +456,8 @@ static int gemsafe_compute_signature(struct sc_card *card, const u8 * data,
{
int r, len;
struct sc_apdu apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 rbuf[MAX_RESP_BUFFER_SIZE];
u8 sbuf[MAX_RESP_BUFFER_SIZE];
sc_context_t *ctx = card->ctx;
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
@ -519,7 +522,7 @@ static int gemsafe_decipher(struct sc_card *card, const u8 * crgram,
{
int r;
struct sc_apdu apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 rbuf[MAX_RESP_BUFFER_SIZE];
sc_context_t *ctx = card->ctx;
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);

View File

@ -156,6 +156,25 @@ struct gids_private_data {
size_t buffersize;
};
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);
}
}
// LOW LEVEL API
///////////////////////////////////////////
@ -236,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;
}
@ -643,10 +664,14 @@ static int gids_init(sc_card_t * card)
data->masterfilesize = sizeof(data->masterfile);
/* supported RSA keys and how padding is done */
flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_RAW;
flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_ONBOARD_KEY_GEN;
/* fix me: add other algorithms when the gids specification will tell how to extract the algo id from the FCP */
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
_sc_card_add_rsa_alg(card, 3072, flags, 0);
_sc_card_add_rsa_alg(card, 4096, flags, 0);
return SC_SUCCESS;
}
@ -820,6 +845,49 @@ err:
return r;
}
static int
gids_decipher(struct sc_card *card,
const u8 * crgram, size_t crgram_len,
u8 * out, size_t outlen)
{
int r;
struct sc_apdu apdu;
if (card == NULL || crgram == NULL || out == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
LOG_FUNC_CALLED(card->ctx);
sc_log(card->ctx,
"Gids decipher: in-len %"SC_FORMAT_LEN_SIZE_T"u, out-len %"SC_FORMAT_LEN_SIZE_T"u",
crgram_len, outlen);
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x80 Resp: Plain value
* P2: 0x86 Cmd: Padding indicator byte followed by cryptogram
* Implementation by Microsoft indicates that Padding indicator
* must not be sent. It may only be needed if Secure Messaging
* is used. This driver does not support SM.
*/
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
apdu.resp = out;
apdu.resplen = outlen;
apdu.le = outlen;
apdu.data = crgram; /* Skip padding indication not needed unless SM */
apdu.lc = crgram_len;
apdu.datalen = crgram_len;
fixup_transceive_length(card, &apdu);
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);
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
// deauthenticate all pins
static int gids_logout(sc_card_t *card)
{
@ -2090,7 +2158,7 @@ static struct sc_card_driver *sc_get_driver(void)
gids_ops.logout = gids_logout;
gids_ops.restore_security_env = NULL;
gids_ops.set_security_env = gids_set_security_env;
gids_ops.decipher = iso_ops->decipher;
gids_ops.decipher = gids_decipher;
gids_ops.compute_signature = iso_ops->compute_signature;
gids_ops.change_reference_data = NULL; // see pin_cmd
gids_ops.reset_retry_counter = NULL; // see pin_cmd

View File

@ -749,8 +749,10 @@ gpk_compute_crycks(sc_card_t *card, sc_apdu_t *apdu,
block[len++] = apdu->p1;
block[len++] = apdu->p2;
block[len++] = apdu->lc + 3;
if ((i = apdu->datalen) + len > sizeof(block))
if (apdu->datalen + len > sizeof(block))
i = sizeof(block) - len;
else
i = apdu->datalen;
memcpy(block+len, apdu->data, i);
len += i;

View File

@ -416,8 +416,10 @@ iasecc_init_gemalto(struct sc_card *card)
card->caps |= SC_CARD_CAP_USE_FCI_AC;
sc_format_path("3F00", &path);
sc_select_file(card, &path, NULL);
/* Result ignored*/
if (SC_SUCCESS != sc_select_file(card, &path, NULL)) {
/* Result ignored*/
sc_log(card->ctx, "Warning, MF select failed");
}
rv = iasecc_parse_ef_atr(card);
sc_log(ctx, "rv %i", rv);
@ -578,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));
@ -597,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) {
@ -612,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);
@ -626,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);
}
@ -857,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;
@ -871,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);
@ -880,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);
}
@ -902,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;
@ -943,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++) {
@ -956,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) {
@ -968,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;
@ -982,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;
}
@ -990,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",
@ -1002,15 +1025,29 @@ 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) {
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);
}
@ -1058,6 +1095,12 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
sc_print_cache(card);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
err:
if (file_out) {
sc_file_free(*file_out);
*file_out = NULL;
}
return rv;
}

View File

@ -0,0 +1,804 @@
/*
* card-idprime.c: Support for Gemalto IDPrime smart cards
*
* Copyright (c) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#ifdef ENABLE_ZLIB
#include "compression.h"
#endif
#include "cardctl.h"
#include "pkcs15.h"
static const struct sc_card_operations *iso_ops = NULL;
static struct sc_card_operations idprime_ops;
static struct sc_card_driver idprime_drv = {
"Gemalto IDPrime",
"idprime",
&idprime_ops,
NULL, 0, NULL
};
/* This ATR says, there is no EF.DIR nor EF.ATR so ISO discovery mechanisms
* are not useful here */
static const struct sc_atr_table idprime_atrs[] = {
{ "3b:7f:96:00:00:80:31:80:65:b0:84:41:3d:f6:12:0f:fe:82:90:00",
"ff:ff:00:ff:ff:ff:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff",
"Gemalto IDPrime MD 8840, 3840, 3810, 840 and 830 Cards",
SC_CARD_TYPE_IDPRIME_GENERIC, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
static const sc_path_t idprime_path = {
"", 0,
0, 0, SC_PATH_TYPE_DF_NAME,
{ "\xA0\x00\x00\x00\x18\x80\x00\x00\x00\x06\x62", 11 }
};
/* data structures to store meta data about IDPrime objects */
typedef struct idprime_object {
int fd;
unsigned char key_reference;
u8 df[2];
unsigned short length;
} idprime_object_t;
/*
* IDPrime private data per card state
*/
typedef struct idprime_private_data {
u8 *cache_buf; /* cached version of the currently selected file */
size_t cache_buf_len; /* length of the cached selected file */
int cached; /* is the cached selected file valid */
size_t file_size; /* this is real file size since IDPrime is quite strict about lengths */
list_t pki_list; /* list of pki containers */
idprime_object_t *pki_current; /* current pki object _ctl function */
int tinfo_present; /* Token Info Label object is present*/
u8 tinfo_df[2]; /* DF of object with Token Info Label */
} idprime_private_data_t;
/* For SimCList autocopy, we need to know the size of the data elements */
static size_t idprime_list_meter(const void *el) {
return sizeof(idprime_object_t);
}
void idprime_free_private_data(idprime_private_data_t *priv)
{
free(priv->cache_buf);
list_destroy(&priv->pki_list);
free(priv);
return;
}
idprime_private_data_t *idprime_new_private_data(void)
{
idprime_private_data_t *priv;
priv = calloc(1, sizeof(idprime_private_data_t));
if (priv == NULL)
return NULL;
/* Initialize PKI Applets list */
if (list_init(&priv->pki_list) != 0 ||
list_attributes_copy(&priv->pki_list, idprime_list_meter, 1) != 0) {
idprime_free_private_data(priv);
return NULL;
}
return priv;
}
int idprime_add_object_to_list(list_t *list, const idprime_object_t *object)
{
if (list_append(list, object) < 0)
return SC_ERROR_INTERNAL;
return SC_SUCCESS;
}
/* This selects main IDPrime AID which is used for communication with
* the card */
static int idprime_select_idprime(sc_card_t *card)
{
return iso_ops->select_file(card, &idprime_path, NULL);
}
/* This select some index file, which is useful for enumerating other files
* on the card */
static int idprime_select_index(sc_card_t *card)
{
int r;
sc_file_t *file = NULL;
sc_path_t index_path;
/* First, we need to make sure the IDPrime AID is selected */
r = idprime_select_idprime(card);
if (r != SC_SUCCESS) {
LOG_FUNC_RETURN(card->ctx, r);
}
/* Returns FCI with expected length of data */
sc_format_path("0101", &index_path);
r = iso_ops->select_file(card, &index_path, &file);
if (r == SC_SUCCESS) {
r = file->size;
}
sc_file_free(file);
/* Ignore too large files */
if (r > MAX_FILE_SIZE) {
r = SC_ERROR_INVALID_DATA;
}
return r;
}
static int idprime_process_index(sc_card_t *card, idprime_private_data_t *priv, int length)
{
u8 *buf = NULL;
int r = SC_ERROR_OUT_OF_MEMORY;
int i, num_entries;
idprime_object_t new_object;
buf = malloc(length);
if (buf == NULL) {
goto done;
}
r = iso_ops->read_binary(card, 0, buf, length, 0);
if (r < 1) {
r = SC_ERROR_WRONG_LENGTH;
goto done;
}
/* First byte shows the number of entries, each of them 21 bytes long */
num_entries = buf[0];
if (r < num_entries*21 + 1) {
r = SC_ERROR_INVALID_DATA;
goto done;
}
new_object.fd = 0;
for (i = 0; i < num_entries; i++) {
u8 *start = &buf[i*21+1];
/* First two bytes specify the object DF */
new_object.df[0] = start[0];
new_object.df[1] = start[1];
/* Second two bytes refer to the object size */
new_object.length = bebytes2ushort(&start[2]);
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "df=%s, len=%u",
sc_dump_hex(new_object.df, sizeof(new_object.df)), new_object.length);
/* in minidriver, mscp/kxcNN or kscNN lists certificates */
if (((memcmp(&start[4], "ksc", 3) == 0) || memcmp(&start[4], "kxc", 3) == 0)
&& (memcmp(&start[12], "mscp", 5) == 0)) {
new_object.fd++;
if (card->type == SC_CARD_TYPE_IDPRIME_V2) {
/* The key reference starts from 0x11 */
new_object.key_reference = 0x10 + new_object.fd;
} else {
/* The key reference is one bigger than the value found here for some reason */
new_object.key_reference = start[8] + 1;
}
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found certificate with fd=%d, key_ref=%d",
new_object.fd, new_object.key_reference);
idprime_add_object_to_list(&priv->pki_list, &new_object);
/* This looks like non-standard extension listing pkcs11 token info label in my card */
} else if ((memcmp(&start[4], "tinfo", 6) == 0) && (memcmp(&start[12], "p11", 4) == 0)) {
memcpy(priv->tinfo_df, new_object.df, sizeof(priv->tinfo_df));
priv->tinfo_present = 1;
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found p11/tinfo object");
}
}
r = SC_SUCCESS;
done:
free(buf);
LOG_FUNC_RETURN(card->ctx, r);
}
/* CPLC has 42 bytes, but we get it with 3B header */
#define CPLC_LENGTH 45
static int idprime_init(sc_card_t *card)
{
int r;
unsigned long flags;
idprime_private_data_t *priv = NULL;
struct sc_apdu apdu;
u8 rbuf[CPLC_LENGTH];
size_t rbuflen = sizeof(rbuf);
/* We need to differentiate the OS version since they behave slightly differently */
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xCA, 0x9F, 0x7F);
apdu.resp = rbuf;
apdu.resplen = rbuflen;
apdu.le = rbuflen;
r = sc_transmit_apdu(card, &apdu);
card->type = SC_CARD_TYPE_IDPRIME_GENERIC;
if (r == SC_SUCCESS && apdu.resplen == CPLC_LENGTH) {
/* We are interested in the OS release level here */
switch (rbuf[11]) {
case 0x01:
card->type = SC_CARD_TYPE_IDPRIME_V1;
sc_log(card->ctx, "Detected IDPrime applet version 1");
break;
case 0x02:
card->type = SC_CARD_TYPE_IDPRIME_V2;
sc_log(card->ctx, "Detected IDPrime applet version 2");
break;
default:
sc_log(card->ctx, "Unknown OS version received: %d", rbuf[11]);
break;
}
} else {
sc_log(card->ctx, "Failed to get CPLC data or invalid length returned, "
"err=%d, len=%"SC_FORMAT_LEN_SIZE_T"u",
r, apdu.resplen);
}
/* Now, select and process the index file */
r = idprime_select_index(card);
if (r <= 0) {
LOG_FUNC_RETURN(card->ctx, r);
}
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Index file found");
priv = idprime_new_private_data();
if (!priv) {
return SC_ERROR_OUT_OF_MEMORY;
}
r = idprime_process_index(card, priv, r);
if (r != SC_SUCCESS) {
idprime_free_private_data(priv);
LOG_FUNC_RETURN(card->ctx, r);
}
card->drv_data = priv;
switch (card->type) {
case SC_CARD_TYPE_IDPRIME_V1:
card->name = "Gemalto IDPrime (OSv1)";
break;
case SC_CARD_TYPE_IDPRIME_V2:
card->name = "Gemalto IDPrime (OSv2)";
break;
case SC_CARD_TYPE_IDPRIME_GENERIC:
default:
card->name = "Gemalto IDPrime (generic)";
break;
}
card->cla = 0x00;
/* Set up algorithm info. */
flags = SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_RSA_PAD_PSS
| SC_ALGORITHM_RSA_PAD_OAEP
/* SHA-1 mechanisms are not allowed in the card I have */
| (SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512)
| (SC_ALGORITHM_MGF1_SHA256 | SC_ALGORITHM_MGF1_SHA384 | SC_ALGORITHM_MGF1_SHA512)
;
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
LOG_FUNC_RETURN(card->ctx, 0);
}
static int idprime_finish(sc_card_t *card)
{
idprime_private_data_t * priv = card->drv_data;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
if (priv) {
idprime_free_private_data(priv);
}
return SC_SUCCESS;
}
static int idprime_match_card(sc_card_t *card)
{
int i, r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
i = _sc_match_atr(card, idprime_atrs, &card->type);
if (i < 0)
return 0;
r = idprime_select_index(card);
return (r > 0);
}
/* initialize getting a list and return the number of elements in the list */
static int idprime_get_init_and_get_count(list_t *list, idprime_object_t **entry, int *countp)
{
if (countp == NULL || entry == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
*countp = list_size(list);
list_iterator_start(list);
*entry = list_iterator_next(list);
return SC_SUCCESS;
}
/* finalize the list iterator */
static int idprime_final_iterator(list_t *list)
{
list_iterator_stop(list);
return SC_SUCCESS;
}
/* fill in the prkey_info for the current object on the list and advance to the next object */
static int idprime_fill_prkey_info(list_t *list, idprime_object_t **entry, sc_pkcs15_prkey_info_t *prkey_info)
{
memset(prkey_info, 0, sizeof(sc_pkcs15_prkey_info_t));
if (*entry == NULL) {
return SC_ERROR_FILE_END_REACHED;
}
prkey_info->path.len = sizeof((*entry)->df);
memcpy(prkey_info->path.value, (*entry)->df, sizeof((*entry)->df));
prkey_info->path.type = SC_PATH_TYPE_FILE_ID;
/* Do not specify the length -- it will be read from the FCI */
prkey_info->path.count = -1;
/* TODO figure out the IDs as the original driver? */
prkey_info->id.value[0] = ((*entry)->fd >> 8) & 0xff;
prkey_info->id.value[1] = (*entry)->fd & 0xff;
prkey_info->id.len = 2;
prkey_info->key_reference = (*entry)->key_reference;
*entry = list_iterator_next(list);
return SC_SUCCESS;
}
#define IDPRIME_CARDID_LEN 16
static int idprime_get_serial(sc_card_t* card, sc_serial_number_t* serial)
{
sc_path_t cardid_path;
sc_file_t *file = NULL;
u8 buf[IDPRIME_CARDID_LEN];
int r;
LOG_FUNC_CALLED(card->ctx);
/* XXX this is assumed to be cardid for windows. It can be read from the index file */
sc_format_path("0201", &cardid_path);
r = iso_ops->select_file(card, &cardid_path, &file);
if (r != SC_SUCCESS || file->size != IDPRIME_CARDID_LEN) { /* The cardid is always 16 B */
sc_file_free(file);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
}
r = iso_ops->read_binary(card, 0, buf, file->size, 0);
sc_file_free(file);
if (r < 1) {
LOG_FUNC_RETURN(card->ctx, r);
} else if (r != IDPRIME_CARDID_LEN) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
}
serial->len = MIN(IDPRIME_CARDID_LEN, SC_MAX_SERIALNR);
memcpy(serial->value, buf, serial->len);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
static int idprime_get_token_name(sc_card_t* card, char** tname)
{
idprime_private_data_t * priv = card->drv_data;
sc_path_t tinfo_path = {"\x00\x00", 2, 0, 0, SC_PATH_TYPE_PATH, {"", 0}};
sc_file_t *file = NULL;
u8 buf[2];
int r;
LOG_FUNC_CALLED(card->ctx);
if (tname == NULL) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
if (!priv->tinfo_present) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
}
memcpy(tinfo_path.value, priv->tinfo_df, 2);
r = iso_ops->select_file(card, &tinfo_path, &file);
if (r != SC_SUCCESS || file->size == 0) {
sc_file_free(file);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
}
/* First two bytes lists 0x01, the second indicates length */
r = iso_ops->read_binary(card, 0, buf, 2, 0);
if (r < 2 || buf[1] > file->size) { /* make sure we do not overrun */
sc_file_free(file);
LOG_FUNC_RETURN(card->ctx, r);
}
sc_file_free(file);
*tname = malloc(buf[1]);
if (*tname == NULL) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
}
r = iso_ops->read_binary(card, 2, (unsigned char *)*tname, buf[1], 0);
if (r < 1) {
free(*tname);
LOG_FUNC_RETURN(card->ctx, r);
}
if ((*tname)[r-1] != '\0') {
(*tname)[r-1] = '\0';
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
static int idprime_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
{
idprime_private_data_t * priv = card->drv_data;
LOG_FUNC_CALLED(card->ctx);
sc_log(card->ctx, "cmd=%ld ptr=%p", cmd, ptr);
if (priv == NULL) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
switch (cmd) {
case SC_CARDCTL_GET_SERIALNR:
return idprime_get_serial(card, (sc_serial_number_t *) ptr);
case SC_CARDCTL_IDPRIME_GET_TOKEN_NAME:
return idprime_get_token_name(card, (char **) ptr);
case SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS:
return idprime_get_init_and_get_count(&priv->pki_list, &priv->pki_current,
(int *)ptr);
case SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT:
return idprime_fill_prkey_info(&priv->pki_list, &priv->pki_current,
(sc_pkcs15_prkey_info_t *)ptr);
case SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS:
return idprime_final_iterator(&priv->pki_list);
}
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
}
#define HEADER_LEN 4
static int idprime_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
{
int r, len;
idprime_private_data_t * priv = card->drv_data;
u8 data[HEADER_LEN];
size_t data_len = HEADER_LEN;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
/* forget any old cached values */
if (priv->cache_buf) {
free(priv->cache_buf);
priv->cache_buf = NULL;
}
priv->cache_buf_len = 0;
priv->cached = 0;
r = iso_ops->select_file(card, in_path, file_out);
if (r == SC_SUCCESS && file_out != NULL) {
/* Try to read first bytes of the file to fix FCI in case of
* compressed certififcate */
len = iso_ops->read_binary(card, 0, data, data_len, 0);
if (len == HEADER_LEN && data[0] == 0x01 && data[1] == 0x00) {
/* Cache the real file size for the caching read_binary() */
priv->file_size = (*file_out)->size;
/* Fix the information in the file structure to not confuse upper layers */
(*file_out)->size = (data[3]<<8) | data[2];
}
}
/* Return the exit code of the select command */
return r;
}
// used to read existing certificates
static int idprime_read_binary(sc_card_t *card, unsigned int offset,
unsigned char *buf, size_t count, unsigned long flags)
{
struct idprime_private_data *priv = card->drv_data;
int r;
int size;
sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at offset %d",
count, offset);
if (!priv->cached && offset == 0) {
// this function is called to read and uncompress the certificate
u8 buffer[SC_MAX_EXT_APDU_BUFFER_SIZE];
if (sizeof(buffer) < count) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
/* Read what was reported by FCI from select command */
r = iso_ops->read_binary(card, 0, buffer, priv->file_size, flags);
if (r < 0) {
LOG_FUNC_RETURN(card->ctx, r);
}
if (r < 4) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
}
if (buffer[0] == 1 && buffer[1] == 0) {
#ifdef ENABLE_ZLIB
size_t expectedsize = buffer[2] + buffer[3] * 0x100;
r = sc_decompress_alloc(&priv->cache_buf, &(priv->cache_buf_len),
buffer+4, priv->file_size-4, COMPRESSION_AUTO);
if (r != SC_SUCCESS) {
sc_log(card->ctx, "Zlib error: %d", r);
LOG_FUNC_RETURN(card->ctx, r);
}
if (priv->cache_buf_len != expectedsize) {
sc_log(card->ctx,
"expected size: %"SC_FORMAT_LEN_SIZE_T"u real size: %"SC_FORMAT_LEN_SIZE_T"u",
expectedsize, priv->cache_buf_len);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
}
#else
sc_log(card->ctx, "compression not supported, no zlib");
return SC_ERROR_NOT_SUPPORTED;
#endif /* ENABLE_ZLIB */
} else {
/* assuming uncompressed certificate */
priv->cache_buf = malloc(r);
if (priv->cache_buf == NULL) {
return SC_ERROR_OUT_OF_MEMORY;
}
memcpy(priv->cache_buf, buffer, r);
priv->cache_buf_len = r;
}
priv->cached = 1;
}
if (offset >= priv->cache_buf_len) {
return 0;
}
size = (int) MIN((priv->cache_buf_len - offset), count);
memcpy(buf, priv->cache_buf + offset, size);
return size;
}
static int
idprime_set_security_env(struct sc_card *card,
const struct sc_security_env *env, int se_num)
{
int r;
struct sc_security_env new_env;
if (card == NULL || env == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
/* The card requires algorithm reference here */
new_env = *env;
new_env.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
/* SHA-1 mechanisms are not allowed in the card I have available */
switch (env->operation) {
case SC_SEC_OPERATION_DECIPHER:
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_OAEP) {
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
new_env.algorithm_ref = 0x1D;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
new_env.algorithm_ref = 0x4D;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
new_env.algorithm_ref = 0x5D;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
new_env.algorithm_ref = 0x6D;
}
} else { /* RSA-PKCS without hashing */
new_env.algorithm_ref = 0x1A;
}
break;
case SC_SEC_OPERATION_SIGN:
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) {
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
new_env.algorithm_ref = 0x45;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
new_env.algorithm_ref = 0x55;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
new_env.algorithm_ref = 0x65;
}
} else { /* RSA-PKCS */
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
new_env.algorithm_ref = 0x42;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
new_env.algorithm_ref = 0x52;
} else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
new_env.algorithm_ref = 0x62;
} else { /* RSA-PKCS without hashing */
new_env.algorithm_ref = 0x02;
}
}
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
r = iso_ops->set_security_env(card,
(const struct sc_security_env *) &new_env, se_num);
LOG_FUNC_RETURN(card->ctx, r);
}
/* These are mostly ISO versions updated to IDPrime specifics */
static int
idprime_compute_signature(struct sc_card *card,
const u8 * data, size_t datalen, u8 * out, size_t outlen)
{
int r;
struct sc_apdu apdu;
u8 *p;
u8 sbuf[128]; /* For SHA-512 we need 64 + 2 bytes */
u8 rbuf[4096]; /* needs work. for 3072 keys, needs 384+2 or so */
size_t rbuflen = sizeof(rbuf);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
/* We should be signing hashes only so we should not reach this limit */
if (datalen + 2 > sizeof(sbuf)) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
p = sbuf;
*(p++) = 0x90;
*(p++) = datalen;
memcpy(p, data, datalen);
p += datalen;
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x90 Hash code
* P2: 0xA0 Input template for the computation of a hash-code (the template is hashed) */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x90, 0xA0);
apdu.resp = rbuf;
apdu.resplen = rbuflen;
apdu.le = datalen;
apdu.data = sbuf;
apdu.lc = p - sbuf;
apdu.datalen = p - sbuf;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
/* This just returns the passed data (hash code) (for verification?) */
if (apdu.resplen != datalen || memcmp(rbuf, data, datalen) != 0) {
sc_log(card->ctx, "The initial APDU did not return the same data");
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x9E Resp: Digital Signature
* P2: 0x9A Cmd: Input for Digital Signature */
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x2A, 0x9E, 0x9A);
apdu.resp = out;
apdu.resplen = outlen;
apdu.le = outlen;
if (apdu.le > sc_get_max_recv_size(card)) {
/* The lower layers will automatically do a GET RESPONSE, if possible.
* All other workarounds must be carried out by the upper layers. */
apdu.le = sc_get_max_recv_size(card);
}
apdu.data = NULL;
apdu.datalen = 0;
apdu.lc = 0;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(card->ctx, r, "Card returned error");
LOG_FUNC_RETURN(card->ctx, r);
}
/* These are mostly ISO versions updated to IDPrime specifics */
static int
idprime_decipher(struct sc_card *card,
const u8 * crgram, size_t crgram_len,
u8 * out, size_t outlen)
{
int r;
struct sc_apdu apdu;
u8 *sbuf = NULL;
if (card == NULL || crgram == NULL || out == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
LOG_FUNC_CALLED(card->ctx);
sc_log(card->ctx,
"IDPrime decipher: in-len %"SC_FORMAT_LEN_SIZE_T"u, out-len %"SC_FORMAT_LEN_SIZE_T"u",
crgram_len, outlen);
sbuf = malloc(crgram_len + 1);
if (sbuf == NULL)
return SC_ERROR_OUT_OF_MEMORY;
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x80 Resp: Plain value
* P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
apdu.resp = out;
apdu.resplen = outlen;
apdu.le = outlen;
sbuf[0] = 0x81; /* padding indicator byte, 0x81 = Proprietary */
memcpy(sbuf + 1, crgram, crgram_len);
apdu.data = sbuf;
apdu.lc = crgram_len + 1;
if (apdu.lc > sc_get_max_send_size(card)) {
/* The lower layers will automatically do chaining */
apdu.flags |= SC_APDU_FLAGS_CHAINING;
}
if (apdu.le > sc_get_max_recv_size(card)) {
/* The lower layers will automatically do a GET RESPONSE, if possible.
* All other workarounds must be carried out by the upper layers. */
apdu.le = sc_get_max_recv_size(card);
}
apdu.datalen = crgram_len + 1;
r = sc_transmit_apdu(card, &apdu);
sc_mem_clear(sbuf, crgram_len + 1);
free(sbuf);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
else
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static struct sc_card_driver * sc_get_driver(void)
{
if (iso_ops == NULL) {
iso_ops = sc_get_iso7816_driver()->ops;
}
idprime_ops = *iso_ops;
idprime_ops.match_card = idprime_match_card;
idprime_ops.init = idprime_init;
idprime_ops.finish = idprime_finish;
idprime_ops.read_binary = idprime_read_binary;
idprime_ops.select_file = idprime_select_file;
idprime_ops.card_ctl = idprime_card_ctl;
idprime_ops.set_security_env = idprime_set_security_env;
idprime_ops.compute_signature = idprime_compute_signature;
idprime_ops.decipher = idprime_decipher;
return &idprime_drv;
}
struct sc_card_driver * sc_get_idprime_driver(void)
{
return sc_get_driver();
}

View File

@ -51,9 +51,7 @@ static const struct sc_atr_table mcrd_atrs[] = {
{NULL, NULL, NULL, 0, 0, NULL}
};
static const struct sc_aid EstEID_v3_AID = { {0xF0, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}, 15 };
static const struct sc_aid EstEID_v35_AID = { {0xD2, 0x33, 0x00, 0x00, 0x00, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x33, 0x35}, 15 };
static const struct sc_aid AzeDIT_v35_AID = { {0xD0, 0x31, 0x00, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x49, 0x44}, 11 };
static struct sc_card_operations mcrd_ops;
static struct sc_card_driver mcrd_drv = {
@ -246,19 +244,13 @@ static int mcrd_init(sc_card_t * card)
struct mcrd_priv_data *priv = calloc(1, sizeof *priv);
if (!priv)
return SC_ERROR_OUT_OF_MEMORY;
priv->curpath[0] = MFID;
priv->curpathlen = 1;
card->drv_data = priv;
card->cla = 0x00;
card->caps = SC_CARD_CAP_RNG;
if (!is_esteid_card(card)) {
_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);
} else if (gp_select_aid(card, &EstEID_v3_AID) >= 0) {
/* EstEID v3.0 has 2048 bit keys */
_sc_card_add_rsa_alg(card, 2048, flags, 0);
} else if (gp_select_aid(card, &EstEID_v35_AID) >= 0) {
/* EstEID v3.5 has 2048 bit keys or EC 384 */
if (is_esteid_card(card)) {
_sc_card_add_rsa_alg(card, 2048, flags, 0);
flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
@ -267,18 +259,14 @@ static int mcrd_init(sc_card_t * card)
// sc_read_binary cannot handle recursive 61 00 calls
if (card->reader && card->reader->active_protocol == SC_PROTO_T0)
card->max_recv_size = 255;
} else if (gp_select_aid(card, &AzeDIT_v35_AID) >= 0) {
_sc_card_add_rsa_alg(card, 2048, flags, 0);
} else {
free(card->drv_data);
card->drv_data = NULL;
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_CARD);
_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);
}
priv->curpath[0] = MFID;
priv->curpathlen = 1;
sc_select_file (card, sc_get_mf_path(), NULL);
if (SC_SUCCESS != sc_select_file (card, sc_get_mf_path(), NULL))
sc_log(card->ctx, "Warning: select MF failed");
/* Not needed for the fixed EstEID profile */
if (!is_esteid_card(card))
@ -297,6 +285,7 @@ static int mcrd_finish(sc_card_t * card)
while (priv->df_infos) {
struct df_info_s *tmp = priv->df_infos->next;
clear_special_files(priv->df_infos);
free(priv->df_infos);
priv->df_infos = tmp;
}
free(priv);
@ -623,14 +612,7 @@ do_select(sc_card_t * card, u8 kind,
if (kind == MCRD_SEL_EF) p2 = 0x04;
if (kind == MCRD_SEL_DF) p2 = 0x0C;
sc_format_apdu(card, &apdu, buflen?SC_APDU_CASE_4_SHORT:SC_APDU_CASE_2_SHORT, 0xA4, kind, p2);
apdu.data = buf;
apdu.datalen = buflen;
apdu.lc = apdu.datalen;
apdu.resp = resbuf;
apdu.resplen = sizeof(resbuf);
apdu.le = 256;
sc_format_apdu_ex(&apdu, 0x00, 0xA4, kind, p2, buf, buflen, resbuf, 256);
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (!file) {
@ -682,7 +664,7 @@ do_select(sc_card_t * card, u8 kind,
required. */
static int
select_part(sc_card_t * card, u8 kind, unsigned short int fid,
sc_file_t ** file)
sc_file_t ** file)
{
u8 fbuf[2];
unsigned int len;
@ -710,8 +692,8 @@ select_part(sc_card_t * card, u8 kind, unsigned short int fid,
to figure out whether the last path item is a DF or EF. */
static int
select_down(sc_card_t * card,
unsigned short *pathptr, size_t pathlen,
int df_only, sc_file_t ** file)
unsigned short *pathptr, size_t pathlen,
int df_only, sc_file_t ** file)
{
struct mcrd_priv_data *priv = DRVDATA(card);
int r;
@ -723,7 +705,7 @@ select_down(sc_card_t * card,
for (; pathlen; pathlen--, pathptr++) {
if (priv->curpathlen == MAX_CURPATH)
LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL,
"path too long for cache");
"path too long for cache");
r = -1; /* force DF select. */
if (pathlen == 1 && !df_only) {
/* first try to select an EF and retry an DF
@ -755,7 +737,7 @@ select_down(sc_card_t * card,
static int
select_file_by_path(sc_card_t * card, unsigned short *pathptr,
size_t pathlen, sc_file_t ** file)
size_t pathlen, sc_file_t ** file)
{
struct mcrd_priv_data *priv = DRVDATA(card);
int r;
@ -785,7 +767,7 @@ select_file_by_path(sc_card_t * card, unsigned short *pathptr,
/* Absolute addressing, check cache to avoid
unnecessary selects. */
for (i = 0; (i < pathlen && i < priv->curpathlen
&& pathptr[i] == priv->curpath[i]); i++) ;
&& pathptr[i] == priv->curpath[i]); i++) ;
if (!priv->curpathlen) {
/* Need to do all selects starting at the root. */
priv->curpathlen = 0;
@ -836,6 +818,11 @@ select_file_by_path(sc_card_t * card, unsigned short *pathptr,
priv->curpathlen--;
priv->is_ef = 0;
}
/* Free the previously allocated file so we do not leak memory here */
if (file) {
sc_file_free(*file);
*file = NULL;
}
r = select_down(card, pathptr, pathlen, 0, file);
}
return r;
@ -843,7 +830,7 @@ select_file_by_path(sc_card_t * card, unsigned short *pathptr,
static int
select_file_by_fid(sc_card_t * card, unsigned short *pathptr,
size_t pathlen, sc_file_t ** file)
size_t pathlen, sc_file_t ** file)
{
struct mcrd_priv_data *priv = DRVDATA(card);
int r;
@ -954,11 +941,9 @@ mcrd_select_file(sc_card_t * card, const sc_path_t * path, sc_file_t ** file)
if (samepath != 1 || priv->is_ef == 0 || priv->is_ef == 1) {
if (path->type == SC_PATH_TYPE_PATH)
r = select_file_by_path(card, pathptr, pathlen,
file);
r = select_file_by_path(card, pathptr, pathlen, file);
else { /* SC_PATH_TYPE_FILEID */
r = select_file_by_fid(card, pathptr, pathlen,
file);
r = select_file_by_fid(card, pathptr, pathlen, file);
}
}
}
@ -1064,8 +1049,8 @@ err:
/* heavily modified by -mp */
static int mcrd_compute_signature(sc_card_t * card,
const u8 * data, size_t datalen,
u8 * out, size_t outlen)
const u8 * data, size_t datalen,
u8 * out, size_t outlen)
{
struct mcrd_priv_data *priv = DRVDATA(card);
sc_security_env_t *env = NULL;
@ -1088,16 +1073,9 @@ static int mcrd_compute_signature(sc_card_t * card,
env->algorithm, env->algorithm_flags);
if (env->key_ref[0] == 1) /* authentication key */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0, 0);
sc_format_apdu_ex(&apdu, 0x00, 0x88, 0, 0, data, datalen, out, MIN(0x80U, outlen));
else
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
apdu.lc = datalen;
apdu.data = data;
apdu.datalen = datalen;
apdu.le = MIN(0x80u, outlen);
apdu.resp = out;
apdu.resplen = outlen;
sc_format_apdu_ex(&apdu, 0x00, 0x2A, 0x9E, 0x9A, data, datalen, out, MIN(0x80U, outlen));
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
@ -1143,14 +1121,7 @@ static int mcrd_decipher(struct sc_card *card,
LOG_TEST_RET(card->ctx, r, "Error encoding TLV.");
// Create APDU
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
apdu.lc = sbuf_len;
apdu.data = sbuf;
apdu.datalen = sbuf_len;
apdu.le = MIN(0x80u, outlen);
apdu.resp = out;
apdu.resplen = outlen;
sc_format_apdu_ex(&apdu, 0x00, 0x2A, 0x80, 0x86, sbuf, sbuf_len, out, MIN(0x80U, outlen));
r = sc_transmit_apdu(card, &apdu);
sc_mem_clear(sbuf, sbuf_len);
free(sbuf);

View File

@ -93,7 +93,7 @@ static int muscle_match_card(sc_card_t *card)
apdu.resplen = 64;
apdu.resp = response;
r = sc_transmit_apdu(card, &apdu);
if (r == SC_SUCCESS && response[0] == 0x01) {
if (r == SC_SUCCESS && apdu.resplen > 1 && response[0] == 0x01) {
card->type = SC_CARD_TYPE_MUSCLE_V1;
} else {
card->type = SC_CARD_TYPE_MUSCLE_GENERIC;
@ -388,6 +388,9 @@ static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** f
fs->currentFile[0] = oid[2];
fs->currentFile[1] = oid[3];
} else {
if(pathlen < 2) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
fs->currentPath[0] = oid[pathlen - 2];
fs->currentPath[1] = oid[pathlen - 1];
fs->currentFile[0] = 0;

View File

@ -176,6 +176,7 @@ static int myeid_init(struct sc_card *card)
size_t resp_len = 0;
static struct sc_aid myeid_aid = { "\xA0\x00\x00\x00\x63\x50\x4B\x43\x53\x2D\x31\x35", 0x0C };
int rv = 0;
void *old_drv_data = card->drv_data;
LOG_FUNC_CALLED(card->ctx);
@ -200,14 +201,14 @@ static int myeid_init(struct sc_card *card)
/* Ensure that the MyEID applet is selected. */
rv = myeid_select_aid(card, &myeid_aid, NULL, &resp_len);
LOG_TEST_RET(card->ctx, rv, "Failed to select MyEID applet.");
LOG_TEST_GOTO_ERR(card->ctx, rv, "Failed to select MyEID applet.");
/* find out MyEID version */
appletInfoLen = 20;
if (0 > myeid_get_info(card, appletInfo, appletInfoLen))
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Failed to get MyEID applet information.");
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_CARD, "Failed to get MyEID applet information.");
priv->change_counter = appletInfo[19] | appletInfo[18] << 8;
@ -256,8 +257,8 @@ static int myeid_init(struct sc_card *card)
/* show supported symmetric algorithms */
flags = 0;
if (card_caps.card_supported_features & MYEID_CARD_CAP_3DES) {
if (card_caps.max_des_key_length >= 56)
_sc_card_add_symmetric_alg(card, SC_ALGORITHM_DES, 56, flags);
if (card_caps.max_des_key_length >= 64)
_sc_card_add_symmetric_alg(card, SC_ALGORITHM_DES, 64, flags);
if (card_caps.max_des_key_length >= 128)
_sc_card_add_symmetric_alg(card, SC_ALGORITHM_3DES, 128, flags);
if (card_caps.max_des_key_length >= 192)
@ -280,11 +281,21 @@ static int myeid_init(struct sc_card *card)
if (card->version.fw_major >= 45)
priv->cap_chaining = 1;
card->max_recv_size = 256;
if (card->version.fw_major >= 40)
card->max_recv_size = 256;
else
card->max_recv_size = 255;
card->max_send_size = 255;
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
rv = SC_SUCCESS;
err:
if (rv < 0) {
free(priv);
card->drv_data = old_drv_data;
}
LOG_FUNC_RETURN(card->ctx, rv);
}
static const struct sc_card_operations *iso_ops = NULL;
@ -1468,11 +1479,6 @@ static int myeid_loadkey(sc_card_t *card, unsigned mode, u8* value, int value_le
if (mode == LOAD_KEY_MODULUS && value_len == 256 && !priv->cap_chaining)
{
if ((value_len % 2) > 0 && value[0] == 0x00)
{
value_len--;
value++;
}
mode = 0x88;
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xDA, 0x01, mode);

View File

@ -31,6 +31,10 @@
#include "sm/sm-eac.h"
#include <string.h>
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#endif
static int fread_to_eof(const char *file, unsigned char **buf, size_t *buflen);
#include "../tools/fread_to_eof.c"
@ -136,7 +140,7 @@ static int npa_match_card(sc_card_t * card)
{
int r = 0;
if (0 == r && SC_SUCCESS == sc_enum_apps(card)) {
if (SC_SUCCESS == sc_enum_apps(card)) {
unsigned char esign_aid_0[] = {
0xE8, 0x28, 0xBD, 0x08, 0x0F, 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E,
}, esign_aid_1[] = {
@ -603,10 +607,6 @@ static int npa_standard_pin_cmd(struct sc_card *card,
return r;
}
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#endif
int
npa_reset_retry_counter(sc_card_t *card, enum s_type pin_id,
int ask_for_secret, const char *new, size_t new_len)
@ -617,7 +617,7 @@ npa_reset_retry_counter(sc_card_t *card, enum s_type pin_id,
if (ask_for_secret && (!new || !new_len)) {
if (!(SC_READER_CAP_PIN_PAD & card->reader->capabilities)) {
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifdef ENABLE_OPENSSL
p = malloc(EAC_MAX_PIN_LEN+1);
if (!p) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for new PIN.\n");

View File

@ -32,6 +32,7 @@
* https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.pdf
* https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.0.pdf
* https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.3.1.pdf
* https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf
*/
#if HAVE_CONFIG_H
@ -51,25 +52,31 @@
#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 },
{
"3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4",
"ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:ff:ff:00",
"Gnuk v1.0.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL
"Gnuk v1.x.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL
},
{ "3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1", NULL, "Yubikey NEO (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL },
{ "3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4", NULL, "Yubikey 4 (OpenPGP v2.1)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL },
{ "3b:fd:13:00:00:81:31:fe:15:80:73:c0:21:c0:57:59:75:62:69:4b:65:79:40", NULL, "Yubikey 5 (OpenPGP v3.4)", SC_CARD_TYPE_OPENPGP_V3, 0, NULL },
{ "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c", NULL, default_cardname_v3, SC_CARD_TYPE_OPENPGP_V3, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
static struct sc_card_operations *iso_ops;
static struct sc_card_operations pgp_ops;
static struct sc_card_driver pgp_drv = {
@ -79,83 +86,8 @@ static struct sc_card_driver pgp_drv = {
NULL, 0, NULL
};
/*
* 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.
*/
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,
};
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[] = {
static pgp_ec_curves_t 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,
@ -171,84 +103,44 @@ static struct pgp_supported_ec_curves {
{{{-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 pgp_ec_curves_t 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. */
};
/*
* 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.
*/
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 },
@ -297,9 +189,22 @@ static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */
{ 0, 0, 0, NULL, NULL },
};
static struct do_info pgp33_objects[] = { /* OpenPGP card spec 3.3 */
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 },
{ 0x00dc, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
{ 0x00de, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
{ 0x00de, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL },
/* DO FA is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
{ 0x00fa, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL },
/* DO FB is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
{ 0x00fb, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
/* DO FC is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
{ 0x00fc, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL },
/**** OpenPGP card spec 3.3 ****/
{ 0x00f9, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
/* OpenPGP card spec 3.0 - 3.2 */
/**** OpenPGP card spec 3.0 - 3.2 ****/
{ 0x00d6, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
{ 0x00d7, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
{ 0x00d8, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
@ -307,9 +212,9 @@ static struct do_info pgp33_objects[] = { /* OpenPGP card spec 3.3 */
{ 0x7f66, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, sc_put_data },
/* DO 7F74 is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
{ 0x7f74, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, sc_put_data },
/* OpenPGP card spec 2.1 & 2.2 */
/**** OpenPGP card spec 2.1 & 2.2 ****/
{ 0x00d5, SIMPLE, READ_NEVER | WRITE_PIN3, NULL, sc_put_data },
/* OpenPGP card spec 2.0 */
/**** OpenPGP card spec 2.0 ****/
{ 0x004d, CONSTRUCTED, READ_NEVER | WRITE_PIN3, NULL, sc_put_data },
{ 0x004f, SIMPLE, READ_ALWAYS | WRITE_NEVER, sc_get_data, NULL },
{ 0x005b, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data },
@ -368,30 +273,10 @@ static struct do_info pgp33_objects[] = { /* OpenPGP card spec 3.3 */
{ 0, 0, 0, NULL, NULL },
};
static struct do_info *pgp30_objects = pgp33_objects + 1;
static struct do_info *pgp21_objects = pgp33_objects + 6;
static struct do_info *pgp20_objects = pgp33_objects + 7;
#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data))
struct pgp_priv_data {
pgp_blob_t *mf;
pgp_blob_t *current; /* currently selected file */
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;
/**
@ -412,8 +297,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.
@ -482,7 +365,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);
@ -572,7 +455,8 @@ pgp_init(sc_card_t *card)
: (priv->bcd_version < OPENPGP_CARD_2_1) ? pgp20_objects
: (priv->bcd_version < OPENPGP_CARD_3_0) ? pgp21_objects
: (priv->bcd_version < OPENPGP_CARD_3_3) ? pgp30_objects
: pgp33_objects;
: (priv->bcd_version < OPENPGP_CARD_3_4) ? pgp33_objects
: pgp34_objects;
/* change file path to MF for re-use in MF */
sc_format_path("3f00", &file->path);
@ -637,10 +521,12 @@ pgp_init(sc_card_t *card)
break;
case SC_CARD_TYPE_OPENPGP_GNUK:
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
/* TODO add ECC for more recent Gnuk (1.2.x)
* these are not include in SC_CARD_TYPE_OPENPGP_GNUK, but
* are treated like SC_CARD_TYPE_OPENPGP_V2
* Gnuk supports NIST, SECG and Curve25519 from version 1.2.x on */
/* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */
for (i=0; ec_curves_gnuk[i].oid.value[0] >= 0; i++)
{
_sc_card_add_ec_alg(card, ec_curves_gnuk[i].size,
flags_ecc, ext_flags, &ec_curves_gnuk[i].oid);
}
break;
case SC_CARD_TYPE_OPENPGP_V2:
default:
@ -731,8 +617,8 @@ pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_
sc_init_oid(&oid);
/* Create copy of oid from blob */
for (j=0; j < key_info->u.ec.oid_len; j++) {
oid.value[j] = blob->data[j+1]; /* ignore first byte (algo ID) */
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) */
}
/* compare with list of supported ec_curves */
@ -813,6 +699,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)) {
@ -863,6 +752,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 */
@ -994,7 +886,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;
@ -1071,7 +963,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;
@ -1381,11 +1273,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)
@ -1642,13 +1534,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)
@ -1660,28 +1555,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)
@ -1851,7 +1779,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);
@ -2597,7 +2525,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;
@ -2622,25 +2550,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);
@ -2755,9 +2683,10 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke
LOG_FUNC_CALLED(card->ctx);
/* protect older cards against non-RSA */
/* protect incompatible cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
&& card->type < SC_CARD_TYPE_OPENPGP_V3
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
if (id > card->algorithm_count) {
@ -2802,9 +2731,10 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
LOG_FUNC_CALLED(card->ctx);
/* protect older cards against non-RSA */
/* protect incompatible cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
&& card->type < SC_CARD_TYPE_OPENPGP_V3
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* set Control Reference Template for key */
@ -2819,10 +2749,6 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
"Invalid key ID; must be 1, 2, or 3");
}
if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && key_info->u.rsa.modulus_len != 2048)
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
"Gnuk only supports generating keys up to 2048-bit");
/* set attributes for new-generated key */
r = pgp_update_new_algo_attr(card, key_info);
LOG_TEST_RET(card->ctx, r, "Cannot set attributes for new-generated key");
@ -3168,9 +3094,10 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
LOG_FUNC_CALLED(card->ctx);
/* protect older cards against non-RSA */
/* protect incompatible cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
&& card->type < SC_CARD_TYPE_OPENPGP_V3
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* Validate */

View File

@ -0,0 +1,193 @@
/*
* 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;
struct sc_object_id oid_binary;
} pgp_ec_curves_t;
#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data))
struct pgp_priv_data {
pgp_blob_t *mf;
pgp_blob_t *current; /* currently selected file */
pgp_version_t bcd_version;
pgp_do_info_t *pgp_objects;
pgp_card_state_t state; /* card state */
pgp_ext_caps_t ext_caps; /* extended capabilities */
pgp_sm_algo_t sm_algo; /* Secure Messaging algorithm */
size_t max_challenge_size;
size_t max_cert_size;
size_t max_specialDO_size;
sc_security_env_t sec_env;
};
#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F))
#endif

View File

@ -513,34 +513,17 @@ put_tag_and_len(unsigned int tag, size_t len, u8 **ptr)
* Used by GET DATA, PUT DATA, GENERAL AUTHENTICATE
* and GENERATE ASYMMETRIC KEY PAIR.
* GET DATA may call to get the first 128 bytes to get the length from the tag.
*
* A caller may provide a buffer, and length to read. If not provided,
* an internal 4096 byte buffer is used, and a copy is returned to the
* caller. that need to be freed by the caller.
*/
static int piv_general_io(sc_card_t *card, int ins, int p1, int p2,
const u8 * sendbuf, size_t sendbuflen, u8 ** recvbuf,
size_t * recvbuflen)
const u8 * sendbuf, size_t sendbuflen, u8 *recvbuf,
size_t recvbuflen)
{
int r;
sc_apdu_t apdu;
u8 rbufinitbuf[4096];
u8 *rbuf;
size_t rbuflen;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
rbuf = rbufinitbuf;
rbuflen = sizeof(rbufinitbuf);
/* if caller provided a buffer and length */
if (recvbuf && *recvbuf && recvbuflen && *recvbuflen) {
rbuf = *recvbuf;
rbuflen = *recvbuflen;
}
r = sc_lock(card);
if (r != SC_SUCCESS)
LOG_FUNC_RETURN(card->ctx, r);
@ -553,15 +536,14 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2,
apdu.datalen = sendbuflen;
apdu.data = sendbuf;
if (recvbuf) {
apdu.resp = rbuf;
apdu.le = (rbuflen > 256) ? 256 : rbuflen;
apdu.resplen = rbuflen;
if (recvbuf && recvbuflen) {
apdu.le = (recvbuflen > 256) ? 256 : recvbuflen;
apdu.resplen = recvbuflen;
} else {
apdu.resp = rbuf;
apdu.le = 0;
apdu.resplen = 0;
}
apdu.resp = recvbuf;
/* with new adpu.c and chaining, this actually reads the whole object */
r = sc_transmit_apdu(card, &apdu);
@ -578,18 +560,7 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2,
goto err;
}
if (recvbuflen) {
if (recvbuf && *recvbuf == NULL) {
*recvbuf = malloc(apdu.resplen);
if (*recvbuf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
memcpy(*recvbuf, rbuf, apdu.resplen); /* copy tag too */
}
*recvbuflen = apdu.resplen;
r = *recvbuflen;
}
r = apdu.resplen;
err:
sc_unlock(card);
@ -604,8 +575,7 @@ static int piv_generate_key(sc_card_t *card,
sc_cardctl_piv_genkey_info_t *keydata)
{
int r;
u8 *rbuf = NULL;
size_t rbuflen = 0;
u8 rbuf[4096];
u8 *p;
const u8 *tag;
u8 tagbuf[16];
@ -654,7 +624,7 @@ static int piv_generate_key(sc_card_t *card,
p+=out_len;
r = piv_general_io(card, 0x47, 0x00, keydata->key_num,
tagbuf, p - tagbuf, &rbuf, &rbuflen);
tagbuf, p - tagbuf, rbuf, sizeof rbuf);
if (r >= 0) {
const u8 *cp;
@ -664,9 +634,9 @@ static int piv_generate_key(sc_card_t *card,
/* we will whatever tag is present */
cp = rbuf;
in_len = rbuflen;
in_len = r;
r = sc_asn1_read_tag(&cp, rbuflen, &cla_out, &tag_out, &in_len);
r = sc_asn1_read_tag(&cp, in_len, &cla_out, &tag_out, &in_len);
if (cp == NULL) {
r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
}
@ -710,8 +680,6 @@ static int piv_generate_key(sc_card_t *card,
}
err:
if (rbuf)
free(rbuf);
LOG_FUNC_RETURN(card->ctx, r);
}
@ -927,27 +895,23 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len)
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 */
u8 *rbuf;
size_t rbuflen;
size_t bodylen;
unsigned int cla_out, tag_out;
const u8 *body;
sc_log(card->ctx, "get len of #%d", enumtag);
rbuf = rbufinitbuf;
rbuflen = sizeof(rbufinitbuf);
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, &rbuf, &rbuflen);
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, rbufinitbuf, sizeof rbufinitbuf);
if (r > 0) {
int r_tag;
body = rbuf;
r_tag = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen);
body = rbufinitbuf;
r_tag = sc_asn1_read_tag(&body, r, &cla_out, &tag_out, &bodylen);
if ((r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS)
|| body == NULL) {
sc_log(card->ctx, "r_tag:%d body:%p", r_tag, body);
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
}
*buf_len = (body - rbuf) + bodylen;
*buf_len = (body - rbufinitbuf) + bodylen;
} else if ( r == 0 ) {
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
@ -960,6 +924,9 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len)
"buffer for #%d *buf=0x%p len=%"SC_FORMAT_LEN_SIZE_T"u",
enumtag, *buf, *buf_len);
if (*buf == NULL && *buf_len > 0) {
if (*buf_len > MAX_FILE_SIZE) {
goto err;
}
*buf = malloc(*buf_len);
if (*buf == NULL ) {
r = SC_ERROR_OUT_OF_MEMORY;
@ -967,7 +934,7 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len)
}
}
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, buf, buf_len);
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, *buf, *buf_len);
err:
sc_unlock(card);
@ -1267,7 +1234,7 @@ piv_put_data(sc_card_t *card, int tag, const u8 *buf, size_t buf_len)
memcpy(p, buf, buf_len);
p += buf_len;
r = piv_general_io(card, 0xDB, 0x3F, 0xFF, sbuf, p - sbuf, NULL, NULL);
r = piv_general_io(card, 0xDB, 0x3F, 0xFF, sbuf, p - sbuf, NULL, 0);
if (sbuf)
free(sbuf);
@ -1581,8 +1548,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
#ifdef ENABLE_OPENSSL
int N;
int locked = 0;
u8 *rbuf = NULL;
size_t rbuflen;
u8 rbuf[4096];
u8 *nonce = NULL;
size_t nonce_len;
u8 *p;
@ -1642,7 +1608,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
*p++ = 0x00;
/* get the encrypted nonce */
r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, &rbuf, &rbuflen);
r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, rbuf, sizeof rbuf);
if (r < 0) goto err;
@ -1762,12 +1728,8 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
put_tag_and_len(0x81, witness_len, &p);
memcpy(p, nonce, witness_len);
/* Don't leak rbuf from above */
free(rbuf);
rbuf = NULL;
/* Send constructed data */
r = piv_general_io(card, 0x87, alg_id, key_ref, built,built_len, &rbuf, &rbuflen);
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 */
@ -1837,8 +1799,6 @@ err:
EVP_CIPHER_CTX_free(ctx);
if (locked)
sc_unlock(card);
if (rbuf)
free(rbuf);
if (decrypted_reponse)
free(decrypted_reponse);
if (built)
@ -1869,13 +1829,12 @@ static int piv_general_external_authenticate(sc_card_t *card,
int outlen;
int locked = 0;
u8 *p;
u8 *rbuf = NULL;
u8 rbuf[4096];
u8 *key = NULL;
u8 *cypher_text = NULL;
u8 *output_buf = NULL;
const u8 *body = NULL;
const u8 *challenge_data = NULL;
size_t rbuflen;
size_t body_len;
size_t output_len;
size_t challenge_len;
@ -1922,7 +1881,7 @@ static int piv_general_external_authenticate(sc_card_t *card,
*p++ = 0x00;
/* get a challenge */
r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, &rbuf, &rbuflen);
r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, rbuf, sizeof rbuf);
if (r < 0) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error getting Challenge\n");
goto err;
@ -2034,7 +1993,7 @@ static int piv_general_external_authenticate(sc_card_t *card,
goto err;
}
r = piv_general_io(card, 0x87, alg_id, key_ref, output_buf, output_len, NULL, NULL);
r = piv_general_io(card, 0x87, alg_id, key_ref, output_buf, output_len, NULL, 0);
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Got response challenge\n");
err:
@ -2049,9 +2008,6 @@ err:
free(key);
}
if (rbuf)
free(rbuf);
if (cypher_text)
free(cypher_text);
@ -2218,9 +2174,9 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
/* Dynamic Authentication Template (Challenge) */
u8 sbuf[] = {0x7c, 0x02, 0x81, 0x00};
u8 *rbuf = NULL;
u8 rbuf[4096];
const u8 *p;
size_t rbuf_len = 0, out_len = 0;
size_t out_len = 0;
int r;
unsigned int tag, cla;
piv_private_data_t * priv = PIV_DATA(card);
@ -2233,7 +2189,7 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
}
/* NIST 800-73-3 says use 9B, previous verisons used 00 */
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len);
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, rbuf, sizeof rbuf);
/*
* piv_get_challenge is called in a loop.
* some cards may allow 1 challenge expecting it to be part of
@ -2242,10 +2198,7 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
* Now that the card returned error, we can try one more time.
*/
if (r == SC_ERROR_INCORRECT_PARAMETERS) {
if (rbuf)
free(rbuf);
rbuf_len = 0;
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len);
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, rbuf, sizeof rbuf);
if (r == SC_ERROR_INCORRECT_PARAMETERS) {
r = SC_ERROR_NOT_SUPPORTED;
}
@ -2253,13 +2206,12 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed");
p = rbuf;
r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len);
r = sc_asn1_read_tag(&p, r, &cla, &tag, &out_len);
if (r < 0 || (cla|tag) != 0x7C) {
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Dynamic Authentication Template");
}
rbuf_len = out_len;
r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len);
r = sc_asn1_read_tag(&p, out_len, &cla, &tag, &out_len);
if (r < 0 || (cla|tag) != 0x81) {
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Challenge");
}
@ -2272,8 +2224,6 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
r = (int) out_len;
err:
free(rbuf);
LOG_FUNC_RETURN(card->ctx, r);
}
@ -2342,8 +2292,7 @@ static int piv_validate_general_authentication(sc_card_t *card,
unsigned int real_alg_id;
u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */
u8 *rbuf = NULL;
size_t rbuflen = 0;
u8 rbuf[4096];
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@ -2380,10 +2329,10 @@ static int piv_validate_general_authentication(sc_card_t *card,
/* EC alg_id was already set */
r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref,
sbuf, p - sbuf, &rbuf, &rbuflen);
sbuf, p - sbuf, rbuf, sizeof rbuf);
if (r >= 0) {
body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x7c, &bodylen);
body = sc_asn1_find_tag(card->ctx, rbuf, r, 0x7c, &bodylen);
if (body) {
tag = sc_asn1_find_tag(card->ctx, body, bodylen, 0x82, &taglen);
if (tag) {
@ -2395,9 +2344,6 @@ static int piv_validate_general_authentication(sc_card_t *card,
r = SC_ERROR_INVALID_DATA;
}
if (rbuf)
free(rbuf);
LOG_FUNC_RETURN(card->ctx, r);
}
@ -2411,7 +2357,6 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen,
int i;
size_t nLen;
u8 rbuf[128]; /* For EC conversions 384 will fit */
size_t rbuflen = sizeof(rbuf);
const u8 * body;
size_t bodylen;
const u8 * tag;
@ -2438,11 +2383,11 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen,
}
memset(out, 0, outlen);
r = piv_validate_general_authentication(card, data, datalen, rbuf, rbuflen);
r = piv_validate_general_authentication(card, data, datalen, rbuf, sizeof rbuf);
if (r < 0)
goto err;
body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x30, &bodylen);
body = sc_asn1_find_tag(card->ctx, rbuf, r, 0x30, &bodylen);
for (i = 0; i<2; i++) {
if (body) {

View File

@ -65,6 +65,7 @@ const struct sc_atr_table sc_hsm_atrs[] = {
{"3B:FE:18:00:00:81:31:FE:45:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:FA", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{"3B:8E:80:01:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:18", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{"3B:DE:18:FF:81:91:FE:1F:C3:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:1C", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{"3B:DE:96:FF:81:91:FE:1F:C3:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:92", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{"3B:80:80:01:01", NULL, NULL, SC_CARD_TYPE_SC_HSM_SOC, 0, NULL}, // SoC Sample Card
{
@ -1687,13 +1688,18 @@ static int sc_hsm_init(struct sc_card *card)
sc_file_free(file);
// APDU Buffer limits
// JCOP 2.4.1r3 1462
// JCOP 2.4.2r3 1454
// JCOP 3 1232
// Reiner SCT 1014
// JCOP 2.4.1r3 1462
// JCOP 2.4.2r3 1454
// JCOP 3 1232
// MicroSD with JCOP 3 478 / 506
// Reiner SCT 1014
card->max_send_size = 1217; // 1232 buffer size - 15 byte header and TLV because of odd ins in UPDATE BINARY
if (card->type == SC_CARD_TYPE_SC_HSM_SOC
card->max_send_size = 1232 - 17; // 1232 buffer size - 17 byte header and TLV because of odd ins in UPDATE BINARY
if (!strncmp("Secure Flash Card", card->reader->name, 17)) {
card->max_send_size = 478 - 17;
card->max_recv_size = 506 - 2;
} else if (card->type == SC_CARD_TYPE_SC_HSM_SOC
|| card->type == SC_CARD_TYPE_SC_HSM_GOID) {
card->max_recv_size = 0x0630; // SoC Proxy forces this limit
} else {

View File

@ -476,7 +476,7 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
sc_log(card->ctx, "SetCOS 4.4 PIN refs can only be 1..7\n");
return SC_ERROR_INVALID_ARGUMENTS;
}
bCommands_pin[setcos_pin_index_44(pins, sizeof(pins), (int) bNumber)] |= 1 << i;
bCommands_pin[setcos_pin_index_44(pins, sizeof(pins)/sizeof(pins[0]), (int) bNumber)] |= 1 << i;
break;
case SC_AC_TERM: /* key */
bKeyNumber = bNumber; /* There should be only 1 key */
@ -787,9 +787,9 @@ static void parse_sec_attr_44(sc_file_t *file, const u8 *buf, size_t len)
const int* p_idx;
/* Check all sub-AC definitions within the total AC */
while (len > 1) { /* minimum length = 2 */
while (len > 1 && (size_t)iOffset < len) { /* minimum length = 2 */
size_t iACLen = buf[iOffset] & 0x0F;
if (iACLen > len)
if (iACLen >= len)
break;
iMethod = SC_AC_NONE; /* default no authentication required */
@ -868,7 +868,7 @@ static void parse_sec_attr_44(sc_file_t *file, const u8 *buf, size_t len)
}
/* Encryption key present ? */
iPinCount = iACLen - 1;
iPinCount = iACLen > 0 ? iACLen - 1 : 0;
if (buf[iOffset] & 0x20) {
int iSC;

View File

@ -44,6 +44,7 @@ static const struct sc_atr_table starcos_atrs[] = {
{ "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:30:30:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
{ "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:E0:81:05:22", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
{ "3B:D0:97:FF:81:B1:FE:45:1F:07:2B", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
{ "3b:df:96:ff:81:31:fe:45:80:5b:44:45:2e:42:41:5f:53:43:33:35:32:81:05:b5", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
@ -80,8 +81,22 @@ typedef struct starcos_ex_data_st {
int sec_ops; /* the currently selected security operation,
* i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
unsigned int fix_digestInfo;
unsigned int pin_encoding;
} starcos_ex_data;
#define PIN_ENCODING_DETERMINE 0
#define PIN_ENCODING_DEFAULT SC_PIN_ENCODING_GLP
// known pin formats for StarCOS 3.x cards
#define PIN_FORMAT_F1 0x11
#define PIN_FORMAT_F2 0x12
#define PIN_FORMAT_RSA 0x1230
#define PIN_FORMAT_BCD 0x13
#define PIN_FORMAT_ASCII 0x14
#define PIN_FORMAT_PW_ASCII 0x21
// default is the Format 2 PIN Block which is GLP in OpenSC
#define PIN_FORMAT_DEFAULT PIN_FORMAT_F2
#define CHECK_NOT_SUPPORTED_V3_4(card) \
do { \
if ((card)->type == SC_CARD_TYPE_STARCOS_V3_4) { \
@ -102,6 +117,171 @@ static int starcos_match_card(sc_card_t *card)
return 1;
}
typedef struct starcos_ctrl_ref_template_st {
unsigned int transmission_format;
#if 0
// not relevant values for now
unsigned int se_reference;
unsigned int ssec_initial_value;
#endif
} starcos_ctrl_ref_template;
// tags
#define TAG_STARCOS35_PIN_REFERENCE 0x88
#define TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag 0x7B
#define TAG_STARCOS3X_CTRL_REF_TEMPLATE 0xA4
#define TAG_STARCOS3X_TRANSMISSION_FORMAT 0x89
static const char * starcos_ef_pwdd = "3F000015";
static const char * starcos_ef_keyd = "3F000013";
/**
* Parses supported securiy mechanisms record data.
* It returns SC_SUCCESS and the ctrl_ref_template structure data on success
*/
static int starcos_parse_supported_sec_mechanisms(struct sc_card *card, const unsigned char * buf, size_t buflen, starcos_ctrl_ref_template * ctrl_ref_template)
{
struct sc_context *ctx = card->ctx;
const unsigned char *supported_sec_mechanisms_tag = NULL;
size_t taglen;
LOG_FUNC_CALLED(ctx);
supported_sec_mechanisms_tag = sc_asn1_find_tag(ctx, buf, buflen, TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag, &taglen);
if (supported_sec_mechanisms_tag != NULL && taglen >= 1) {
const unsigned char *tx_fmt_tag = NULL;
const unsigned char *ctrl_ref_template_tag = NULL;
size_t supported_sec_mechanisms_taglen = taglen;
// control-reference template is either included in the supported security mechanisms tag or it can be the CRT tag itself (EF.PWDD)
ctrl_ref_template_tag = sc_asn1_find_tag(ctx, supported_sec_mechanisms_tag, taglen, TAG_STARCOS3X_CTRL_REF_TEMPLATE, &taglen);
if ( ctrl_ref_template_tag == NULL || taglen == 0 ) {
ctrl_ref_template_tag = supported_sec_mechanisms_tag;
taglen = supported_sec_mechanisms_taglen;
}
tx_fmt_tag = sc_asn1_find_tag(ctx, ctrl_ref_template_tag, taglen, TAG_STARCOS3X_TRANSMISSION_FORMAT, &taglen);
if ( tx_fmt_tag != NULL && taglen >= 1 ) {
ctrl_ref_template->transmission_format = *(tx_fmt_tag + 0);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
}
LOG_FUNC_RETURN(ctx, SC_ERROR_TEMPLATE_NOT_FOUND);
}
static int starcos_determine_pin_format34(sc_card_t *card, unsigned int * pin_format)
{
struct sc_context *ctx = card->ctx;
struct sc_path path;
struct sc_file *file;
unsigned char buf[256];
int rv;
int retval = SC_SUCCESS;
int rec_no=1;
LOG_FUNC_CALLED(ctx);
sc_format_path(starcos_ef_pwdd, &path);
rv = sc_select_file(card, &path, &file);
LOG_TEST_RET(ctx, rv, "Cannot select EF.PWDD file");
if ( (rv = sc_read_record(card, rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
starcos_ctrl_ref_template ctrl_ref_template;
memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
if ( rv == SC_SUCCESS ) {
*pin_format = ctrl_ref_template.transmission_format;
sc_log(ctx, "Determined StarCOS 3.4 PIN format: 0x%x", *pin_format);
} else {
sc_log(ctx, "Failed to parse record %d of EF.PWD, err=%d", rec_no, rv);
retval = rv;
}
} else {
sc_log(ctx, "Failed to read record %d of EF.PWDD, err=%d", rec_no, rv);
retval = rv;
}
sc_file_free(file);
LOG_FUNC_RETURN(ctx, retval);
}
static int starcos_determine_pin_format35(sc_card_t *card, unsigned int * pin_format)
{
struct sc_context *ctx = card->ctx;
struct sc_path path;
struct sc_file *file;
unsigned char buf[256];
int rv;
int retval = SC_ERROR_RECORD_NOT_FOUND;
int rec_no=1;
starcos_ctrl_ref_template ctrl_ref_template;
LOG_FUNC_CALLED(ctx);
sc_format_path(starcos_ef_keyd, &path);
rv = sc_select_file(card, &path, &file);
LOG_TEST_RET(ctx, rv, "Cannot select EF.KEYD file");
while ( (rv = sc_read_record(card, rec_no++, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
if ( buf[0] != TAG_STARCOS35_PIN_REFERENCE ) continue;
memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
if ( rv == SC_SUCCESS ) {
*pin_format = ctrl_ref_template.transmission_format;
sc_log(ctx, "Determined StarCOS 3.5 PIN format: 0x%x", *pin_format);
retval = rv;
// assuming that all PINs and PUKs have the same transmission format
break;
} else {
sc_log(ctx, "Failed to parse record %d of EF.KEYD, err=%d", rec_no-1, rv);
retval = rv;
}
}
sc_file_free(file);
LOG_FUNC_RETURN(ctx, retval);
}
/**
* Determine v3.x PIN encoding by parsing either
* EF.PWDD (for v3.4) or EF.KEYD (for v3.5)
*
* It returns an OpenSC PIN encoding, using the default value on failure
*/
static unsigned int starcos_determine_pin_encoding(sc_card_t *card)
{
unsigned int pin_format = PIN_FORMAT_DEFAULT;
unsigned int encoding = PIN_ENCODING_DETERMINE;
if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 ) {
starcos_determine_pin_format34(card, &pin_format);
} else if ( card->type == SC_CARD_TYPE_STARCOS_V3_5 ) {
starcos_determine_pin_format35(card, &pin_format);
}
switch (pin_format) {
case PIN_FORMAT_PW_ASCII:
case PIN_FORMAT_ASCII:
encoding = SC_PIN_ENCODING_ASCII;
break;
case PIN_FORMAT_BCD:
encoding = SC_PIN_ENCODING_BCD;
break;
case PIN_FORMAT_F1:
case PIN_FORMAT_F2:
encoding = SC_PIN_ENCODING_GLP;
break;
}
sc_log(card->ctx, "Determined PIN encoding: %d", encoding);
return encoding;
}
static int starcos_init(sc_card_t *card)
{
unsigned int flags;
@ -114,6 +294,7 @@ static int starcos_init(sc_card_t *card)
card->name = "STARCOS";
card->cla = 0x00;
card->drv_data = (void *)ex_data;
ex_data->pin_encoding = PIN_ENCODING_DETERMINE;
flags = SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_ONBOARD_KEY_GEN
@ -133,6 +314,7 @@ static int starcos_init(sc_card_t *card)
else
card->name = "STARCOS 3.5";
card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
card->caps |= SC_CARD_CAP_APDU_EXT;
flags |= SC_CARD_FLAG_RNG
| SC_ALGORITHM_RSA_HASH_SHA224
@ -168,6 +350,11 @@ static int starcos_init(sc_card_t *card)
}
}
if ( ex_data->pin_encoding == PIN_ENCODING_DETERMINE ) {
// about to determine PIN encoding
ex_data->pin_encoding = starcos_determine_pin_encoding(card);
}
return 0;
}
@ -698,7 +885,7 @@ static int starcos_select_file(sc_card_t *card,
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
if (card->type != SC_CARD_TYPE_STARCOS_V3_4
|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
&& card->type != SC_CARD_TYPE_STARCOS_V3_5) {
/* unify path (the first FID should be MF) */
if (path[0] != 0x3f || path[1] != 0x00)
{
@ -1854,11 +2041,12 @@ static int starcos_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int r;
LOG_FUNC_CALLED(card->ctx);
starcos_ex_data * ex_data = (starcos_ex_data*)card->drv_data;
switch (card->type) {
case SC_CARD_TYPE_STARCOS_V3_4:
case SC_CARD_TYPE_STARCOS_V3_5:
data->flags |= SC_PIN_CMD_NEED_PADDING;
data->pin1.encoding = SC_PIN_ENCODING_GLP;
data->pin1.encoding = ex_data->pin_encoding;
/* fall through */
default:
r = iso_ops->pin_cmd(card, data, tries_left);

View File

@ -86,7 +86,7 @@ static int tcos_match_card(sc_card_t *card)
static int tcos_init(sc_card_t *card)
{
unsigned long flags;
unsigned long flags;
tcos_data *data = malloc(sizeof(tcos_data));
if (!data) return SC_ERROR_OUT_OF_MEMORY;
@ -95,20 +95,20 @@ static int tcos_init(sc_card_t *card)
card->drv_data = (void *)data;
card->cla = 0x00;
flags = SC_ALGORITHM_RSA_RAW;
flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
flags |= SC_ALGORITHM_RSA_HASH_NONE;
flags = SC_ALGORITHM_RSA_RAW;
flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
flags |= SC_ALGORITHM_RSA_HASH_NONE;
_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);
_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 (card->type == SC_CARD_TYPE_TCOS_V3) {
card->caps |= SC_CARD_CAP_APDU_EXT;
_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);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
}
return 0;
@ -124,20 +124,20 @@ static int tcos_construct_fci(const sc_file_t *file,
{
u8 *p = out;
u8 buf[64];
size_t n;
size_t n;
/* FIXME: possible buffer overflow */
/* FIXME: possible buffer overflow */
*p++ = 0x6F; /* FCI */
p++;
*p++ = 0x6F; /* FCI */
p++;
/* File size */
buf[0] = (file->size >> 8) & 0xFF;
buf[1] = file->size & 0xFF;
sc_asn1_put_tag(0x81, buf, 2, p, 16, &p);
/* File descriptor */
n = 0;
/* File descriptor */
n = 0;
buf[n] = file->shareable ? 0x40 : 0;
switch (file->type) {
case SC_FILE_TYPE_WORKING_EF:
@ -149,63 +149,60 @@ static int tcos_construct_fci(const sc_file_t *file,
return SC_ERROR_NOT_SUPPORTED;
}
buf[n++] |= file->ef_structure & 7;
if ( (file->ef_structure & 7) > 1) {
/* record structured file */
buf[n++] = 0x41; /* indicate 3rd byte */
buf[n++] = file->record_length;
}
if ( (file->ef_structure & 7) > 1) {
/* record structured file */
buf[n++] = 0x41; /* indicate 3rd byte */
buf[n++] = file->record_length;
}
sc_asn1_put_tag(0x82, buf, n, p, 8, &p);
/* File identifier */
/* File identifier */
buf[0] = (file->id >> 8) & 0xFF;
buf[1] = file->id & 0xFF;
sc_asn1_put_tag(0x83, buf, 2, p, 16, &p);
/* Directory name */
if (file->type == SC_FILE_TYPE_DF) {
if (file->namelen) {
sc_asn1_put_tag(0x84, file->name, file->namelen,
/* Directory name */
if (file->type == SC_FILE_TYPE_DF) {
if (file->namelen) {
sc_asn1_put_tag(0x84, file->name, file->namelen,
p, 16, &p);
}
else {
/* TCOS needs one, so we use a faked one */
snprintf ((char *) buf, sizeof(buf)-1, "foo-%lu",
} else {
/* TCOS needs one, so we use a faked one */
snprintf ((char *) buf, sizeof(buf)-1, "foo-%lu",
(unsigned long) time (NULL));
sc_asn1_put_tag(0x84, buf, strlen ((char *) buf), p, 16, &p);
}
}
sc_asn1_put_tag(0x84, buf, strlen ((char *) buf), p, 16, &p);
}
}
/* File descriptor extension */
if (file->prop_attr_len && file->prop_attr) {
/* File descriptor extension */
if (file->prop_attr_len && file->prop_attr) {
n = file->prop_attr_len;
memcpy(buf, file->prop_attr, n);
}
else {
n = 0;
buf[n++] = 0x01; /* not invalidated, permanent */
if (file->type == SC_FILE_TYPE_WORKING_EF)
buf[n++] = 0x00; /* generic data file */
}
sc_asn1_put_tag(0x85, buf, n, p, 16, &p);
} else {
n = 0;
buf[n++] = 0x01; /* not invalidated, permanent */
if (file->type == SC_FILE_TYPE_WORKING_EF)
buf[n++] = 0x00; /* generic data file */
}
sc_asn1_put_tag(0x85, buf, n, p, 16, &p);
/* Security attributes */
/* Security attributes */
if (file->sec_attr_len && file->sec_attr) {
memcpy(buf, file->sec_attr, file->sec_attr_len);
n = file->sec_attr_len;
} else {
/* no attributes given - fall back to default one */
memcpy (buf+ 0, "\xa4\x00\x00\x00\xff\xff", 6); /* select */
memcpy (buf+ 6, "\xb0\x00\x00\x00\xff\xff", 6); /* read bin */
memcpy (buf+12, "\xd6\x00\x00\x00\xff\xff", 6); /* upd bin */
memcpy (buf+18, "\x60\x00\x00\x00\xff\xff", 6); /* admin grp*/
n = 24;
}
else {
/* no attributes given - fall back to default one */
memcpy (buf+ 0, "\xa4\x00\x00\x00\xff\xff", 6); /* select */
memcpy (buf+ 6, "\xb0\x00\x00\x00\xff\xff", 6); /* read bin */
memcpy (buf+12, "\xd6\x00\x00\x00\xff\xff", 6); /* upd bin */
memcpy (buf+18, "\x60\x00\x00\x00\xff\xff", 6); /* admin grp*/
n = 24;
}
sc_asn1_put_tag(0x86, buf, n, p, sizeof (buf), &p);
sc_asn1_put_tag(0x86, buf, n, p, sizeof (buf), &p);
/* fixup length of FCI */
out[1] = p - out - 2;
/* fixup length of FCI */
out[1] = p - out - 2;
*outlen = p - out;
return 0;
@ -222,9 +219,9 @@ static int tcos_create_file(sc_card_t *card, sc_file_t *file)
len = SC_MAX_APDU_BUFFER_SIZE;
r = tcos_construct_fci(file, sbuf, &len);
LOG_TEST_RET(card->ctx, r, "tcos_construct_fci() failed");
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
apdu.cla |= 0x80; /* this is an proprietary extension */
apdu.cla |= 0x80; /* this is an proprietary extension */
apdu.lc = len;
apdu.datalen = len;
apdu.data = sbuf;
@ -235,7 +232,7 @@ static int tcos_create_file(sc_card_t *card, sc_file_t *file)
}
static unsigned int map_operations (int commandbyte )
static unsigned int map_operations (int commandbyte)
{
unsigned int op = (unsigned int)-1;
@ -272,72 +269,70 @@ static unsigned int map_operations (int commandbyte )
static void parse_sec_attr(sc_card_t *card,
sc_file_t *file, const u8 *buf, size_t len)
{
unsigned int op;
/* list directory is not covered by ACLs - so always add an entry */
sc_file_add_acl_entry (file, SC_AC_OP_LIST_FILES,
unsigned int op;
/* list directory is not covered by ACLs - so always add an entry */
sc_file_add_acl_entry (file, SC_AC_OP_LIST_FILES,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
/* FIXME: check for what LOCK is used */
sc_file_add_acl_entry (file, SC_AC_OP_LOCK,
/* FIXME: check for what LOCK is used */
sc_file_add_acl_entry (file, SC_AC_OP_LOCK,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
for (; len >= 6; len -= 6, buf += 6) {
/* FIXME: temporary hacks */
if (!memcmp(buf, "\xa4\x00\x00\x00\xff\xff", 6)) /* select */
sc_file_add_acl_entry (file, SC_AC_OP_SELECT,
for (; len >= 6; len -= 6, buf += 6) {
/* FIXME: temporary hacks */
if (!memcmp(buf, "\xa4\x00\x00\x00\xff\xff", 6)) {/* select */
sc_file_add_acl_entry (file, SC_AC_OP_SELECT,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
else if (!memcmp(buf, "\xb0\x00\x00\x00\xff\xff", 6)) /*read*/
sc_file_add_acl_entry (file, SC_AC_OP_READ,
} else if (!memcmp(buf, "\xb0\x00\x00\x00\xff\xff", 6)) {/*read*/
sc_file_add_acl_entry (file, SC_AC_OP_READ,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
else if (!memcmp(buf, "\xd6\x00\x00\x00\xff\xff", 6)) /*upd*/
sc_file_add_acl_entry (file, SC_AC_OP_UPDATE,
} else if (!memcmp(buf, "\xd6\x00\x00\x00\xff\xff", 6)) {/*upd*/
sc_file_add_acl_entry (file, SC_AC_OP_UPDATE,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
else if (!memcmp(buf, "\x60\x00\x00\x00\xff\xff", 6)) {/*adm */
sc_file_add_acl_entry (file, SC_AC_OP_WRITE,
} else if (!memcmp(buf, "\x60\x00\x00\x00\xff\xff", 6)) {/*adm */
sc_file_add_acl_entry (file, SC_AC_OP_WRITE,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
sc_file_add_acl_entry (file, SC_AC_OP_CREATE,
sc_file_add_acl_entry (file, SC_AC_OP_CREATE,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
sc_file_add_acl_entry (file, SC_AC_OP_INVALIDATE,
sc_file_add_acl_entry (file, SC_AC_OP_INVALIDATE,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
sc_file_add_acl_entry (file, SC_AC_OP_REHABILITATE,
sc_file_add_acl_entry (file, SC_AC_OP_REHABILITATE,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
}
else {
/* the first byte tells use the command or the
command group. We have to mask bit 0
because this one distinguish between AND/OR
combination of PINs*/
op = map_operations (buf[0]);
if (op == (unsigned int)-1)
{
sc_log(card->ctx,
"Unknown security command byte %02x\n",
buf[0]);
continue;
}
if (!buf[1])
sc_file_add_acl_entry (file, op,
} else {
/* the first byte tells use the command or the
command group. We have to mask bit 0
because this one distinguish between AND/OR
combination of PINs*/
op = map_operations (buf[0]);
if (op == (unsigned int)-1) {
sc_log(card->ctx,
"Unknown security command byte %02x\n",
buf[0]);
continue;
}
if (!buf[1])
sc_file_add_acl_entry (file, op,
SC_AC_NONE,
SC_AC_KEY_REF_NONE);
else
sc_file_add_acl_entry (file, op,
else
sc_file_add_acl_entry (file, op,
SC_AC_CHV, buf[1]);
if (!buf[2] && !buf[3])
sc_file_add_acl_entry (file, op,
if (!buf[2] && !buf[3])
sc_file_add_acl_entry (file, op,
SC_AC_NONE,
SC_AC_KEY_REF_NONE);
else
sc_file_add_acl_entry (file, op,
else
sc_file_add_acl_entry (file, op,
SC_AC_TERM,
(buf[2]<<8)|buf[3]);
}
}
}
}
}
static int tcos_select_file(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file_out)
const sc_path_t *in_path,
sc_file_t **file_out)
{
sc_context_t *ctx;
sc_apdu_t apdu;
@ -351,7 +346,7 @@ static int tcos_select_file(sc_card_t *card,
pathlen = in_path->len;
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x04);
switch (in_path->type) {
case SC_PATH_TYPE_FILE_ID:
if (pathlen != 2) return SC_ERROR_INVALID_ARGUMENTS;
@ -386,8 +381,8 @@ static int tcos_select_file(sc_card_t *card,
apdu.le = 256;
} else {
apdu.resplen = 0;
apdu.le = 0;
apdu.p2 = 0x0C;
apdu.le = 0;
apdu.p2 = 0x0C;
apdu.cse = (pathlen == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
}
@ -396,8 +391,8 @@ static int tcos_select_file(sc_card_t *card,
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r || file_out == NULL) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
if (apdu.resplen < 1 || apdu.resp[0] != 0x62){
sc_log(ctx, "received invalid template %02X\n", apdu.resp[0]);
if (apdu.resplen < 1 || apdu.resp[0] != 0x62) {
sc_log(ctx, "received invalid template %02X\n", apdu.resp[0]);
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
}
@ -436,9 +431,9 @@ static int tcos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, r, "List Dir failed");
if (apdu.resplen > buflen) return SC_ERROR_BUFFER_TOO_SMALL;
sc_log(ctx,
"got %"SC_FORMAT_LEN_SIZE_T"u %s-FileIDs\n",
apdu.resplen / 2, p1 == 1 ? "DF" : "EF");
sc_log(ctx,
"got %"SC_FORMAT_LEN_SIZE_T"u %s-FileIDs\n",
apdu.resplen / 2, p1 == 1 ? "DF" : "EF");
memcpy(buf, apdu.resp, apdu.resplen);
buf += apdu.resplen;
@ -457,17 +452,17 @@ static int tcos_delete_file(sc_card_t *card, const sc_path_t *path)
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
sc_log(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
sc_log(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
sbuf[0] = path->value[0];
sbuf[1] = path->value[1];
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
apdu.cla |= 0x80;
apdu.cla |= 0x80;
apdu.lc = 2;
apdu.datalen = 2;
apdu.data = sbuf;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_check_sw(card, apdu.sw1, apdu.sw2);
@ -487,19 +482,19 @@ static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env,
tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
data=(tcos_data *)card->drv_data;
if (se_num || (env->operation!=SC_SEC_OPERATION_DECIPHER && env->operation!=SC_SEC_OPERATION_SIGN)){
if (se_num || (env->operation!=SC_SEC_OPERATION_DECIPHER && env->operation!=SC_SEC_OPERATION_SIGN)) {
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
if(!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT))
sc_log(ctx,
sc_log(ctx,
"No Key-Reference in SecEnvironment\n");
else
sc_log(ctx,
"Key-Reference %02X (len=%"SC_FORMAT_LEN_SIZE_T"u)\n",
env->key_ref[0], env->key_ref_len);
sc_log(ctx,
"Key-Reference %02X (len=%"SC_FORMAT_LEN_SIZE_T"u)\n",
env->key_ref[0], env->key_ref_len);
/* Key-Reference 0x80 ?? */
default_key= !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || (env->key_ref_len==1 && env->key_ref[0]==0x80);
sc_log(ctx,
sc_log(ctx,
"TCOS3:%d PKCS1:%d\n", tcos3,
!!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
@ -508,7 +503,6 @@ static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env,
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, tcos3 ? 0x41 : 0xC1, 0xB8);
p = sbuf;
*p++=0x80; *p++=0x01; *p++=tcos3 ? 0x0A : 0x10;
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
*p++ = (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) ? 0x83 : 0x84;
*p++ = env->key_ref_len;
@ -520,12 +514,12 @@ static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env,
r=sc_transmit_apdu(card, &apdu);
if (r) {
sc_log(ctx,
sc_log(ctx,
"%s: APDU transmit failed", sc_strerror(r));
return r;
}
if (apdu.sw1==0x6A && (apdu.sw2==0x81 || apdu.sw2==0x88)) {
sc_log(ctx,
sc_log(ctx,
"Detected Signature-Only key\n");
if (env->operation==SC_SEC_OPERATION_SIGN && default_key) return SC_SUCCESS;
}
@ -550,11 +544,12 @@ static int tcos_compute_signature(sc_card_t *card, const u8 * data, size_t datal
assert(card != NULL && data != NULL && out != NULL);
tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
if (datalen > 255) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
// We can sign (key length / 8) bytes
if (datalen > 256) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
if(((tcos_data *)card->drv_data)->next_sign){
if(datalen>48){
sc_log(card->ctx, "Data to be signed is too long (TCOS supports max. 48 bytes)\n");
if(((tcos_data *)card->drv_data)->next_sign) {
if(datalen>48) {
sc_log(card->ctx, "Data to be signed is too long (TCOS supports max. 48 bytes)\n");
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
@ -616,7 +611,7 @@ static int tcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len,
data=(tcos_data *)card->drv_data;
LOG_FUNC_CALLED(ctx);
sc_log(ctx,
sc_log(ctx,
"TCOS3:%d PKCS1:%d\n",tcos3,
!!(data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
@ -636,7 +631,7 @@ static int tcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len,
if (apdu.sw1==0x90 && apdu.sw2==0x00) {
size_t len= (apdu.resplen>outlen) ? outlen : apdu.resplen;
unsigned int offset=0;
if(tcos3 && (data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) && apdu.resp[0]==0 && apdu.resp[1]==2){
if(tcos3 && (data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) && apdu.resp[0]==0 && apdu.resp[1]==2) {
offset=2; while(offset<len && apdu.resp[offset]!=0) ++offset;
offset=(offset<len-1) ? offset+1 : 0;
}
@ -657,11 +652,11 @@ static int tcos_setperm(sc_card_t *card, int enable_nullpin)
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xEE, 0x00, 0x00);
apdu.cla |= 0x80;
apdu.cla |= 0x80;
apdu.lc = 0;
apdu.datalen = 0;
apdu.data = NULL;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_check_sw(card, apdu.sw1, apdu.sw2);
@ -722,11 +717,10 @@ struct sc_card_driver * sc_get_tcos_driver(void)
tcos_ops.select_file = tcos_select_file;
tcos_ops.list_files = tcos_list_files;
tcos_ops.delete_file = tcos_delete_file;
tcos_ops.set_security_env = tcos_set_security_env;
tcos_ops.compute_signature = tcos_compute_signature;
tcos_ops.decipher = tcos_decipher;
tcos_ops.restore_security_env = tcos_restore_security_env;
tcos_ops.card_ctl = tcos_card_ctl;
return &tcos_drv;
}

View File

@ -157,8 +157,6 @@ static void sc_card_free(sc_card_t *card)
sc_free_apps(card);
sc_free_ef_atr(card);
sc_file_free(card->ef_dir);
free(card->ops);
if (card->algorithms != NULL) {

View File

@ -303,6 +303,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 {

View File

@ -75,7 +75,6 @@ enum {
SC_CARD_TYPE_MCRD_BASE = 5000,
SC_CARD_TYPE_MCRD_GENERIC,
SC_CARD_TYPE_MCRD_ESTEID_V30,
SC_CARD_TYPE_MCRD_DTRUST,
/* setcos driver */
SC_CARD_TYPE_SETCOS_BASE = 6000,
@ -235,6 +234,7 @@ enum {
/* JPKI cards */
SC_CARD_TYPE_JPKI_BASE = 31000,
/* Coolkey cards */
SC_CARD_TYPE_COOLKEY_BASE = 32000,
SC_CARD_TYPE_COOLKEY_GENERIC,
@ -259,6 +259,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);
@ -302,6 +308,7 @@ extern sc_card_driver_t *sc_get_cac_driver(void);
extern sc_card_driver_t *sc_get_cac1_driver(void);
extern sc_card_driver_t *sc_get_npa_driver(void);
extern sc_card_driver_t *sc_get_esteid2018_driver(void);
extern sc_card_driver_t *sc_get_idprime_driver(void);
#ifdef __cplusplus
}

View File

@ -38,11 +38,12 @@ static int zerr_to_opensc(int err) {
return SC_SUCCESS;
case Z_UNKNOWN:
return SC_ERROR_UNKNOWN;
case Z_BUF_ERROR: /* XXX: something else than OOM ? */
case Z_DATA_ERROR:
case Z_BUF_ERROR:
return SC_ERROR_UNKNOWN_DATA_RECEIVED;
case Z_MEM_ERROR:
return SC_ERROR_OUT_OF_MEMORY;
case Z_VERSION_ERROR:
case Z_DATA_ERROR:
case Z_STREAM_ERROR:
/* case Z_NEED_DICT: */
default:
@ -50,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) {
@ -100,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);
@ -110,6 +127,9 @@ static int sc_decompress_gzip(u8* out, size_t* outLen, const u8* in, size_t inLe
*outLen = gz.total_out;
err = inflateEnd(&gz);
if (*outLen == 0) {
return SC_ERROR_UNKNOWN_DATA_RECEIVED;
}
return zerr_to_opensc(err);
}
@ -130,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));
@ -158,28 +184,31 @@ static int sc_decompress_zlib_alloc(u8** out, size_t* outLen, const u8* in, size
z_stream gz;
int err;
int window_size = 15;
const int startSize = inLen < 1024 ? 2048 : inLen * 2;
const int blockSize = inLen < 1024 ? 512 : inLen / 2;
int bufferSize = startSize;
if(gzip)
const size_t startSize = inLen < 1024 ? 2048 : inLen * 2;
const size_t blockSize = inLen < 1024 ? 512 : inLen / 2;
size_t bufferSize = startSize;
if (gzip)
window_size += 0x20;
memset(&gz, 0, sizeof(gz));
if (!out || !outLen)
return SC_ERROR_INVALID_ARGUMENTS;
gz.next_in = (u8*)in;
gz.avail_in = inLen;
err = inflateInit2(&gz, window_size);
if(err != Z_OK) return zerr_to_opensc(err);
if (err != Z_OK)
return zerr_to_opensc(err);
*outLen = 0;
while(1) {
while (1) {
/* Setup buffer... */
int num;
size_t num;
u8* buf = realloc(*out, bufferSize);
if(!buf) {
if(*out)
free(*out);
if (!buf) {
free(*out);
*out = NULL;
return SC_ERROR_OUT_OF_MEMORY;
}
@ -188,25 +217,27 @@ static int sc_decompress_zlib_alloc(u8** out, size_t* outLen, const u8* in, size
gz.avail_out = bufferSize - *outLen;
err = inflate(&gz, Z_FULL_FLUSH);
if(err != Z_STREAM_END && err != Z_OK) {
if(*out)
free(*out);
if (err != Z_STREAM_END && err != Z_OK) {
free(*out);
*out = NULL;
break;
}
num = bufferSize - *outLen - gz.avail_out;
if(num > 0) {
*outLen += num;
bufferSize += num + blockSize;
num = *outLen + gz.avail_out;
if (bufferSize > num) {
*outLen += bufferSize - num;
bufferSize += bufferSize - num + blockSize;
}
if(err == Z_STREAM_END) {
if (*outLen) {
buf = realloc(buf, *outLen); /* Shrink it down, if it fails, just use old data */
if(buf) {
if (err == Z_STREAM_END) {
if (*outLen > 0) {
/* Shrink it down, if it fails, just use old data */
buf = realloc(buf, *outLen);
if (buf) {
*out = buf;
}
} else {
free(*out);
*out = NULL;
err = Z_DATA_ERROR;
}
break;
}
@ -214,14 +245,21 @@ static int sc_decompress_zlib_alloc(u8** out, size_t* outLen, const u8* in, size
inflateEnd(&gz);
return zerr_to_opensc(err);
}
int sc_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method) {
if(method == COMPRESSION_AUTO) {
int sc_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method)
{
if (in == NULL || out == NULL) {
return SC_ERROR_UNKNOWN_DATA_RECEIVED;
}
if (method == COMPRESSION_AUTO) {
method = detect_method(in, inLen);
if(method == COMPRESSION_UNKNOWN) {
if (method == COMPRESSION_UNKNOWN) {
return SC_ERROR_UNKNOWN_DATA_RECEIVED;
}
}
switch(method) {
switch (method) {
case COMPRESSION_ZLIB:
return sc_decompress_zlib_alloc(out, outLen, in, inLen, 0);
case COMPRESSION_GZIP:

View File

@ -128,6 +128,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
{ "esteid2018", (void *(*)(void)) sc_get_esteid2018_driver },
{ "idprime", (void *(*)(void)) sc_get_idprime_driver },
/* Here should be placed drivers that need some APDU transactions in the
* driver's `match_card()` function. */

View File

@ -647,23 +647,22 @@ static int cwa_prepare_external_auth(sc_card_t * card,
if (bnsub)
BN_free(bnsub);
if (buf1) {
memset(buf1, 0, 128);
sc_mem_clear(buf1, 128);
free(buf1);
}
if (buf2) {
memset(buf2, 0, 128);
sc_mem_clear(buf2, 128);
free(buf2);
}
if (buf3) {
memset(buf3, 0, 128);
sc_mem_clear(buf3, 128);
free(buf3);
}
if (sha_buf) {
memset(sha_buf, 0, 74 + 32 + 8 + 1 + 7);
sc_mem_clear(sha_buf, 74 + 32 + 8 + 1 + 7);
free(sha_buf);
}
if (sha_data) {
memset(sha_data, 0, SHA_DIGEST_LENGTH);
free(sha_data);
}
@ -770,15 +769,14 @@ static int cwa_compute_session_keys(sc_card_t * card)
compute_session_keys_end:
if (kseed) {
memset(kseed, 0, 32);
sc_mem_clear(kseed, 32);
free(kseed);
}
if (data) {
memset(data, 0, 32 + 4);
sc_mem_clear(data, 32 + 4);
free(data);
}
if (sha_data) {
memset(sha_data, 0, SHA_DIGEST_LENGTH);
free(sha_data);
}
if (res != SC_SUCCESS)

View File

@ -29,8 +29,6 @@
#include "internal.h"
#include "asn1.h"
#define MAX_FILE_SIZE 65535
struct app_entry {
const u8 *aid;
size_t aid_len;
@ -120,6 +118,7 @@ parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr)
if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT && path_len > 0) {
/* application path present: ignore AID */
if (path_len > SC_MAX_PATH_SIZE) {
free(app->label);
free(app);
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Application path is too long.");
}
@ -137,6 +136,7 @@ parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr)
if (asn1_dirrecord[3].flags & SC_ASN1_PRESENT) {
app->ddo.value = malloc(ddo_len);
if (app->ddo.value == NULL) {
free(app->label);
free(app);
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate DDO value");
}
@ -162,29 +162,31 @@ int sc_enum_apps(sc_card_t *card)
int ef_structure;
size_t file_size, jj;
int r, ii, idx;
struct sc_file *ef_dir = NULL;
LOG_FUNC_CALLED(ctx);
if (card->app_count < 0)
card->app_count = 0;
sc_free_apps(card);
card->app_count = 0;
sc_format_path("3F002F00", &path);
sc_file_free(card->ef_dir);
card->ef_dir = NULL;
r = sc_select_file(card, &path, &card->ef_dir);
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 (card->ef_dir->type != SC_FILE_TYPE_WORKING_EF) {
sc_file_free(card->ef_dir);
card->ef_dir = NULL;
if (ef_dir->type != SC_FILE_TYPE_WORKING_EF) {
sc_file_free(ef_dir);
LOG_TEST_RET(ctx, SC_ERROR_INVALID_CARD, "EF(DIR) is not a working EF.");
}
ef_structure = card->ef_dir->ef_structure;
ef_structure = ef_dir->ef_structure;
file_size = ef_dir->size;
sc_file_free(ef_dir);
if (ef_structure == SC_FILE_EF_TRANSPARENT) {
u8 *buf = NULL, *p;
size_t bufsize;
file_size = card->ef_dir->size;
if (file_size == 0)
LOG_FUNC_RETURN(ctx, 0);
if (file_size > MAX_FILE_SIZE)

View File

@ -139,7 +139,7 @@ int sc_parse_ef_atr(struct sc_card *card)
{
struct sc_context *ctx = card->ctx;
struct sc_path path;
struct sc_file *file;
struct sc_file *file = NULL;
int rv;
unsigned char *buf = NULL;
size_t size;
@ -157,17 +157,19 @@ int sc_parse_ef_atr(struct sc_card *card)
}
buf = malloc(size);
if (!buf)
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Memory allocation error");
LOG_TEST_GOTO_ERR(ctx, SC_ERROR_OUT_OF_MEMORY, "Memory allocation error");
rv = sc_read_binary(card, 0, buf, size, 0);
LOG_TEST_RET(ctx, rv, "Cannot read EF(ATR) file");
LOG_TEST_GOTO_ERR(ctx, rv, "Cannot read EF(ATR) file");
rv = sc_parse_ef_atr_content(card, buf, rv);
LOG_TEST_RET(ctx, rv, "EF(ATR) parse error");
LOG_TEST_GOTO_ERR(ctx, rv, "EF(ATR) parse error");
free(buf);
rv = SC_SUCCESS;
err:
sc_file_free(file);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
free(buf);
LOG_FUNC_RETURN(ctx, rv);
}
void sc_free_ef_atr(sc_card_t *card)

View File

@ -25,6 +25,13 @@
#endif
#include "internal.h"
#include "gp.h"
/* ISO 7816 CLA values */
#define GLOBAL_PLATFORM_CLASS 0x80
/* ISO 71816 INS values */
#define ISO7816_INS_GET_DATA 0xca
/* The AID of the Card Manager defined by Open Platform 2.0.1 specification */
static const struct sc_aid gp_card_manager = {
@ -50,7 +57,6 @@ gp_select_aid(struct sc_card *card, const struct sc_aid *aid)
apdu.datalen = aid->len;
rv = sc_transmit_apdu(card, &apdu);
if (rv < 0)
return rv;
@ -82,3 +88,34 @@ gp_select_isd_rid(struct sc_card *card)
rv = gp_select_aid(card, &gp_isd_rid);
LOG_FUNC_RETURN(card->ctx, rv);
}
/* Get Card Production Life-Cycle information */
int
gp_get_cplc_data(struct sc_card *card, global_platform_cplc_data_t *cplc_data)
{
size_t len = sizeof(global_platform_cplc_data_t);
u8 *receive_buf = (u8 *)cplc_data;
struct sc_apdu apdu;
int rc;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, ISO7816_INS_GET_DATA, 0x9f, 0x7f);
apdu.cla = GLOBAL_PLATFORM_CLASS;
apdu.resp = receive_buf;
apdu.resplen = len;
apdu.le = len;
rc = sc_transmit_apdu(card, &apdu);
if (rc < 0)
LOG_FUNC_RETURN(card->ctx, rc);
rc = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (rc < 0)
LOG_FUNC_RETURN(card->ctx, rc);
/* We expect this will fill the whole structure in the argument.
* If we got something else, report error */
if ((size_t)apdu.resplen < sizeof(global_platform_cplc_data_t)) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA);
}
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
}

View File

@ -32,9 +32,48 @@
extern "C" {
#endif
#ifdef _MSC_VER
#define PACKED
#pragma pack(push,1)
#elif defined(__GNUC__)
#define PACKED __attribute__ ((__packed__))
#endif
/* returned by the iso get status apdu with the global platform cplc data parameters */
typedef struct global_platform_cplc_data {
u8 tag[2];
u8 length;
u8 ic_fabricator[2];
u8 ic_type[2];
u8 os_id[2];
u8 os_date[2];
u8 os_level[2];
u8 fabrication_data[2];
u8 ic_serial_number[4];
u8 ic_batch[2];
u8 module_fabricator[2];
u8 packing_data[2];
u8 icc_manufacturer[2];
u8 ic_embedding_data[2];
u8 pre_personalizer[2];
u8 ic_pre_personalization_data[2];
u8 ic_pre_personalization_id[4];
u8 ic_personalizaer[2];
u8 ic_personalization_data[2];
u8 ic_personalization_id[4];
} PACKED global_platform_cplc_data_t;
int gp_select_aid(struct sc_card *card, const struct sc_aid *aid);
int gp_select_card_manager(struct sc_card *card);
int gp_select_isd_rid(struct sc_card *card);
int gp_get_cplc_data(struct sc_card *card, global_platform_cplc_data_t *cplc_data);
#ifdef _MSC_VER
#undef PACKED
#pragma pack(pop)
#elif defined(__GNUC__)
#undef PACKED
#endif
#ifdef __cplusplus
}

View File

@ -117,6 +117,12 @@ unsigned short bebytes2ushort(const u8 *buf);
* @return the converted value
*/
unsigned short lebytes2ushort(const u8 *buf);
/**
* Convert 4 bytes in little endian order into an unsigned long
* @param buf the byte array of 4 bytes
* @return the converted value
*/
unsigned long lebytes2ulong(const u8 *buf);
#define BYTES4BITS(num) (((num) + 7) / 8) /* number of bytes necessary to hold 'num' bits */

View File

@ -358,7 +358,7 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file,
/* fall through */
case 0x80:
/* determine the file size */
if (sc_asn1_decode_integer(p, length, &size) == 0 && size >= 0) {
if (sc_asn1_decode_integer(p, length, &size, 0) == 0 && size >= 0) {
file->size = size;
sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u",
file->size);
@ -387,13 +387,36 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file,
file->type = SC_FILE_TYPE_DF;
break;
default:
file->type = SC_FILE_TYPE_UNKNOWN;
type = "unknown";
break;
}
sc_log(ctx, " type: %s", type);
sc_log(ctx, " EF structure: %d", byte & 0x07);
sc_log(ctx, " tag 0x82: 0x%02x", byte);
if (SC_SUCCESS != sc_file_set_type_attr(file, &byte, 1))
/* if possible, get additional information for non-DFs */
if (file->type != SC_FILE_TYPE_DF) {
/* record length for fixed size records */
if (length > 2 && byte & 0x02) {
file->record_length = (length > 3)
? bebytes2ushort(p+2)
: p[2];
sc_log(ctx, " record length: %"SC_FORMAT_LEN_SIZE_T"u",
file->record_length);
}
/* number of records */
if (length > 4) {
file->record_count = (length > 5)
? bebytes2ushort(p+4)
: p[4];
sc_log(ctx, " records: %"SC_FORMAT_LEN_SIZE_T"u",
file->record_count);
}
}
if (SC_SUCCESS != sc_file_set_type_attr(file, p, length))
sc_log(ctx, "Warning: Could not set file attributes");
}
break;

View File

@ -37,6 +37,7 @@ enum {
SC_LOG_DEBUG_SM, /* secure messaging */
SC_LOG_DEBUG_ASN1, /* asn1.c */
SC_LOG_DEBUG_MATCH, /* card matching */
SC_LOG_DEBUG_PIN, /* PIN commands */
};
#define SC_COLOR_FG_RED 0x0001

View File

@ -147,8 +147,8 @@ int mscfs_lookup_path(mscfs_t* fs, const u8 *path, int pathlen, msc_id* objectId
return MSCFS_INVALID_ARGS;
if(isDirectory) {
/* Directory must be right next to root */
if((0 == memcmp(path, "\x3F\x00", 2) && pathlen == 4)
|| (0 == memcmp(fs->currentPath, "\x3F\x00", 2) && pathlen == 2)) {
if ((pathlen == 4 && 0 == memcmp(path, "\x3F\x00", 2)) ||
(pathlen == 2 && 0 == memcmp(fs->currentPath, "\x3F\x00", 2))) {
oid[0] = path[pathlen - 2];
oid[1] = path[pathlen - 1];
oid[2] = oid[3] = 0;
@ -169,7 +169,7 @@ int mscfs_lookup_path(mscfs_t* fs, const u8 *path, int pathlen, msc_id* objectId
if(pathlen > 4)
return MSCFS_INVALID_ARGS;
/* Reset to root */
if(0 == memcmp(path, "\x3F\x00", 2) && pathlen == 2) {
if(pathlen == 2 && 0 == memcmp(path, "\x3F\x00", 2)) {
oid[0] = oid[2] = path[0];
oid[1] = oid[3] = path[1];
} else if(pathlen == 2) { /* Path preserved for current-path */
@ -207,10 +207,13 @@ int mscfs_check_selection(mscfs_t *fs, int requiredItem)
int mscfs_loadFileInfo(mscfs_t* fs, const u8 *path, int pathlen, mscfs_file_t **file_data, int* idx)
{
msc_id fullPath;
int x;
msc_id fullPath = {{0, 0, 0, 0}};
int x, rc;
assert(fs != NULL && path != NULL && file_data != NULL);
mscfs_lookup_path(fs, path, pathlen, &fullPath, 0);
rc = mscfs_lookup_path(fs, path, pathlen, &fullPath, 0);
if (rc != SC_SUCCESS) {
return rc;
}
/* Obtain file information while checking if it exists */
mscfs_check_cache(fs);

View File

@ -107,12 +107,13 @@ extern "C" {
* must support at least one of them, and exactly one of them must be selected
* for a given operation. */
#define SC_ALGORITHM_RSA_RAW 0x00000001
#define SC_ALGORITHM_RSA_PADS 0x0000001F
#define SC_ALGORITHM_RSA_PADS 0x0000003F
#define SC_ALGORITHM_RSA_PAD_NONE 0x00000001
#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 /* PKCS#1 v1.5 padding */
#define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004
#define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008
#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* PKCS#1 v2.0 PSS */
#define SC_ALGORITHM_RSA_PAD_OAEP 0x00000020 /* PKCS#1 v2.0 OAEP */
/* If the card is willing to produce a cryptogram with the following
* hash values, set these flags accordingly. The interpretation of the hash
@ -217,6 +218,8 @@ extern "C" {
#define SC_EVENT_READER_DETACHED 0x0008
#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;
@ -542,10 +545,6 @@ struct sc_reader_operations {
* instead of relying on the ACL info in the profile files. */
#define SC_CARD_CAP_USE_FCI_AC 0x00000010
/* D-TRUST CardOS cards special flags */
#define SC_CARD_CAP_ONLY_RAW_HASH 0x00000040
#define SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED 0x00000080
/* Card (or card driver) supports an protected authentication mechanism */
#define SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH 0x00000100
@ -578,7 +577,6 @@ typedef struct sc_card {
struct sc_app_info *app[SC_MAX_CARD_APPS];
int app_count;
struct sc_file *ef_dir;
struct sc_ef_atr *ef_atr;

View File

@ -499,6 +499,7 @@ int sc_get_encoding_flags(sc_context_t *ctx,
/* Use the card's raw RSA capability on the padded input */
*sflags = SC_ALGORITHM_RSA_PAD_NONE;
*pflags = iflags;
/* TODO emulate the OAEP decryption */
} else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
(iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) {

View File

@ -252,7 +252,13 @@ static int sc_pkcs15emu_actalis_init(sc_pkcs15_card_t * p15card)
j++;
cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
if (r < 0) {
sc_log(card->ctx, "Failed to add cert obj r=%d", r);
free(cert);
free(compCert);
continue;
}
free(cert);
free(compCert);

View File

@ -253,8 +253,7 @@ static int sc_pkcs15emu_atrust_acos_init(sc_pkcs15_card_t *p15card)
if (r != SC_SUCCESS || !file)
return SC_ERROR_INTERNAL;
/* set the application DF */
if (p15card->file_app)
free(p15card->file_app);
sc_file_free(p15card->file_app);
p15card->file_app = file;
return SC_SUCCESS;

View File

@ -84,89 +84,6 @@ static const char * cac_get_name(int type)
return ("CAC");
}
/*
* These could move to a helper file for other cards that wish to use usage as a way of getting flags
*/
/* Only certain usages are valid for a given algorithm, return all the usages that the algorithm supports so we
* can use it as a filter for all the public and private key usages */
static unsigned int
cac_alg_flags_from_algorithm(int algorithm)
{
switch (algorithm) {
case SC_ALGORITHM_RSA:
return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP |
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
case SC_ALGORITHM_DSA:
return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
#ifdef SC_ALGORITHM_DH
case SC_ALGORITHM_DH:
return SC_PKCS15_PRKEY_USAGE_DERIVE ;
#endif
case SC_ALGORITHM_EC:
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
case SC_ALGORITHM_GOSTR3410:
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
return 0;
}
/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */
#define CAC_X509_USAGE_SIGNATURE \
(SC_X509_DIGITAL_SIGNATURE | \
SC_X509_NON_REPUDIATION | \
SC_X509_KEY_CERT_SIGN | \
SC_X509_CRL_SIGN)
#define CAC_X509_USAGE_DERIVE \
SC_X509_KEY_AGREEMENT
#define CAC_X509_USAGE_UNWRAP \
(SC_X509_KEY_ENCIPHERMENT | \
SC_X509_KEY_AGREEMENT)
#define CAC_X509_USAGE_DECRYPT \
(SC_X509_DATA_ENCIPHERMENT | \
SC_X509_ENCIPHER_ONLY)
#define CAC_X509_USAGE_NONREPUDIATION \
SC_X509_NON_REPUDIATION
/* map a cert usage and algorithm to public and private key usages */
static int
cac_map_usage(unsigned int cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation)
{
unsigned int pub_usage = 0, pr_usage = 0;
unsigned int alg_flags = cac_alg_flags_from_algorithm(algorithm);
if (cert_usage & CAC_X509_USAGE_SIGNATURE) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
}
if (cert_usage & CAC_X509_USAGE_DERIVE) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
}
if (cert_usage & (CAC_X509_USAGE_DECRYPT|CAC_X509_USAGE_UNWRAP)) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
}
if (allow_nonrepudiation && (cert_usage & CAC_X509_USAGE_NONREPUDIATION)) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
/* filter usages algorithm */
if (pub_usage_ptr) {
*pub_usage_ptr = pub_usage & alg_flags;
}
if (pr_usage_ptr) {
*pr_usage_ptr = pr_usage & alg_flags;
}
return SC_SUCCESS;
}
static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
{
static const pindata pins[] = {
@ -407,9 +324,9 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
if (r < 0) {
usage = 0xd9ULL; /* basic default usage */
usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */
}
cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
sc_dump_hex(cert_info.id.value, cert_info.id.len),
usage, pubkey_info.usage, prkey_info.usage);

View File

@ -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");
@ -479,7 +483,11 @@ sc_pkcs15_decode_cdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_obje
return r;
LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->file_app) {
free(der->value);
return SC_ERROR_INTERNAL;
}
r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path);
LOG_TEST_RET(ctx, r, "Cannot make absolute path");
}
@ -495,6 +503,7 @@ sc_pkcs15_decode_cdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_obje
break;
case SC_PKCS15_CARD_OPTS_PRIV_CERT_IGNORE:
sc_log(ctx, "Ignoring certificate");
free(der->value);
return 0;
}
@ -545,6 +554,88 @@ sc_pkcs15_encode_cdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj
return r;
}
/* Only certain usages are valid for a given algorithm, return all the usages
* that the algorithm supports so we can use it as a filter for all
* the public and private key usages
*/
static unsigned int
sc_pkcs15_alg_flags_from_algorithm(int algorithm)
{
switch (algorithm) {
case SC_ALGORITHM_RSA:
return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP |
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
case SC_ALGORITHM_DSA:
return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
#ifdef SC_ALGORITHM_DH
case SC_ALGORITHM_DH:
return SC_PKCS15_PRKEY_USAGE_DERIVE ;
#endif
case SC_ALGORITHM_EC:
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
case SC_ALGORITHM_GOSTR3410:
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
return 0;
}
/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */
#define SC_PKCS15_X509_USAGE_SIGNATURE \
(SC_X509_DIGITAL_SIGNATURE | \
SC_X509_NON_REPUDIATION | \
SC_X509_KEY_CERT_SIGN | \
SC_X509_CRL_SIGN)
#define SC_PKCS15_X509_USAGE_DERIVE \
SC_X509_KEY_AGREEMENT
#define SC_PKCS15_X509_USAGE_UNWRAP \
(SC_X509_KEY_ENCIPHERMENT | \
SC_X509_KEY_AGREEMENT)
#define SC_PKCS15_X509_USAGE_DECRYPT \
(SC_X509_DATA_ENCIPHERMENT | \
SC_X509_ENCIPHER_ONLY)
#define SC_PKCS15_X509_USAGE_NONREPUDIATION \
SC_X509_NON_REPUDIATION
/* map a cert usage and algorithm to public and private key usages */
int
sc_pkcs15_map_usage(unsigned int cert_usage, int algorithm,
unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr,
int allow_nonrepudiation)
{
unsigned int pub_usage = 0, pr_usage = 0;
unsigned int alg_flags = sc_pkcs15_alg_flags_from_algorithm(algorithm);
if (cert_usage & SC_PKCS15_X509_USAGE_SIGNATURE) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
}
if (cert_usage & SC_PKCS15_X509_USAGE_DERIVE) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
}
if (cert_usage & (SC_PKCS15_X509_USAGE_DECRYPT|SC_PKCS15_X509_USAGE_UNWRAP)) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
}
if (allow_nonrepudiation && (cert_usage & SC_PKCS15_X509_USAGE_NONREPUDIATION)) {
pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
/* filter usages algorithm */
if (pub_usage_ptr) {
*pub_usage_ptr = pub_usage & alg_flags;
}
if (pr_usage_ptr) {
*pr_usage_ptr = pr_usage & alg_flags;
}
return SC_SUCCESS;
}
void
sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert)

View File

@ -538,6 +538,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_INIT_GET_OBJECTS, &count);
LOG_TEST_RET(card->ctx, r, "Can not initiate objects.");
sc_log(card->ctx, "Iterating over %d objects", count);
for (i = 0; i < count; i++) {
struct sc_cardctl_coolkey_object coolkey_obj;
struct sc_pkcs15_object obj_obj;
@ -555,7 +556,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
if (r < 0)
LOG_FUNC_RETURN(card->ctx, r);
sc_log(card->ctx, "Loading object %d", i);
memset(&obj_obj, 0, sizeof(obj_obj));
/* coolkey applets have label only on the certificates,
* but we should copy it also to the keys matching the same ID */
@ -571,6 +572,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
}
switch (obj_class) {
case CKO_PRIVATE_KEY:
sc_log(card->ctx, "Processing private key object %d", i);
r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type);
/* default to CKK_RSA */
if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
@ -593,12 +595,12 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
if (key_type == CKK_RSA) {
obj_type = SC_PKCS15_TYPE_PRKEY_RSA;
if (key) {
prkey_info.modulus_length = key->u.rsa.modulus.len*8;
prkey_info.modulus_length = key->u.rsa.modulus.len*8;
}
} else if (key_type == CKK_EC) {
obj_type = SC_PKCS15_TYPE_PUBKEY_EC;
obj_type = SC_PKCS15_TYPE_PRKEY_EC;
if (key) {
prkey_info.field_length = key->u.ec.params.field_length;
prkey_info.field_length = key->u.ec.params.field_length;
}
} else {
goto fail;
@ -606,6 +608,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
break;
case CKO_PUBLIC_KEY:
sc_log(card->ctx, "Processing public key object %d", i);
r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type);
/* default to CKK_RSA */
if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
@ -623,21 +626,21 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
obj_info = &pubkey_info;
memset(&pubkey_info, 0, sizeof(pubkey_info));
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, key, &pubkey_info.direct.spki.value,
&pubkey_info.direct.spki.len);
&pubkey_info.direct.spki.len);
if (r < 0)
goto fail;
coolkey_get_id(card, &coolkey_obj, &pubkey_info.id);
pubkey_info.path = coolkey_obj.path;
pubkey_info.native = 1;
pubkey_info.native = 1;
pubkey_info.key_reference = coolkey_obj.id;
coolkey_get_usage(card, &coolkey_obj, &pubkey_info.usage);
coolkey_get_access(card, &coolkey_obj, &pubkey_info.access_flags);
if (key_type == CKK_RSA) {
obj_type = SC_PKCS15_TYPE_PUBKEY_RSA;
pubkey_info.modulus_length = key->u.rsa.modulus.len*8;
pubkey_info.modulus_length = key->u.rsa.modulus.len*8;
} else if (key_type == CKK_EC) {
obj_type = SC_PKCS15_TYPE_PUBKEY_EC;
pubkey_info.field_length = key->u.ec.params.field_length;
pubkey_info.field_length = key->u.ec.params.field_length;
} else {
goto fail;
}
@ -647,6 +650,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
break;
case CKO_CERTIFICATE:
sc_log(card->ctx, "Processing certificate object %d", i);
obj_info = &cert_info;
memset(&cert_info, 0, sizeof(cert_info));
coolkey_get_id(card, &coolkey_obj, &cert_info.id);
@ -663,7 +667,8 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
default:
/* no other recognized types which are stored 'on card' */
break;
sc_log(card->ctx, "Unknown object type %lu, skipping", obj_class);
continue;
}
if (obj_info == NULL) {
continue;

View File

@ -43,7 +43,7 @@ sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_data_info *info,
struct sc_pkcs15_data **data_object_out)
{
struct sc_context *ctx = p15card->card->ctx;
struct sc_context *ctx = p15card->card->ctx;
struct sc_pkcs15_data *data_object;
struct sc_pkcs15_der der;
int r;
@ -123,7 +123,10 @@ int sc_pkcs15_decode_dodf_entry(struct sc_pkcs15_card *p15card,
return r;
LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->file_app) {
return SC_ERROR_INTERNAL;
}
r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path);
if (r < 0)
return r;

View File

@ -194,7 +194,7 @@ int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid
sc_path_t path;
unsigned char *tokeninfo_content = NULL;
struct sc_file *file_tokeninfo = NULL;
struct sc_pkcs15_tokeninfo *tokeninfo = sc_pkcs15_tokeninfo_new();
struct sc_pkcs15_tokeninfo *tokeninfo = NULL;
sc_serial_number_t serial;
if (!p15card || ! p15card->card)
@ -202,6 +202,7 @@ int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid
SC_FUNC_CALLED(p15card->card->ctx, 1);
tokeninfo = sc_pkcs15_tokeninfo_new();
if (!p15card || !tokeninfo
|| (aid && (aid->len != sizeof aid_CIA
|| 0 != memcmp(aid->value, aid_CIA, sizeof aid_CIA))))

View File

@ -169,7 +169,10 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card)
}
/* Set root path of this application */
sc_file_free(p15card->file_app);
p15card->file_app = sc_file_new();
if (NULL == p15card->file_app)
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
sc_format_path("3F00", &p15card->file_app->path);
/* Load TokenInfo */

View File

@ -205,7 +205,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
u8 sysrec[7];
int num_keyinfo = 0;
keyinfo kinfo[8]; /* will loook for 8 keys */
keyinfo kinfo[8]; /* will look for 8 keys */
u8 modulus_buf[ 1 + 1024 / 8]; /* tag+modulus */
u8 *cp;
char buf[256];
@ -360,14 +360,14 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
}
if ( gsdata[idx1] == 0x30 &&
is_seq(gsdata + idx1, &seq_size1, &seq_len1) &&
is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) &&
gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 &&
gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 &&
gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 &&
gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 &&
gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 &&
idx1 + 4 + seq_len1 < file->size) {
is_seq(gsdata + idx1, &seq_size1, &seq_len1) &&
is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) &&
gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 &&
gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 &&
gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 &&
gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 &&
gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 &&
idx1 + 4 + seq_len1 < file->size) {
/* we have a cert (I hope) */
/* read in rest if needed */
idxlen = idx1 + seq_len1 + 4 - idx2;
@ -386,7 +386,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
return SC_ERROR_OUT_OF_MEMORY;
memcpy(cert_info.value.value, gsdata + idx1, cert_info.value.len);
idx1 = idx1 + cert_info.value.len;
idx1 = idx1 + cert_info.value.len;
break;
}
idx1++;

View File

@ -425,8 +425,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card)
if (r != SC_SUCCESS || !file)
return SC_ERROR_INTERNAL;
/* set the application DF */
if (p15card->file_app)
free(p15card->file_app);
sc_file_free(p15card->file_app);
p15card->file_app = file;
return SC_SUCCESS;

View File

@ -0,0 +1,286 @@
/*
* partial PKCS15 emulation for IDPrime cards.
*
* We can not use the ISO code, since the EF.DIR and EF.ATR for
* object discovery are missing
*
* Copyright (C) 2019, Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include "internal.h"
#include "cardctl.h"
#include "pkcs15.h"
#define CERT_LABEL_TEMPLATE "Certificate %d"
#define PUBKEY_LABEL_TEMPLATE "Public key %d"
#define PRIVKEY_LABEL_TEMPLATE "Private key %d"
static int idprime_detect_card(sc_pkcs15_card_t *p15card)
{
sc_card_t *card = p15card->card;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
if (card->type < SC_CARD_TYPE_IDPRIME_BASE
|| card->type >= SC_CARD_TYPE_IDPRIME_BASE+1000)
return SC_ERROR_INVALID_CARD;
return SC_SUCCESS;
}
static int sc_pkcs15emu_idprime_init(sc_pkcs15_card_t *p15card)
{
int r, i;
sc_card_t *card = p15card->card;
sc_serial_number_t serial;
char buf[SC_MAX_SERIALNR * 2 + 1];
int count;
char *token_name = NULL;
struct sc_pkcs15_auth_info pin_info;
struct sc_pkcs15_object pin_obj;
const char pin_label[] = "PIN";
const char *pin_id = "11";
/* oid for key usage */
static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }};
unsigned int usage;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
/* could read this off card if needed */
p15card->tokeninfo->label = strdup("IDPrime");
p15card->tokeninfo->manufacturer_id = strdup("Gemalto");
/*
* get serial number
*/
memset(&serial, 0, sizeof(serial));
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
if (r < 0) {
sc_log(card->ctx, "sc_card_ctl rc=%d", r);
p15card->tokeninfo->serial_number = strdup("00000000");
} else {
sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
p15card->tokeninfo->serial_number = strdup(buf);
}
/* set pin */
sc_log(card->ctx, "IDPrime adding pin...");
memset(&pin_info, 0, sizeof(pin_info));
memset(&pin_obj, 0, sizeof(pin_obj));
pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
sc_pkcs15_format_id(pin_id, &pin_info.auth_id);
pin_info.attrs.pin.reference = 0x11;
pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED;
pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info.attrs.pin.min_length = 4;
pin_info.attrs.pin.stored_length = 0;
pin_info.attrs.pin.max_length = 16;
pin_info.tries_left = -1;
sc_log(card->ctx, "IDPrime Adding pin with label=%s", pin_label);
strncpy(pin_obj.label, pin_label, SC_PKCS15_MAX_LABEL_SIZE - 1);
pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
if (r < 0)
LOG_FUNC_RETURN(card->ctx, r);
/*
* get token name if provided
*/
r = sc_card_ctl(card, SC_CARDCTL_IDPRIME_GET_TOKEN_NAME, &token_name);
if (r < 0) {
/* On failure we will get the token name from certificates later */
sc_log(card->ctx, "sc_card_ctl rc=%d", r);
} else {
free(p15card->tokeninfo->label);
p15card->tokeninfo->label = token_name;
sc_log(card->ctx, "IDPrime setting token label = %s", token_name);
}
/*
* certs, pubkeys and priv keys are related and we assume
* they are in order
* We need to read the cert, get modulus and keylen
* We use those for the pubkey, and priv key objects.
*/
sc_log(card->ctx, "IDPrime adding certs, pub and priv keys...");
r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, &count);
LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");
for (i = 0; i < count; i++) {
struct sc_pkcs15_prkey_info prkey_info;
struct sc_pkcs15_cert_info cert_info;
struct sc_pkcs15_pubkey_info pubkey_info;
struct sc_pkcs15_object cert_obj;
struct sc_pkcs15_object pubkey_obj;
struct sc_pkcs15_object prkey_obj;
sc_pkcs15_der_t cert_der;
sc_pkcs15_cert_t *cert_out = NULL;
r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, &prkey_info);
LOG_TEST_RET(card->ctx, r, "Can not get next object");
memset(&cert_info, 0, sizeof(cert_info));
memset(&pubkey_info, 0, sizeof(pubkey_info));
/* prkey_info cleaned by the card_ctl call */
memset(&cert_obj, 0, sizeof(cert_obj));
memset(&pubkey_obj, 0, sizeof(pubkey_obj));
memset(&prkey_obj, 0, sizeof(prkey_obj));
cert_info.id = prkey_info.id;
pubkey_info.id = prkey_info.id;
cert_info.path = prkey_info.path;
/* For private keys, we no longer care for the path, just
* the key reference later used in the security environment */
prkey_info.path.len = 0;
prkey_info.path.aid.len = 0;
pubkey_info.key_reference = prkey_info.key_reference;
sc_log(card->ctx, "Key ref r=%x", prkey_info.key_reference);
pubkey_info.native = 1;
prkey_info.native = 1;
snprintf(cert_obj.label, SC_PKCS15_MAX_LABEL_SIZE, CERT_LABEL_TEMPLATE, i+1);
snprintf(pubkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PUBKEY_LABEL_TEMPLATE, i+1);
snprintf(prkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PRIVKEY_LABEL_TEMPLATE, i+1);
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id);
r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);
if (r) {
sc_log(card->ctx, "No cert found,i=%d", i);
continue;
}
cert_info.path.count = cert_der.len;
sc_log(card->ctx,
"cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n",
cert_der.len, cert_info.path.count, r);
sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len);
/* cache it using the PKCS15 emulation objects */
/* as it does not change */
if (cert_der.value) {
cert_info.value.value = cert_der.value;
cert_info.value.len = cert_der.len;
cert_info.path.len = 0; /* use in mem cert from now on */
}
/* following will find the cached cert in cert_info */
r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
if (r < 0 || cert_out->key == NULL) {
sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r);
if (cert_out != NULL)
sc_pkcs15_free_certificate(cert_out);
free(cert_der.value);
continue;
}
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
if (r < 0) {
sc_log(card->ctx, " Failed to add cert obj r=%d",r);
sc_pkcs15_free_certificate(cert_out);
free(cert_der.value);
continue;
}
/* set the token name to the name of the CN of the first certificate */
if (!token_name) {
u8 * cn_name = NULL;
size_t cn_len = 0;
static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject,
cert_out->subject_len, &cn_oid, &cn_name, &cn_len);
if (r == SC_SUCCESS) {
token_name = malloc (cn_len+1);
if (!token_name) {
free(cn_name);
r = SC_ERROR_OUT_OF_MEMORY;
goto fail;
}
memcpy(token_name, cn_name, cn_len);
free(cn_name);
token_name[cn_len] = '\0';
free(p15card->tokeninfo->label);
p15card->tokeninfo->label = token_name;
}
}
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key,
&pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len);
if (r < 0)
goto fail;
pubkey_obj.emulated = cert_out->key;
r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
if (r < 0) {
usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */
}
sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
sc_dump_hex(cert_info.id.value, cert_info.id.len),
usage, pubkey_info.usage, prkey_info.usage);
if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
sc_pkcs15_free_certificate(cert_out);
continue;
} else {
pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
sc_log(card->ctx, "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
if (r < 0)
goto fail;
sc_log(card->ctx, "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
if (r < 0)
goto fail;
}
cert_out->key = NULL;
fail:
sc_pkcs15_free_certificate(cert_out);
if (r < 0)
LOG_FUNC_RETURN(card->ctx, r); /* should not fail */
}
r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count);
LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card,
struct sc_aid *aid)
{
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (idprime_detect_card(p15card))
return SC_ERROR_WRONG_CARD;
return sc_pkcs15emu_idprime_init(p15card);
}

View File

@ -179,7 +179,7 @@ static int loadFile(const sc_pkcs15_card_t *p15card, const sc_path_t *path,
u8 *buf, const size_t buflen)
{
int sc_res;
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
sc_res = sc_select_file(p15card->card, path, NULL);
if(sc_res != SC_SUCCESS)
@ -207,16 +207,16 @@ static int itacns_add_cert(sc_pkcs15_card_t *p15card,
sc_pkcs15_cert_t *cert;
#endif
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
if(type != SC_PKCS15_TYPE_CERT_X509) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Cannot add a certificate of a type other than X.509");
return 1;
}
*ext_info_ok = 0;
memset(&info, 0, sizeof(info));
memset(&obj, 0, sizeof(obj));
@ -273,7 +273,7 @@ static int itacns_add_pubkey(sc_pkcs15_card_t *p15card,
sc_pkcs15_pubkey_info_t info;
sc_pkcs15_object_t obj;
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
memset(&info, 0, sizeof(info));
memset(&obj, 0, sizeof(obj));
@ -309,10 +309,10 @@ static int itacns_add_prkey(sc_pkcs15_card_t *p15card,
sc_pkcs15_prkey_info_t info;
sc_pkcs15_object_t obj;
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
if(type != SC_PKCS15_TYPE_PRKEY_RSA) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Cannot add a private key of a type other than RSA");
return 1;
}
@ -348,7 +348,7 @@ static int itacns_add_pin(sc_pkcs15_card_t *p15card,
struct sc_pkcs15_auth_info pin_info;
struct sc_pkcs15_object pin_obj;
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
memset(&pin_info, 0, sizeof(pin_info));
pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
@ -525,7 +525,7 @@ static int itacns_add_data_files(sc_pkcs15_card_t *p15card)
rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
objs, 32);
if(rv < 0) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Data enumeration failed");
return SC_SUCCESS;
}
@ -537,7 +537,7 @@ static int itacns_add_data_files(sc_pkcs15_card_t *p15card)
}
if(i>=32) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Could not find EF_DatiPersonali: "
"keeping generic card name");
return SC_SUCCESS;
@ -545,7 +545,7 @@ static int itacns_add_data_files(sc_pkcs15_card_t *p15card)
rv = sc_pkcs15_read_data_object(p15card, cinfo, &p15_personaldata);
if (rv) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Could not read EF_DatiPersonali: "
"keeping generic card name");
return SC_SUCCESS;
@ -555,7 +555,7 @@ static int itacns_add_data_files(sc_pkcs15_card_t *p15card)
char fullname[160];
if(get_name_from_EF_DatiPersonali(p15_personaldata->data,
fullname, sizeof(fullname))) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Could not parse EF_DatiPersonali: "
"keeping generic card name");
sc_pkcs15_free_data_object(p15_personaldata);
@ -661,7 +661,7 @@ static int itacns_check_and_add_keyset(sc_pkcs15_card_t *p15card,
/* Certificate */
if (!cert_path) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"We cannot use keys without a matching certificate");
return SC_ERROR_NOT_SUPPORTED;
}
@ -671,7 +671,7 @@ static int itacns_check_and_add_keyset(sc_pkcs15_card_t *p15card,
if (r == SC_ERROR_FILE_NOT_FOUND)
return 0;
if (r != SC_SUCCESS) {
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Could not find certificate for %s", label);
return r;
}
@ -726,7 +726,7 @@ static int itacns_check_and_add_keyset(sc_pkcs15_card_t *p15card,
prkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
}
#else /* ENABLE_OPENSSL */
sc_log(p15card->card->ctx,
sc_log(p15card->card->ctx,
"Extended certificate info retrieved without OpenSSL. "
"How is this possible?");
return SC_ERROR_INTERNAL;
@ -760,7 +760,7 @@ static int itacns_init(sc_pkcs15_card_t *p15card)
int found_certs;
int card_is_cie_v1, cns0_secenv;
SC_FUNC_CALLED(p15card->card->ctx, 1);
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
set_string(&p15card->tokeninfo->label, p15card->card->name);
if(p15card->card->drv_data) {
@ -848,7 +848,7 @@ static int itacns_init(sc_pkcs15_card_t *p15card)
/* Did we find anything? */
if (certificate_count == 0)
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE,
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Warning: no certificates found!");
/* Back to Master File */
@ -863,7 +863,7 @@ static int itacns_init(sc_pkcs15_card_t *p15card)
int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
{
sc_card_t *card = p15card->card;
SC_FUNC_CALLED(card->ctx, 1);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
/* Check card */
if (! (

View File

@ -105,25 +105,30 @@ typedef struct _pgp_manuf_map {
} pgp_manuf_map_t;
static const pgp_manuf_map_t manuf_map[] = {
{ 0x0001, "PPC Card Systems" },
{ 0x0002, "Prism" },
{ 0x0003, "OpenFortress" },
{ 0x0004, "Wewid AB" },
{ 0x0005, "ZeitControl" },
{ 0x0006, "Yubico" },
{ 0x0007, "OpenKMS" },
{ 0x0008, "LogoEmail" },
{ 0x0009, "Fidesmo" },
{ 0x000A, "Dangerous Things" },
{ 0x002A, "Magrathea" },
{ 0x0042, "GnuPG e.V." },
{ 0x1337, "Warsaw Hackerspace" },
{ 0x2342, "warpzone" },
{ 0x63AF, "Trustica" },
{ 0xBD0E, "Paranoidlabs" },
{ 0xF517, "FSIJ" },
{ 0x0000, "test card" },
{ 0xffff, "test card" },
{ 0x0001, "PPC Card Systems" },
{ 0x0002, "Prism" },
{ 0x0003, "OpenFortress" },
{ 0x0004, "Wewid AB" },
{ 0x0005, "ZeitControl" },
{ 0x0006, "Yubico" },
{ 0x0007, "OpenKMS" },
{ 0x0008, "LogoEmail" },
{ 0x0009, "Fidesmo" },
{ 0x000A, "Dangerous Things" },
{ 0x000B, "Feitian Technologies" },
{ 0x002A, "Magrathea" },
{ 0x0042, "GnuPG e.V." },
{ 0x1337, "Warsaw Hackerspace" },
{ 0x2342, "warpzone" },
{ 0x4354, "Confidential Technologies" },
{ 0x5443, "TIF-IT e.V." },
{ 0x63AF, "Trustica" },
{ 0xBA53, "c-base e.V." },
{ 0xBD0E, "Paranoidlabs" },
{ 0xF517, "FSIJ" },
{ 0xF5EC, "F-Secure" },
{ 0x0000, "test card" },
{ 0xffff, "test card" },
{ 0, NULL }
};
@ -166,7 +171,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
sc_context_t *ctx = card->ctx;
char string[256];
u8 c4data[10];
u8 c5data[70];
u8 c5data[100];
int r, i;
const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V1)
? pin_cfg_v1 : pin_cfg_v2;
@ -257,7 +262,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
*/
if ((r = read_file(card, "006E:0073:00C5", c5data, sizeof(c5data))) < 0)
goto failed;
if (r != 60) {
if (r < 60) {
sc_log(ctx,
"finger print bytes have unexpected length (expected 60, got %d)\n", r);
return SC_ERROR_OBJECT_NOT_VALID;

View File

@ -176,8 +176,10 @@ sc_pkcs15_decode_aodf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_obj
/* Give priority to AID defined in the application DDO */
if (p15card->app && p15card->app->ddo.aid.len)
info.path.aid = p15card->app->ddo.aid;
else if (p15card->file_app->path.len)
else if (p15card->file_app && p15card->file_app->path.len)
info.path = p15card->file_app->path;
else
return SC_ERROR_INTERNAL;
}
}
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "decoded PIN(ref:%X,path:%s)", info.attrs.pin.reference, sc_print_path(&info.path));
@ -296,11 +298,15 @@ sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pi
const unsigned char *pincode, size_t pinlen)
{
struct sc_context *ctx = p15card->card->ctx;
struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
struct sc_pkcs15_auth_info *auth_info;
int r;
LOG_FUNC_CALLED(ctx);
if (!pin_obj || !pin_obj->data)
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_PIN_REFERENCE);
auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
/*
* if pin cache is disabled, we can get here with no PIN data.
* in this case, to avoid error or unnecessary pin prompting on pinpad,

View File

@ -761,6 +761,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
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;
}

View File

@ -36,10 +36,8 @@
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
#endif
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
#endif
#endif
@ -259,8 +257,8 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
r = sc_asn1_decode_choice(ctx, asn1_prkey, *buf, *buflen, buf, buflen);
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
return r;
LOG_TEST_RET(ctx, r, "PrKey DF ASN.1 decoding failed");
goto err;
LOG_TEST_GOTO_ERR(ctx, r, "PrKey DF ASN.1 decoding failed");
if (asn1_prkey[0].flags & SC_ASN1_PRESENT) {
obj->type = SC_PKCS15_TYPE_PRKEY_RSA;
}
@ -274,30 +272,39 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
info.path.type = SC_PATH_TYPE_PATH_PROT;
}
else if (asn1_prkey[3].flags & SC_ASN1_PRESENT) {
/* FIXME proper handling of gost parameters without the need of
* allocating data here. this would also make sc_pkcs15_free_key_params
* obsolete */
obj->type = SC_PKCS15_TYPE_PRKEY_GOSTR3410;
assert(info.modulus_length == 0);
if (info.modulus_length != 0 || info.params.len != 0) {
r = SC_ERROR_INVALID_ASN1_OBJECT;
goto err;
}
info.modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE;
assert(info.params.len == 0);
info.params.len = sizeof(struct sc_pkcs15_keyinfo_gostparams);
info.params.data = malloc(info.params.len);
if (info.params.data == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
assert(sizeof(*keyinfo_gostparams) == info.params.len);
if (info.params.data == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
keyinfo_gostparams = info.params.data;
keyinfo_gostparams->gostr3410 = gostr3410_params[0];
keyinfo_gostparams->gostr3411 = gostr3410_params[1];
keyinfo_gostparams->gost28147 = gostr3410_params[2];
}
else {
sc_log(ctx, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry.");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
r = SC_ERROR_INVALID_ASN1_OBJECT;
LOG_TEST_GOTO_ERR(ctx, r, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry.");
}
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->file_app) {
r = SC_ERROR_INTERNAL;
goto err;
}
r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path);
if (r < 0) {
sc_pkcs15_free_key_params(&info.params);
return r;
goto err;
}
}
else {
@ -340,14 +347,24 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
obj->data = malloc(sizeof(info));
if (obj->data == NULL) {
sc_pkcs15_free_key_params(&info.params);
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
memcpy(obj->data, &info, sizeof(info));
sc_log(ctx, "Key Subject %s", sc_dump_hex(info.subject.value, info.subject.len));
sc_log(ctx, "Key path %s", sc_print_path(&info.path));
return 0;
r = SC_SUCCESS;
err:
if (r < 0) {
/* This might have allocated something. If so, clear it now */
free(info.subject.value);
sc_pkcs15_free_key_params(&info.params);
}
return r;
}
int sc_pkcs15_encode_prkdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj,
@ -580,7 +597,6 @@ sc_pkcs15_free_prkey(struct sc_pkcs15_prkey *key)
free(key->u.dsa.priv.data);
break;
case SC_ALGORITHM_GOSTR3410:
assert(key->u.gostr3410.d.data);
free(key->u.gostr3410.d.data);
break;
case SC_ALGORITHM_EC:
@ -599,6 +615,9 @@ sc_pkcs15_free_prkey(struct sc_pkcs15_prkey *key)
void sc_pkcs15_free_prkey_info(sc_pkcs15_prkey_info_t *key)
{
if (!key)
return;
if (key->subject.value)
free(key->subject.value);
@ -678,7 +697,7 @@ sc_pkcs15_convert_prkey(struct sc_pkcs15_prkey *pkcs15_key, void *evp_key)
DSA_free(src);
break;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
#if !defined(OPENSSL_NO_EC)
case NID_id_GostR3410_2001: {
struct sc_pkcs15_prkey_gostr3410 *dst = &pkcs15_key->u.gostr3410;
EC_KEY *src = EVP_PKEY_get0(pk);
@ -755,7 +774,7 @@ sc_pkcs15_convert_prkey(struct sc_pkcs15_prkey *pkcs15_key, void *evp_key)
break;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */
#endif /* !defined(OPENSSL_NO_EC) */
default:
return SC_ERROR_NOT_SUPPORTED;
}

View File

@ -163,8 +163,7 @@ static int sc_pkcs15emu_pteid_init(sc_pkcs15_card_t * p15card)
if (rv != SC_SUCCESS || !file)
return SC_ERROR_INTERNAL;
/* set the application DF */
if (p15card->file_app)
free(p15card->file_app);
sc_file_free(p15card->file_app);
p15card->file_app = file;
/* Load TokenInfo */

View File

@ -40,12 +40,10 @@
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
#endif
#endif
#endif
#include "internal.h"
#include "asn1.h"
@ -340,7 +338,11 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card,
obj->type = SC_PKCS15_TYPE_PUBKEY_DSA;
}
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->app || !p15card->app->ddo.aid.len) {
if (!p15card->file_app) {
r = SC_ERROR_INTERNAL;
goto err;
}
r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info->path);
if (r < 0) {
goto err;
@ -1622,7 +1624,7 @@ sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key)
DSA_free(src);
break;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
#if !defined(OPENSSL_NO_EC)
case NID_id_GostR3410_2001: {
struct sc_pkcs15_pubkey_gostr3410 *dst = &pkcs15_key->u.gostr3410;
EC_KEY *eckey = EVP_PKEY_get0(pk);
@ -1703,7 +1705,7 @@ sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key)
break;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */
#endif /* !defined(OPENSSL_NO_EC) */
default:
return SC_ERROR_NOT_SUPPORTED;
}

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