Merge branch 'master' into ecc-fixes
This commit is contained in:
commit
e45712bd29
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
11
.travis.yml
11
.travis.yml
|
@ -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
37
COPYING
|
@ -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!
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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}
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
106
NEWS
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
38
appveyor.yml
38
appveyor.yml
|
@ -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
|
||||
|
|
15
configure.ac
15
configure.ac
|
@ -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}")
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -170,6 +170,13 @@
|
|||
<listitem><para>Specify 'derive' key usage flag (EC only).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--usage-wrap</option>
|
||||
</term>
|
||||
<listitem><para>Specify 'wrap' key usage flag.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--label</option> <replaceable>name</replaceable>,
|
||||
|
|
|
@ -348,46 +348,26 @@
|
|||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--options-file</option> <replaceable>filename</replaceable>
|
||||
<option>--pin</option> <replaceable>pin</replaceable>,
|
||||
<option>--puk</option> <replaceable>puk</replaceable>,
|
||||
<option>--so-pin</option> <replaceable>sopin</replaceable>,
|
||||
<option>--so-puk</option> <replaceable>sopuk</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Tells <command>pkcs15-init</command> to read additional options
|
||||
from <replaceable>filename</replaceable>. The file is supposed to
|
||||
contain one long option per line, without the leading dashes,
|
||||
for instance:
|
||||
<programlisting>
|
||||
pin 1234
|
||||
puk 87654321
|
||||
</programlisting>
|
||||
These options can be used to specify the PIN/PUK values
|
||||
on the command line. If the value is set to
|
||||
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
|
||||
of the specified environment variable is used. By default,
|
||||
the code is prompted on the command line if needed.
|
||||
</para>
|
||||
<para>
|
||||
You can specify <option>--options-file</option> several times.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--pin</option>,
|
||||
<option>--puk</option>
|
||||
<option>--so-pin</option>,
|
||||
<option>--so-puk</option>,
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
These options can be used to specify PIN/PUK values
|
||||
on the command line. If set to
|
||||
env:<replaceable>VARIABLE</replaceable>, the value
|
||||
of the environment variable
|
||||
<replaceable>VARIABLE</replaceable> is used. Note
|
||||
that on most operation systems, any user can
|
||||
Note that on most operation systems, any user can
|
||||
display the command line of any process on the
|
||||
system using utilities such as
|
||||
<command>ps(1)</command>. Therefore, you should use
|
||||
these options only on a secured system, or in an
|
||||
options file specified with
|
||||
<option>--options-file</option>.
|
||||
<command>ps(1)</command>. Therefore, you should prefer
|
||||
passing the codes via an environment variable
|
||||
on an unsecured system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
@ -310,16 +310,27 @@
|
|||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--pin</option> <replaceable>PIN</replaceable>
|
||||
<option>--pin</option> <replaceable>pin</replaceable>,
|
||||
<option>--new-pin</option> <replaceable>newpin</replaceable>
|
||||
<option>--puk</option> <replaceable>puk</replaceable>
|
||||
</term>
|
||||
<listitem><para>Specify PIN</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--puk</option> <replaceable>PUK</replaceable>
|
||||
</term>
|
||||
<listitem><para>Specify Unblock PIN</para></listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
These options can be used to specify the PIN/PUK values
|
||||
on the command line. If the value is set to
|
||||
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
|
||||
of the specified environment variable is used. By default,
|
||||
the code is prompted on the command line if needed.
|
||||
</para>
|
||||
<para>
|
||||
Note that on most operation systems, any user can
|
||||
display the command line of any process on the
|
||||
system using utilities such as
|
||||
<command>ps(1)</command>. Therefore, you should prefer
|
||||
passing the codes via an environment variable
|
||||
on an unsecured system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -120,26 +120,25 @@
|
|||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--so-pin</option> <replaceable>value</replaceable>
|
||||
<option>--pin</option> <replaceable>pin</replaceable>,
|
||||
<option>--so-pin</option> <replaceable>sopin</replaceable>,
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Define SO-PIN for initialization. If set to
|
||||
env:<replaceable>VARIABLE</replaceable>, the value of
|
||||
the environment variable
|
||||
<replaceable>VARIABLE</replaceable> is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--pin</option> <replaceable>value</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Define user PIN for initialization, wrap or
|
||||
unwrap operation. If set to
|
||||
env:<replaceable>VARIABLE</replaceable>, the value of
|
||||
the environment variable
|
||||
<replaceable>VARIABLE</replaceable> is used.</para>
|
||||
<para>
|
||||
These options can be used to specify the PIN values
|
||||
on the command line. If the value is set to
|
||||
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
|
||||
of the specified environment variable is used. By default,
|
||||
the code is prompted on the command line if needed.
|
||||
</para>
|
||||
<para>
|
||||
Note that on most operation systems, any user can
|
||||
display the command line of any process on the
|
||||
system using utilities such as
|
||||
<command>ps(1)</command>. Therefore, you should prefer
|
||||
passing the codes via an environment variable
|
||||
on an unsecured system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
@ -115,25 +115,28 @@
|
|||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--pin-value</option> <replaceable>value</replaceable>,
|
||||
<option>-x</option> <replaceable>value</replaceable>
|
||||
<option>--pin-value</option> <replaceable>pin</replaceable>,
|
||||
<option>-x</option> <replaceable>pin</replaceable>
|
||||
<option>--puk-value</option> <replaceable>puk</replaceable>,
|
||||
<option>-y</option> <replaceable>puk</replaceable>
|
||||
</term>
|
||||
<listitem><para>Set value of PIN. If set to
|
||||
env:<replaceable>VARIABLE</replaceable>, the value of
|
||||
the environment variable
|
||||
<replaceable>VARIABLE</replaceable> is used.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--puk-value</option> <replaceable>value</replaceable>,
|
||||
<option>-y</option> <replaceable>value</replaceable>
|
||||
</term>
|
||||
<listitem><para>set value of PUK (or value of new PIN for change PIN
|
||||
command see <option>-n</option>). If set to
|
||||
env:<replaceable>VARIABLE</replaceable>, the value of
|
||||
the environment variable
|
||||
<replaceable>VARIABLE</replaceable> is used.</para></listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
These options can be used to specify the PIN/PUK values
|
||||
on the command line. If the value is set to
|
||||
<literal>env:</literal><replaceable>VARIABLE</replaceable>, the value
|
||||
of the specified environment variable is used. By default,
|
||||
the code is prompted on the command line if needed.
|
||||
</para>
|
||||
<para>
|
||||
Note that on most operation systems, any user can
|
||||
display the command line of any process on the
|
||||
system using utilities such as
|
||||
<command>ps(1)</command>. Therefore, you should prefer
|
||||
passing the codes via an environment variable
|
||||
on an unsecured system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -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"
|
||||
])
|
||||
])
|
|
@ -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"
|
||||
])
|
||||
])
|
|
@ -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])
|
||||
])
|
|
@ -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])[
|
||||
])
|
||||
])
|
|
@ -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])
|
||||
])
|
|
@ -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
|
||||
])
|
|
@ -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="\""
|
||||
])
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -71,8 +71,10 @@
|
|||
|
||||
/* disable asserts */
|
||||
#ifndef SIMCLIST_DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -123,7 +123,7 @@ static int atrust_acos_init(struct sc_card *card)
|
|||
| SC_ALGORITHM_RSA_HASH_RIPEMD160
|
||||
| SC_ALGORITHM_RSA_HASH_MD5_SHA1;
|
||||
|
||||
if (!strcmp(card->name, ACOS_EMV_A05))
|
||||
if (card->name != NULL && !strcmp(card->name, ACOS_EMV_A05))
|
||||
flags |= SC_ALGORITHM_RSA_HASH_SHA256;
|
||||
|
||||
_sc_card_add_rsa_alg(card, 1536, flags, 0x10001);
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#endif
|
||||
#include "iso7816.h"
|
||||
#include "card-cac-common.h"
|
||||
#include "pkcs15.h"
|
||||
|
||||
/*
|
||||
* CAC hardware and APDU constants
|
||||
|
@ -105,6 +106,8 @@
|
|||
#define CAC_ACR_AMP 0x20
|
||||
#define CAC_ACR_SERVICE 0x21
|
||||
|
||||
#define CAC_MAX_CCC_DEPTH 16
|
||||
|
||||
/* hardware data structures (returned in the CCC) */
|
||||
/* part of the card_url */
|
||||
typedef struct cac_access_profile {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(¶ms.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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -128,6 +128,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
|
|||
{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
|
||||
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
|
||||
{ "esteid2018", (void *(*)(void)) sc_get_esteid2018_driver },
|
||||
{ "idprime", (void *(*)(void)) sc_get_idprime_driver },
|
||||
|
||||
/* Here should be placed drivers that need some APDU transactions in the
|
||||
* driver's `match_card()` function. */
|
||||
|
|
|
@ -647,23 +647,22 @@ static int cwa_prepare_external_auth(sc_card_t * card,
|
|||
if (bnsub)
|
||||
BN_free(bnsub);
|
||||
if (buf1) {
|
||||
memset(buf1, 0, 128);
|
||||
sc_mem_clear(buf1, 128);
|
||||
free(buf1);
|
||||
}
|
||||
if (buf2) {
|
||||
memset(buf2, 0, 128);
|
||||
sc_mem_clear(buf2, 128);
|
||||
free(buf2);
|
||||
}
|
||||
if (buf3) {
|
||||
memset(buf3, 0, 128);
|
||||
sc_mem_clear(buf3, 128);
|
||||
free(buf3);
|
||||
}
|
||||
if (sha_buf) {
|
||||
memset(sha_buf, 0, 74 + 32 + 8 + 1 + 7);
|
||||
sc_mem_clear(sha_buf, 74 + 32 + 8 + 1 + 7);
|
||||
free(sha_buf);
|
||||
}
|
||||
if (sha_data) {
|
||||
memset(sha_data, 0, SHA_DIGEST_LENGTH);
|
||||
free(sha_data);
|
||||
}
|
||||
|
||||
|
@ -770,15 +769,14 @@ static int cwa_compute_session_keys(sc_card_t * card)
|
|||
|
||||
compute_session_keys_end:
|
||||
if (kseed) {
|
||||
memset(kseed, 0, 32);
|
||||
sc_mem_clear(kseed, 32);
|
||||
free(kseed);
|
||||
}
|
||||
if (data) {
|
||||
memset(data, 0, 32 + 4);
|
||||
sc_mem_clear(data, 32 + 4);
|
||||
free(data);
|
||||
}
|
||||
if (sha_data) {
|
||||
memset(sha_data, 0, SHA_DIGEST_LENGTH);
|
||||
free(sha_data);
|
||||
}
|
||||
if (res != SC_SUCCESS)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -499,6 +499,7 @@ int sc_get_encoding_flags(sc_context_t *ctx,
|
|||
/* Use the card's raw RSA capability on the padded input */
|
||||
*sflags = SC_ALGORITHM_RSA_PAD_NONE;
|
||||
*pflags = iflags;
|
||||
/* TODO emulate the OAEP decryption */
|
||||
|
||||
} else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
|
||||
(iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
|
||||
|
|
|
@ -252,7 +252,13 @@ static int sc_pkcs15emu_actalis_init(sc_pkcs15_card_t * p15card)
|
|||
|
||||
j++;
|
||||
cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||
sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
|
||||
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
|
||||
if (r < 0) {
|
||||
sc_log(card->ctx, "Failed to add cert obj r=%d", r);
|
||||
free(cert);
|
||||
free(compCert);
|
||||
continue;
|
||||
}
|
||||
|
||||
free(cert);
|
||||
free(compCert);
|
||||
|
|
|
@ -253,8 +253,7 @@ static int sc_pkcs15emu_atrust_acos_init(sc_pkcs15_card_t *p15card)
|
|||
if (r != SC_SUCCESS || !file)
|
||||
return SC_ERROR_INTERNAL;
|
||||
/* set the application DF */
|
||||
if (p15card->file_app)
|
||||
free(p15card->file_app);
|
||||
sc_file_free(p15card->file_app);
|
||||
p15card->file_app = file;
|
||||
|
||||
return SC_SUCCESS;
|
||||
|
|
|
@ -84,89 +84,6 @@ static const char * cac_get_name(int type)
|
|||
return ("CAC");
|
||||
}
|
||||
|
||||
/*
|
||||
* These could move to a helper file for other cards that wish to use usage as a way of getting flags
|
||||
*/
|
||||
|
||||
/* Only certain usages are valid for a given algorithm, return all the usages that the algorithm supports so we
|
||||
* can use it as a filter for all the public and private key usages */
|
||||
static unsigned int
|
||||
cac_alg_flags_from_algorithm(int algorithm)
|
||||
{
|
||||
switch (algorithm) {
|
||||
case SC_ALGORITHM_RSA:
|
||||
return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP |
|
||||
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
|
||||
SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
|
||||
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
|
||||
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
case SC_ALGORITHM_DSA:
|
||||
return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
|
||||
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
#ifdef SC_ALGORITHM_DH
|
||||
case SC_ALGORITHM_DH:
|
||||
return SC_PKCS15_PRKEY_USAGE_DERIVE ;
|
||||
#endif
|
||||
case SC_ALGORITHM_EC:
|
||||
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
|
||||
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
case SC_ALGORITHM_GOSTR3410:
|
||||
return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
|
||||
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */
|
||||
#define CAC_X509_USAGE_SIGNATURE \
|
||||
(SC_X509_DIGITAL_SIGNATURE | \
|
||||
SC_X509_NON_REPUDIATION | \
|
||||
SC_X509_KEY_CERT_SIGN | \
|
||||
SC_X509_CRL_SIGN)
|
||||
#define CAC_X509_USAGE_DERIVE \
|
||||
SC_X509_KEY_AGREEMENT
|
||||
#define CAC_X509_USAGE_UNWRAP \
|
||||
(SC_X509_KEY_ENCIPHERMENT | \
|
||||
SC_X509_KEY_AGREEMENT)
|
||||
#define CAC_X509_USAGE_DECRYPT \
|
||||
(SC_X509_DATA_ENCIPHERMENT | \
|
||||
SC_X509_ENCIPHER_ONLY)
|
||||
#define CAC_X509_USAGE_NONREPUDIATION \
|
||||
SC_X509_NON_REPUDIATION
|
||||
|
||||
/* map a cert usage and algorithm to public and private key usages */
|
||||
static int
|
||||
cac_map_usage(unsigned int cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation)
|
||||
{
|
||||
unsigned int pub_usage = 0, pr_usage = 0;
|
||||
unsigned int alg_flags = cac_alg_flags_from_algorithm(algorithm);
|
||||
|
||||
if (cert_usage & CAC_X509_USAGE_SIGNATURE) {
|
||||
pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
|
||||
pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
|
||||
}
|
||||
if (cert_usage & CAC_X509_USAGE_DERIVE) {
|
||||
pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
}
|
||||
if (cert_usage & (CAC_X509_USAGE_DECRYPT|CAC_X509_USAGE_UNWRAP)) {
|
||||
pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
|
||||
pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
|
||||
}
|
||||
if (allow_nonrepudiation && (cert_usage & CAC_X509_USAGE_NONREPUDIATION)) {
|
||||
pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
}
|
||||
/* filter usages algorithm */
|
||||
if (pub_usage_ptr) {
|
||||
*pub_usage_ptr = pub_usage & alg_flags;
|
||||
}
|
||||
if (pr_usage_ptr) {
|
||||
*pr_usage_ptr = pr_usage & alg_flags;
|
||||
}
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
|
||||
{
|
||||
static const pindata pins[] = {
|
||||
|
@ -407,9 +324,9 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
|
||||
if (r < 0) {
|
||||
usage = 0xd9ULL; /* basic default usage */
|
||||
usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */
|
||||
}
|
||||
cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
|
||||
sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
|
||||
sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
|
||||
sc_dump_hex(cert_info.id.value, cert_info.id.len),
|
||||
usage, pubkey_info.usage, prkey_info.usage);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -169,7 +169,10 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card)
|
|||
}
|
||||
|
||||
/* Set root path of this application */
|
||||
sc_file_free(p15card->file_app);
|
||||
p15card->file_app = sc_file_new();
|
||||
if (NULL == p15card->file_app)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
|
||||
sc_format_path("3F00", &p15card->file_app->path);
|
||||
|
||||
/* Load TokenInfo */
|
||||
|
|
|
@ -205,7 +205,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
u8 sysrec[7];
|
||||
int num_keyinfo = 0;
|
||||
keyinfo kinfo[8]; /* will loook for 8 keys */
|
||||
keyinfo kinfo[8]; /* will look for 8 keys */
|
||||
u8 modulus_buf[ 1 + 1024 / 8]; /* tag+modulus */
|
||||
u8 *cp;
|
||||
char buf[256];
|
||||
|
@ -360,14 +360,14 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
|
|||
}
|
||||
|
||||
if ( gsdata[idx1] == 0x30 &&
|
||||
is_seq(gsdata + idx1, &seq_size1, &seq_len1) &&
|
||||
is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 &&
|
||||
idx1 + 4 + seq_len1 < file->size) {
|
||||
is_seq(gsdata + idx1, &seq_size1, &seq_len1) &&
|
||||
is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 &&
|
||||
gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 &&
|
||||
idx1 + 4 + seq_len1 < file->size) {
|
||||
/* we have a cert (I hope) */
|
||||
/* read in rest if needed */
|
||||
idxlen = idx1 + seq_len1 + 4 - idx2;
|
||||
|
@ -386,7 +386,7 @@ static int sc_pkcs15emu_gemsafeGPK_init(sc_pkcs15_card_t *p15card)
|
|||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(cert_info.value.value, gsdata + idx1, cert_info.value.len);
|
||||
idx1 = idx1 + cert_info.value.len;
|
||||
idx1 = idx1 + cert_info.value.len;
|
||||
break;
|
||||
}
|
||||
idx1++;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 (! (
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue