debian/0000755000000000000000000000000012271714100007161 5ustar debian/libckyapplet1.dirs0000644000000000000000000000001011617461503012610 0ustar usr/lib debian/copyright0000644000000000000000000000726612266506371011144 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: coolkey Upstream-Contact: http://directory.fedoraproject.org/wiki/CoolKey Source: http://directory.fedora.redhat.com/download/coolkey/coolkey-1.1.0.tar.gz Comment: Debianized by A. Maitland Bottoms on 28 November 2006. CVSROOT=:pserver:anonymous@cvs.fedora.redhat.com:/cvs/dirsec cvs export -D 20061215 coolkey Updates from SVN at http://svn.fedorahosted.org/svn/coolkey Updates from git at http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git or git://pkgs.fedoraproject.org/coolkey.git Updates from Red Hat source: (coolkey-1.1.0-15.el5.src.rpm MD5: 660de82bb4173dd68b996f872e841937 SHA-256: 77aff0adfabd0f9049ebff152fec2a5c11d6c521bcb76cfc2e272d1d6c531625) Copyright: 2005-2011 Red Hat, Inc. License: LGPL-2.1 The Coolkey library is: # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # # 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 version # 2.1 of the License. . A full copy of the license is in the file: /usr/share/common-licenses/LGPL-2.1 Files: debian/* Copyright: 2006,2007,2010,2012, A. Maitland Bottoms 2007-2009,2011-2012 Ludovic Rousseau License: LGPL-2.1 Comment: patches in debian/patches are derived from the patches available in the Red Hat .src.rpm files, adjusted by quilt refresh. Files: conf* *am *in ac* lt* missing Comment: The package is built using autoconf, automake, libtool et al. Copyright: (C) 1994-2005,2011,2012 Free Software Foundation, Inc. License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This program 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 General Public License for more details. . You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. Files: install-sh Comment: This originates from X11R5 (mit/util/scripts/install.sh), which was later released in X11R6 (xc/config/util/install.sh) with the following copyright and license. Copyright: (C) 1994 X Consortium License: MIT/X Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. License: LGPL-2.1 The Coolkey library is: # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # # 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 version # 2.1 of the License. . A full copy of the license is in the file: /usr/share/common-licenses/LGPL-2.1 debian/libckyapplet1.install0000644000000000000000000000015011617461503013322 0ustar src/libckyapplet/.libs/libckyapplet.so.1.0.0 usr/lib/ src/libckyapplet/.libs/libckyapplet.so.1 usr/lib/ debian/libckyapplet1-dev.dirs0000644000000000000000000000001412266513514013371 0ustar usr/include debian/source/0000755000000000000000000000000012266514235010474 5ustar debian/source/format0000644000000000000000000000001411617461503011700 0ustar 3.0 (quilt) debian/README.Debian0000644000000000000000000001316212266506371011242 0ustar Some hints on making use of Coolkey. The active ingredient in the Coolkey package is the file /usr/lib/pkcs11/libcoolkeypk11.so - which is a "PKCS #11 module". Several applications can make use of PKCS #11 modules - including iceweasel, iceape, icedove, epiphany and evolution. The web browser and email applications usually have a GUI allowing the user to control how PKCS #11 modules and PKI certificates are used. Many applications use an underlying cryptography library from the Mozilla project called the "Network Security Service". Where there is no gui - such as the Gnome Evolution MUA, the libnss3-tools Debian package provides Network Security Service tools for manipulating an application's database of PKCS #11 modules and PKI certificates. The Coolkey package also provides the pk11install application. "pk11install is really a generic tool that probably should be moved to NSS (you can change the parameters and install any PKCS #11 module)." ... "It differs form modutil in that it doesn't try to load the module itself to install it. It also differs from modutil in that it 'knows' where several NSS apps store their database (OK, where old netscape and modern mozilla apps). You can run it as a user and install your favorite PKCS #11 module into all the browsers/mailreaders you have installed." - Bob Relyea, a coolkey developer. Coolkey depends upon the pcscd musclecard token management daemon. (Using libpcsclite to communicate.) Coolkey will dynamically detect pcscd and the presence of tokens when the system has pcscd managing one or more PKI hardware token device interfaces (such as an ActivCard, Inc. SmartCard Reader, or a Dell smart card reader keyboard, or other CCID and/or musclecard supported devices). A user will have a PKI capable Smart Card inserted in the reader, and then Coolkey will allow the web browser to authenticate the user to a web server, and a Mail User Agent to sign and decrypt email messages. Public Key Infrastructure, PKI, is all about certificate management. The user has the responsibility to decide which can be trusted, given the set of Certificate Authority certificates (and also subsidiary CA certificates) and individual and system ID certificates. Most applications provide a GUI for managing certificates, or the NSS (Network Security Service) certutil can be useful. Even when an application is using coolkey and the hardware and smart card token are present, the application probably won't carry out authentication or signing operations unless it also has the right chain of CA certificates installed and trusted. The Debian package ca-certificates has quite a few CA certificates that might be useful. Those using Coolkey with DoD PKI might look into Bug #274963: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=274963 Read /usr/share/doc/ca-certificates/README.Debian and you can help resolve that bug. Of course, with PKI one should proceed with caution and due diligence when selecting CA certificates to trust. Some starting places for finding DoD CA certificates include: https://ca-5.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-6.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-7.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-8.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-9.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-10.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-11.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-12.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-13.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-14.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-15.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-16.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-17.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-18.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-19.c3pki.chamb.disa.mil/ca/GetCAChain.html https://ca-20.c3pki.den.disa.mil/ca/GetCAChain.html https://ca-21.c3pki.chamb.disa.mil/ca/GetCAChain.html Coolkey with Mozilla-based NSS applications ( firefox, iceweasel, iceape, thunderbird, icedove...) From the Application GUI: - Edit - Preferences - Security tab (or possibly Encrytion tab) - Security Devices button in the Device Manager pop-up window - Load button in the Load PKCS#11 Device pop-up window - give it a name, such as "Coolkey PKCS#11 Module" - select the filename /usr/lib/pkcs11/libcoolkeypk11.so with the smart card inserted - OK button Not that selecting the PKCS#11 token in the Device Manager window will provide for log in, log out and change password operations using the smart card's PIN. Then under the Edit - Preferences - Security tab, selecting - View Certificates button will show the certificates present on the smart card under the My Certiciates tab. Coolkey with Gnome Epiphany web browser: The Debian package epiphany-extensions should be installed to provide the necessary NSS support. From the Tools menu item, the manage Security Devices and Certificate Manager GUIs are available. Coolkey with Evolution: You can use the NSS modultil command to insert your PKCS #11 token into evolution's secmod.db: `modutil -add "Coolkey" -libfile /usr/lib/pkcs11/libcoolkeypk11.so -dbdir .evolution` from my home directory did the right thing. Alas, evolution as of version 2.6.3-3 still had some problems picking the right certificate... perhaps evolution bugzilla bug 372435. Updates to support newer cards... as of version 1.1.0-12 coolkey includes support. For discussion see https://bugzilla.redhat.com/show_bug.cgi?id=593017 https://bugzilla.redhat.com/show_bug.cgi?id=534172 http://rhn.redhat.com/errata/RHEA-2011-0111.html -- A. Maitland Bottoms , Tue, 10 Apr 2012 19:07:33 -0400 debian/libckyapplet1-dev.install0000755000000000000000000000061712266512124014106 0ustar #! /usr/bin/dh-exec src/libckyapplet/.libs/libckyapplet.so usr/lib/ src/libckyapplet/.libs/libckyapplet.a usr/lib/ src/libckyapplet/libckyapplet.pc usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig/ src/libckyapplet/cky_applet.h usr/include/ src/libckyapplet/cky_card.h usr/include/ src/libckyapplet/cky_base.h usr/include/ src/libckyapplet/cky_list.h usr/include/ src/libckyapplet/cky_factory.h usr/include/ debian/changelog0000644000000000000000000001565512271704556011065 0ustar coolkey (1.1.0-13ubuntu2) trusty; urgency=low * Remove recommends for epiphany-browser as it no longer exists. Debian bug 736181. -- Brian Murray Tue, 28 Jan 2014 01:57:12 -0800 coolkey (1.1.0-13ubuntu1) trusty; urgency=medium * Use dh-autoreconf instead of autotools-dev to also fix FTBFS on ppc64el by getting new libtool macros (still updates config.{sub,guess}). -- Logan Rosen Sat, 18 Jan 2014 23:46:09 -0500 coolkey (1.1.0-13) unstable; urgency=medium * Fix "uninitialized variable causes firefox to crash when card is inserted into reader" patch in debian/patches/coolkey-nextSize.patch (Closes: #698230) * Install the libckyapplet.pc in the correct multi-arch directory * debian/control: use canonical Vcs-* fields -- Ludovic Rousseau Sat, 18 Jan 2014 15:06:42 +0000 coolkey (1.1.0-12) unstable; urgency=low * The coolkey device driver has been updated to follow the new Card Compatibility Container (CCC) specification, so that Gemalto TOPDLGX4 144K CAC cards are now supported. * Handle pcscd restarting. * debian/control: Standards-Version: 3.9.2 -> 3.9.3. Dep3 headers updated in debian/patches files; Dep5 Machine-readable debian/copyright -- A. Maitland Bottoms Wed, 11 Apr 2012 20:56:20 -0400 coolkey (1.1.0-11) unstable; urgency=low * debian/control: Fix libckyapplet1-dev_1.1.0-10_amd64.deb: package says section is libdevel, override says devel. * Fix "Coolkey don't working with ActiveKey Sim" proposed patch applied (Closes: #634870) * Fix lintian warning: I: coolkey: package-contains-empty-directory usr/bin/ * Use debhelper version 9 to have automatic hardening -- Ludovic Rousseau Mon, 09 Apr 2012 17:12:01 +0200 coolkey (1.1.0-10) unstable; urgency=low * Fix "FTBFS: /usr/bin/ld: cannot find -lsoftokn3" do not build pk11install anymore (Closes: #632803) * Fix "Broken dependencies: pk11install: error while loading shared libraries: libsoftokn3.so" pk11install is no more provided (Closes: #635033) * Do not provide .la files any more. Fix lintian errors: E: coolkey: non-empty-dependency_libs-in-la-file usr/lib/pkcs11/libcoolkeypk11.la E: libckyapplet1-dev: non-empty-dependency_libs-in-la-file usr/lib/libckyapplet.la * debian/control: Standards-Version: 3.8.3 -> 3.9.2. No change needed. -- Ludovic Rousseau Sun, 07 Aug 2011 12:49:58 +0200 coolkey (1.1.0-9) unstable; urgency=low * debian/patches/coolkey-latest.patch: refresh * debian/patches/coolkey-pcsc-lite: use SCARD_READERSTATE * instead of LPSCARD_READERSTATE not present in pcsc-lite from squeeze (1.5.5) -- Ludovic Rousseau Sun, 27 Mar 2011 15:22:11 +0200 coolkey (1.1.0-8) unstable; urgency=low * Fix "FTBFS: cky_card.h:44: error: expected ')' before '*' token" patch in coolkey-pcsc-lite (Closes: #614437) * debian/patches/spelling-error-in-binary: I: coolkey: spelling-error-in-binary ./usr/lib/pkcs11/libcoolkeypk11.so Inconsistant Inconsistent -- Ludovic Rousseau Wed, 23 Feb 2011 20:36:20 +0000 coolkey (1.1.0-7) experimental; urgency=low * Update packaging using dh and dpkg-source 3.0 (quilt) format * upstream coolkey-coolkey-cache-dir-move.patch * upstream coolkey-gcc43.patch * upstream coolkey-latest.patch * upstream coolkey-simple-bugs.patch * upstream coolkey-thread-fix.patch * upstream coolkey-cac.patch * upstream coolkey-cac-1.patch -- A. Maitland Bottoms Wed, 22 Dec 2010 19:12:07 -0500 coolkey (1.1.0-6) unstable; urgency=low * debian/control: Standards-Version: 3.7.3 => 3.8.3 add debian/README.source (lintian warning patch-system-but-no-source-readme) * use debhelper compat level 7 instead of (deprecated) 4 * debian/control: add ${misc:Depends} lintian warning debhelper-but-no-misc-depends -- Ludovic Rousseau Sun, 01 Nov 2009 16:10:52 +0100 coolkey (1.1.0-5) unstable; urgency=medium * debian/control: Build-Depends: libnspr4-dev Closes: #486956 "FTBFS: pkcs11t.h:59:21: error: prtypes.h: No such file or directory" -- Ludovic Rousseau Sun, 22 Jun 2008 07:42:03 +0200 coolkey (1.1.0-4) unstable; urgency=low * debian/rules: - use -rpath to find libsoftokn3.so in /usr/lib/nss/ since nss version 3.12.0~1.9b1-1 moved it there. Closes: #456877 "coolkey: FTBFS: /usr/bin/ld: cannot find -lsoftokn3" - do not ignore $(MAKE) clean result (debian-rules-ignores-make-clean-error lintian warning) * debian/control: - Standards-Version: 3.7.2.2 -> 3.7.3. No change needed - use a debian/compat file instead of DH_COMPAT in debian/rules - add a minimal Build-Depends: version on debhelper - set libckyapplet1-dev in Section: libdevel instead of devel - change coolkey Depends: from libccid, pcscd to libpcsclite1 Closes: #445164 "coolkey: Update libccid depends for pcsc-omnikey" - libckyapplet1-dev Depends: on the ${binary:Version} of libckyapplet1 - add a Homepage: field - add Vcs-Browser: and Vcs-Svn: fields * debian/patches/{01_coolkey_cpp.dpatch, 02_log_cpp.dpatch, 03_machdep_cpp.dpatch, 04_object_cpp.dpatch, 05_slot_cpp.dpatch}: fixes for g++ 4.3. Closes: #455658 "FTBFS with GCC 4.3: #define redefined" -- Ludovic Rousseau Sun, 06 Jan 2008 17:58:33 +0100 coolkey (1.1.0-3) unstable; urgency=low * fix for CVE-2007-4129 - correct cache file handling debian/patches/06_machdep_cpp_CVE-2007-4129.dpatch -- A. Maitland Bottoms Mon, 03 Sep 2007 21:49:06 -0400 coolkey (1.1.0-2) unstable; urgency=low * debian/rules: install config.{config,guess} from autotools-dev Closes: #414457 "coolkey(GNU/k*BSD): FTBFS: out of date config.sub/config.guess" -- Ludovic Rousseau Sun, 18 Mar 2007 21:57:58 +0100 coolkey (1.1.0-1) unstable; urgency=low * New upstream release -- A. Maitland Bottoms Tue, 20 Feb 2007 20:19:34 -0500 coolkey (0.20061215-1) experimental; urgency=low * Mention all licenses from source in package copyright file * new upstream: - Some tokens do not support RSA_PKCS1_SHA1, use the NOPAD version and hand build the PKCS1 padding. - Remove reset and CUID reading for CAC. This was causing concurrent apps to loose login state. * Upload to unstable. (Closes: #400843) -- A. Maitland Bottoms Thu, 21 Dec 2006 20:38:11 -0500 coolkey (0.20061127-2) experimental; urgency=low * Update Build-Depends to include pkg-config -- A. Maitland Bottoms Wed, 29 Nov 2006 11:39:45 -0500 coolkey (0.20061127-1) experimental; urgency=low * Initial package. (Closes: #400843) -- A. Maitland Bottoms Tue, 28 Nov 2006 23:52:14 -0500 Local variables: add-log-mailing-address "bottoms@debian.org" End: debian/pk11install.10000644000000000000000000000244711617461503011426 0ustar .\" Copyright (c) 2006 .\" A. Maitland Bottoms .\" .Dd November 28, 2006 .Dt COOLKEY 1 .Os Debian .Sh NAME .Nm coolkey-pk11install .Nd Add Coolkey to Mozilla NSS .Sh SYNOPSIS .Nm coolkey-pk11install .Op Fl i .Op Fl u .Op Fl v .Op Fl p .Ar PATH .Pp Options are (i, install) (u, uninstall) (v, verbose) (p, path) .Sh INTRODUCTION .Nm coolkey-pk11install Handles placing the coolkey loadable modules in the right place for integration with web browsers and mail user agents that use Mozilla NSS. .Pp "pk11install is really a generic tool that probably should be moved to NSS (you can change the parameters and install any PKCS #11 module)." ... "It differs form modutil in that it doesn't try to load the module itself to install it. It also differs from modutil in that it 'knows' where several NSS apps store their database (OK, where old netscape and modern mozilla apps). You can run it as a user and install your favorite PKCS #11 module into all the browsers/mailreaders you have installed." - Bob Relyea, a coolkey developer. .Pp .Sh SUMMARY (Good luck) .Pp .Sh FILES None. It is up to the user to keep track of state when necessary. .Pp .Sh SEE ALSO .Xr mozilla 1 , .Sh HISTORY An LGPL licensed security module to allow Smart Card use. .Pp .Sh BUGS Maybe too many. .Pp .\" This bug is no longer: .\" No man page. debian/coolkey.manpages0000644000000000000000000000002511617461503012351 0ustar debian/pk11install.1 debian/compat0000644000000000000000000000000211740576454010401 0ustar 9 debian/coolkey.install0000644000000000000000000000014711617466700012235 0ustar src/coolkey/.libs/libcoolkeypk11.so usr/lib/pkcs11/ src/coolkey/.libs/libcoolkeypk11.a usr/lib/pkcs11/ debian/control0000644000000000000000000000272412271677227010613 0ustar Source: coolkey Section: admin Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: A. Maitland Bottoms Uploaders: Ludovic Rousseau Build-Depends: debhelper (>= 9~), autoconf, dh-autoreconf, pkg-config, zlib1g-dev, libpcsclite-dev, libnss3-dev, libnspr4-dev, dh-exec (>=0.3) Standards-Version: 3.9.3 Homepage: http://directory.fedoraproject.org/wiki/CoolKey Vcs-Browser: http://anonscm.debian.org/viewvc/pkg-coolkey/coolkey/trunk/ Vcs-Svn: svn://anonscm.debian.org/pkg-coolkey/coolkey/trunk Package: coolkey Architecture: any Depends: libckyapplet1 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, libpcsclite1 Recommends: libnss3-tools Description: Smart Card PKCS #11 cryptographic module Linux Driver support for the CoolKey and Common Access Card (CAC) smart card security keys used in a Public Key Infrastructure (PKI). The libpkcs11 module allows use of Smart Cards in applications that use mozilla Network Security Services (NSS). Package: libckyapplet1 Architecture: any Section: libs Depends: ${shlibs:Depends}, ${misc:Depends} Description: Smart Card Coolkey applet Protocol library for Coolkey applications. Package: libckyapplet1-dev Architecture: any Section: devel Depends: ${shlibs:Depends}, ${misc:Depends}, libckyapplet1 (= ${binary:Version}) Description: Smart Card Coolkey applet development files Header files and support for Coolkey applications. debian/patches/0000755000000000000000000000000012266514235010623 5ustar debian/patches/spelling-error-in-binary0000644000000000000000000000131711617461503015400 0ustar Description: fix spelling errors found by lintian Author: Ludovic Rousseau Last-Update: 2011-02-23 --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -129,7 +129,7 @@ if (numSlots > numReaders) { readerListLock.releaseLock(); throw PKCS11Exception(CKR_GENERAL_ERROR, - "Reader and slot count inconsistant\n"); + "Reader and slot count inconsistent\n"); } try { @@ -1974,7 +1974,7 @@ if (offset > size) { CKYBuffer_FreeData(&objBuffer); throw PKCS11Exception(CKR_DEVICE_ERROR, - "Inconsistant combined object data"); + "Inconsistent combined object data"); } CKYSize objSize = offset - start; CKYBuffer_Reserve(&info.data, objSize +1); debian/patches/coolkey-thread-fix.patch0000644000000000000000000001102112266506371015337 0ustar Description: Fix coolkey thread issues Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=4099f2251ffdf1e8be0e96ede91183557ba1aaba Author: Robert Relyea Date: Fri Dec 18 23:37:45 2009 +0000 SVN 86 https://fedorahosted.org/coolkey/changeset?reponame=&new=86%40%2F&old=85%40%2F Fix coolkey thread issues: 1) Coolkey returned errors when ever thread safety was requested, even though coolkey was thread safe. 2) Coolkey would hang if used with non-threaded applications which did not link with -lpthreads --- a/src/coolkey/coolkey.cpp +++ b/src/coolkey/coolkey.cpp @@ -42,7 +42,9 @@ static SlotList *slotList = NULL; -static OSLock finalizeLock(false); +static OSLock *finalizeLock = NULL; +#define FINALIZE_GETLOCK() if (finalizeLock) finalizeLock->getLock(); +#define FINALIZE_RELEASELOCK() if (finalizeLock) finalizeLock->releaseLock(); static CK_BBOOL initialized = FALSE; static CK_BBOOL finalizing = FALSE; @@ -208,11 +210,13 @@ if( initialized ) { return CKR_CRYPTOKI_ALREADY_INITIALIZED; } - if (!finalizeLock.isValid()) { + if (finalizeLock && !finalizeLock->isValid()) { return CKR_CANT_LOCK; } CK_C_INITIALIZE_ARGS* initArgs = (CK_C_INITIALIZE_ARGS*) pInitArgs; + OSLock::setThreadSafe(0); if( initArgs != NULL ) { + bool needThreads; /* work around a bug in NSS where the library parameters are only * send if locking is requested */ if (initArgs->LibraryParameters) { @@ -220,7 +224,17 @@ } else { Params::ClearParams(); } - if( (initArgs->flags & CKF_OS_LOCKING_OK) || initArgs->LockMutex ){ + needThreads = ((initArgs->flags & CKF_OS_LOCKING_OK) != 0); + OSLock::setThreadSafe(needThreads); + /* don't get a finalize lock unless someone initializes us asking + * us to use threads */ + if (needThreads && !finalizeLock) { + finalizeLock = new OSLock(true); + if (finalizeLock == NULL) return CKR_HOST_MEMORY; + } + /* only support OS LOCKING threads */ + if( ((initArgs->flags & CKF_OS_LOCKING_OK) == 0) + && initArgs->LockMutex ){ throw PKCS11Exception(CKR_CANT_LOCK); } } @@ -259,9 +273,9 @@ // the finalizing call first, we know it will set waitEvent before // we can get the lock, so we only need to protect setting finalizing // to true. - finalizeLock.getLock(); + FINALIZE_GETLOCK(); finalizing = TRUE; - finalizeLock.releaseLock(); + FINALIZE_RELEASELOCK(); if (waitEvent) { /* we're waiting on a slot event, shutdown first to allow * the wait function to complete before we pull the rug out. @@ -273,10 +287,10 @@ } delete slotList; delete log; - finalizeLock.getLock(); + FINALIZE_GETLOCK(); finalizing = FALSE; initialized = FALSE; - finalizeLock.releaseLock(); + FINALIZE_RELEASELOCK(); return CKR_OK; } @@ -595,17 +609,17 @@ CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) { - finalizeLock.getLock(); + FINALIZE_GETLOCK(); if( ! initialized ) { - finalizeLock.releaseLock(); + FINALIZE_RELEASELOCK(); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (finalizing) { - finalizeLock.releaseLock(); + FINALIZE_RELEASELOCK(); return CKR_CRYPTOKI_NOT_INITIALIZED; } waitEvent = TRUE; - finalizeLock.releaseLock(); + FINALIZE_RELEASELOCK(); try { log->log("C_WaitForSlotEvent called\n"); slotList->waitForSlotEvent(flags, pSlot, pReserved); --- a/src/coolkey/machdep.cpp +++ b/src/coolkey/machdep.cpp @@ -37,6 +37,8 @@ #include #endif +bool OSLock::needThread = 0; + #ifdef _WIN32 // // Windows functions to grab a named shared memory segment of a specific size, @@ -123,6 +125,10 @@ OSLock::OSLock(bool exceptionAllowed) { + if (!needThread) { + lockData = NULL; + return; + } lockData = new OSLockData; if (lockData) { InitializeCriticalSection(&lockData->mutex); @@ -439,6 +445,9 @@ int rc; lockData = NULL; + if (!needThread) { + return; + } #ifdef MAC if (!OSLock_attr_init) { rc = pthread_mutexattr_init(&OSLock_attr); --- a/src/coolkey/machdep.h +++ b/src/coolkey/machdep.h @@ -40,12 +40,14 @@ class OSLock { private: OSLockData *lockData; + static bool needThread; public: OSLock(bool exceptionAllowed = true); ~OSLock(); bool isValid(); void getLock(); void releaseLock(); + static void setThreadSafe(bool thread) { needThread = thread; } }; typedef unsigned long OSTime; debian/patches/coolkey-cac-1.patch0000644000000000000000000000136012266506371014175 0ustar Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=36791f8443da484b1d52c0e33db7496d4a100d33 Description: Cac card crash fix, #606842. Author: Jack Magne --- a/src/coolkey/object.cpp +++ b/src/coolkey/object.cpp @@ -505,6 +505,10 @@ unsigned char tag; unsigned int used_length= 0; + if(!buf) { + return NULL; + } + tag = buf[used_length++]; /* blow out when we come to the end */ --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -2192,6 +2192,10 @@ if (throwException && (status != CKYSUCCESS)) { handleConnectionError(); } + + if(CKYBuffer_Size(cert) == 0) { + handleConnectionError(); + } return status; } debian/patches/coolkey-cac-rhl5.patch0000644000000000000000000007447712266506371014732 0ustar Date: Wed Jul 20 2010 Robert Relyea - 1.1.0-15 Description: work with new piv-like CAC cards Author: Robert Relyea Last-Update: 2011-01-13 http://rhn.redhat.com/errata/RHEA-2011-0111.html * The coolkey package provides support for CoolKey and Common Access Card (CAC) smart card products. * The coolkey device driver has been updated to follow the new Card Compatibility Container (CCC) specification, so that Gemalto TOPDLGX4 144K CAC cards are now supported. (BZ#593017) --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -372,7 +372,7 @@ : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL), slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), isVersion1Key(false), needLogin(false), fullTokenName(false), - mCoolkey(false), + mCoolkey(false), mOldCAC(false), #ifdef USE_SHMEM shmem(readerName_), #endif @@ -412,6 +412,9 @@ } CKYBuffer_InitEmpty(&cardATR); CKYBuffer_InitEmpty(&mCUID); + for (int i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_InitEmpty(&cardAID[i]); + } } catch(PKCS11Exception &) { if (conn) { CKYCardConnection_Destroy(conn); @@ -479,6 +482,9 @@ CKYBuffer_FreeData(&nonce); CKYBuffer_FreeData(&cardATR); CKYBuffer_FreeData(&mCUID); + for (int i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_FreeData(&cardAID[i]); + } } template @@ -583,6 +589,7 @@ if( ! CKYCardConnection_IsConnected(conn) ) { int i = 0; //for cranky readers try again a few more times + status = CKYSCARDERR; while( i++ < 5 && status != CKYSUCCESS ) { status = CKYCardConnection_Connect(conn, readerName); @@ -671,12 +678,12 @@ status = CKYApplet_SelectCoolKeyManager(conn, NULL); if (status != CKYSUCCESS) { log->log("CoolKey Select failed 0x%x\n", status); - status = CACApplet_SelectPKI(conn, 0, NULL); + status = getCACAid(); if (status != CKYSUCCESS) { - log->log("CAC Select failed 0x%x\n", status); + log->log("CAC Select failed 0x%x\n", status); if (status == CKYSCARDERR) { - log->log("CAC Card Failure 0x%x\n", - CKYCardConnection_GetLastError(conn)); + log->log("CAC Card Failure 0x%x\n", + CKYCardConnection_GetLastError(conn)); disconnect(); } return; @@ -771,17 +778,111 @@ invalidateLogin(false); } +CKYStatus +Slot::getCACAid() +{ + CKYBuffer tBuf; + CKYBuffer vBuf; + CKYSize tlen, vlen; + CKYOffset toffset, voffset; + int certSlot = 0; + int i,length = 0; + CKYStatus status; + + CKYBuffer_InitEmpty(&tBuf); + CKYBuffer_InitEmpty(&vBuf); + + /* clear out the card AID's */ + for (i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_Resize(&cardAID[i],0); + } + + status = CACApplet_SelectCCC(conn,NULL); + if (status != CKYSUCCESS) { + /* are we an old CAC */ + status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL); + if (status != CKYSUCCESS) { + /* no, just fail */ + return status; + } + /* yes, fill in the old applets */ + mOldCAC = true; + for (i=1; i< MAX_CERT_SLOTS; i++) { + CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); + } + return CKYSUCCESS; + } + /* definately not an old CAC */ + mOldCAC = false; + + /* read the TLV */ + status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + tlen = CKYBuffer_Size(&tBuf); + vlen = CKYBuffer_Size(&vBuf); + + for(toffset = 2, voffset=2; + certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ; + voffset += length) { + + CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset); + length = CKYBuffer_GetChar(&tBuf, toffset+1); + toffset += 2; + if (length == 0xff) { + length = CKYBuffer_GetShortLE(&tBuf, toffset); + toffset +=2; + } + if (tag != CAC_TAG_CARDURL) { + continue; + } + /* CARDURL tags must be at least 10 bytes long */ + if (length < 10) { + continue; + } + /* check the app type, should be TLV_APP_PKI */ + if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) { + continue; + } + status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5); + if (status != CKYSUCCESS) { + goto done; + } + status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, + voffset+8, 2); + if (status != CKYSUCCESS) { + goto done; + } + cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6); + + certSlot++; + } + status = CKYSUCCESS; + if (certSlot == 0) { + status = CKYAPDUFAIL; /* probably neeed a beter error code */ + } + +done: + CKYBuffer_FreeData(&tBuf); + CKYBuffer_FreeData(&vBuf); + return status; +} + void Slot::refreshTokenState() { if( cardStateMayHaveChanged() ) { -log->log("card changed\n"); + log->log("card changed\n"); invalidateLogin(true); closeAllSessions(); unloadObjects(); connectToToken(); - if( state & APPLET_PERSONALIZED ) { try { loadObjects(); @@ -1019,7 +1120,7 @@ struct _manList { unsigned short type; - char *string; + const char *string; }; static const struct _manList manList[] = { @@ -1280,13 +1381,30 @@ Slot::selectCACApplet(CKYByte instance) { CKYStatus status; - status = CACApplet_SelectPKI(conn, instance, NULL); + CKYBuffer *aid = &cardAID[instance]; + + if (CKYBuffer_Size(aid) == 0) { + disconnect(); + throw PKCS11Exception(CKR_DEVICE_REMOVED); + return; + } + + status = CKYApplet_SelectFile(conn, aid, NULL); if ( status == CKYSCARDERR ) handleConnectionError(); if ( status != CKYSUCCESS) { // could not select applet: this just means it's not there disconnect(); throw PKCS11Exception(CKR_DEVICE_REMOVED); } + if (mOldCAC) { + return; + } + status = CACApplet_SelectFile(conn, cardEF[instance], NULL); + if ( status == CKYSCARDERR ) handleConnectionError(); + if ( status != CKYSUCCESS) { + disconnect(); + throw PKCS11Exception(CKR_DEVICE_REMOVED); + } } // assume we are already in a transaction void @@ -2059,10 +2177,90 @@ return objInfoList; } +CKYStatus +Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, + bool throwException) +{ + CKYStatus status; + CKYISOStatus apduRC; + *nextSize = 0; + + if (mOldCAC) { + /* get the first 100 bytes of the cert */ + status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); + if (throwException && (status != CKYSUCCESS)) { + handleConnectionError(); + } + + if(CKYBuffer_Size(cert) == 0) { + handleConnectionError(); + } + return status; + } + + CKYBuffer tBuf; + CKYBuffer vBuf; + CKYSize tlen, vlen; + CKYOffset toffset, voffset; + int length = 0; + + CKYBuffer_InitEmpty(&tBuf); + CKYBuffer_InitEmpty(&vBuf); + CKYBuffer_Resize(cert, 0); + + /* handle the new CAC card read */ + /* read the TLV */ + status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + tlen = CKYBuffer_Size(&tBuf); + vlen = CKYBuffer_Size(&vBuf); + + /* look for the Cert out of the TLV */ + for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ; + voffset += length) { + + CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset); + length = CKYBuffer_GetChar(&tBuf, toffset+1); + toffset += 2; + if (length == 0xff) { + length = CKYBuffer_GetShortLE(&tBuf, toffset); + toffset +=2; + } + if (tag != CAC_TAG_CERTIFICATE) { + continue; + } + CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length); + break; + } + status = CKYSUCCESS; + +done: + CKYBuffer_FreeData(&tBuf); + CKYBuffer_FreeData(&vBuf); + return status; +} + +/* + * only necessary for old CAC cards. New CAC cards have to read the + * whole cert in anyway above.... + */ +CKYStatus +Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize) +{ + CKYISOStatus apduRC; + assert(mOldCAC); + return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC); +} + void Slot::loadCACCert(CKYByte instance) { - CKYISOStatus apduRC; CKYStatus status = CKYSUCCESS; CKYBuffer cert; CKYBuffer rawCert; @@ -2097,12 +2295,7 @@ instance, OSTimeNow() - time); if (instance == 0) { - /* get the first 100 bytes of the cert */ - status = CACApplet_GetCertificateFirst(conn, &rawCert, - &nextSize, &apduRC); - if (status != CKYSUCCESS) { - handleConnectionError(); - } + readCACCertificateFirst(&rawCert, &nextSize, true); log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", instance, OSTimeNow() - time); } @@ -2143,8 +2336,7 @@ shmem.setVersion(SHMEM_VERSION); shmem.setDataVersion(dataVersion); } else { - status = CACApplet_GetCertificateFirst(conn, &rawCert, - &nextSize, &apduRC); + status = readCACCertificateFirst(&rawCert, &nextSize, false); if (status != CKYSUCCESS) { /* CAC only requires the Certificate in pki '0' */ @@ -2159,8 +2351,7 @@ } if (nextSize) { - status = CACApplet_GetCertificateAppend(conn, &rawCert, - nextSize, &apduRC); + status = readCACCertificateAppend(&rawCert, nextSize); } log->log("CAC Cert %d: Fetch rest : %d ms\n", instance, OSTimeNow() - time); @@ -2176,9 +2367,10 @@ log->log("CAC Cert %d: Cert has been read: %d ms\n", instance, OSTimeNow() - time); - if (CKYBuffer_GetChar(&rawCert,0) == 1) { + if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) { CKYSize guessFinalSize = CKYBuffer_Size(&rawCert); CKYSize certSize = 0; + CKYOffset offset = mOldCAC ? 1 : 0; int zret = Z_MEM_ERROR; do { @@ -2189,7 +2381,8 @@ } certSize = guessFinalSize; zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize, - CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1); + CKYBuffer_Data(&rawCert)+offset, + CKYBuffer_Size(&rawCert)-offset); } while (zret == Z_BUF_ERROR); if (zret != Z_OK) { @@ -2526,7 +2719,7 @@ switch( result ) { case CKYISO_SUCCESS: break; - case 6981: + case 0x6981: throw PKCS11Exception(CKR_PIN_LOCKED); default: if ((result & 0xff00) == 0x6300) { @@ -3205,6 +3398,10 @@ status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction, input, NULL, output, getNonce(), &result); } + /* map the ISO not logged in code to the coolkey one */ + if (status == CKYISO_CONDITION_NOT_SATISFIED) { + status = (CKYStatus) CKYISO_UNAUTHORIZED; + } if (status != CKYSUCCESS) { if ( status == CKYSCARDERR ) { handleConnectionError(); --- a/src/coolkey/slot.h +++ b/src/coolkey/slot.h @@ -294,6 +294,7 @@ const CKYBuffer *paddedOutput) const = 0; }; +#define MAX_CERT_SLOTS 3 class Slot { public: @@ -328,6 +329,8 @@ CKYBuffer nonce; CKYBuffer cardATR; CKYBuffer mCUID; + CKYBuffer cardAID[MAX_CERT_SLOTS]; + unsigned short cardEF[MAX_CERT_SLOTS]; bool isVersion1Key; bool needLogin; long publicFree; @@ -335,6 +338,7 @@ long privateFree; bool fullTokenName; bool mCoolkey; + bool mOldCAC; //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 }; @@ -398,6 +402,11 @@ list fetchCombinedObjects(const CKYBuffer *header); list fetchSeparateObjects(); + CKYStatus getCACAid(); + CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, + bool throwException); + CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); + void selectApplet(); void selectCACApplet(CKYByte instance); void unloadObjects(); --- a/src/libckyapplet/cky_applet.c +++ b/src/libckyapplet/cky_applet.c @@ -41,7 +41,13 @@ CKYStatus CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param) { - return CKYAPDUFactory_SelectFile(apdu,(const CKYBuffer *)param); + return CKYAPDUFactory_SelectFile(apdu, 4, 0, (const CKYBuffer *)param); +} + +CKYStatus +CACAppletFactory_SelectFile(CKYAPDU *apdu, const void *param) +{ + return CKYAPDUFactory_SelectFile(apdu, 2, 12, (const CKYBuffer *)param); } CKYStatus @@ -225,10 +231,17 @@ } CKYStatus -CACAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param) +CACAppletFactory_SignDecryptStep(CKYAPDU *apdu, const void *param) +{ + const CKYBuffer *buf=(CKYBuffer *)param; + return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_STEP, buf); +} + +CKYStatus +CACAppletFactory_SignDecryptFinal(CKYAPDU *apdu, const void *param) { const CKYBuffer *buf=(CKYBuffer *)param; - return CACAPDUFactory_SignDecrypt(apdu, buf); + return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_FINAL, buf); } CKYStatus @@ -246,6 +259,13 @@ } CKYStatus +CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param) +{ + const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param; + return CACAPDUFactory_ReadFile(apdu, rfs->offset, rfs->type, rfs->count); +} + +CKYStatus CACAppletFactory_GetProperties(CKYAPDU *apdu, const void *param) { return CACAPDUFactory_GetProperties(apdu); @@ -457,7 +477,7 @@ CKYISOStatus *apduRC) { return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, AID, NULL, - 0, CKYAppletFill_Null, NULL, apduRC); + CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); } static CKYByte coolkeyid[] = {0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00 }; @@ -477,22 +497,23 @@ return ret; } -static CKYByte CACPKIid[] = {0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; +static CKYByte CACPKIid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01 }; /* * Select the CoolKey applet. Must happen after we start a transaction and * before we issue any applet specific command. */ CKYStatus -CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, - CKYISOStatus *apduRC) +CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cacAID, + CKYByte instance, CKYISOStatus *apduRC) { CKYStatus ret; - CKYBuffer CACPKIAID; - CKYBuffer_InitFromData(&CACPKIAID, CACPKIid, sizeof(CACPKIid)); - CKYBuffer_SetChar(&CACPKIAID, 6, instance); - ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CACPKIAID, + CKYBuffer_AppendData(cacAID, CACPKIid, sizeof(CACPKIid)); + CKYBuffer_AppendChar(cacAID, instance); + ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, cacAID, NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); - CKYBuffer_FreeData(&CACPKIAID); + if (ret != CKYSUCCESS) { + CKYBuffer_Resize(cacAID, 0); + } return ret; } @@ -515,11 +536,38 @@ CKYBuffer CAC_CM_AID; CKYBuffer_InitFromData(&CAC_CM_AID, cacmgrid, sizeof(cacmgrid)); ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID, - NULL, 0, CKYAppletFill_Null, NULL, apduRC); + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); CKYBuffer_FreeData(&CAC_CM_AID); return ret; } +static CKYByte cacCCCid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00 }; +CKYStatus +CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYBuffer CAC_CM_AID; + CKYBuffer_InitFromData(&CAC_CM_AID, cacCCCid, sizeof(cacCCCid)); + ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID, + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); + CKYBuffer_FreeData(&CAC_CM_AID); + return ret; +} + +CKYStatus +CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef, + CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYBuffer efBuf; + CKYBuffer_InitEmpty(&efBuf); + CKYBuffer_AppendShortLE(&efBuf, ef); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SelectFile, &efBuf, + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); + CKYBuffer_FreeData(&efBuf); + return ret; +} + /* * GetCPLC cluster -- must be called with CM selected */ @@ -673,8 +721,8 @@ ccd.keyNumber = keyNumber; ccd.location = location; ccd.data = data; - return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, &ccd, - nonce, 0, CKYAppletFill_Null, NULL, apduRC); + return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, + &ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC); } /* computeCrypt returns data in the form : @@ -832,11 +880,39 @@ CKYBuffer *result, CKYISOStatus *apduRC) { CKYStatus ret; - - ret = CKYApplet_HandleAPDU(conn, - CACAppletFactory_SignDecrypt, data, NULL, - CKYBuffer_Size(data), CKYAppletFill_ReplaceBuffer, + CKYSize dataSize = CKYBuffer_Size(data); + CKYOffset offset = 0; + CKYBuffer tmp; + + CKYBuffer_InitEmpty(&tmp); + + CKYBuffer_Resize(result, 0); + for(offset = 0; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; + offset += CKY_MAX_WRITE_CHUNK_SIZE) { + CKYBuffer_Resize(&tmp,0); + CKYBuffer_AppendBuffer(&tmp, data, offset, CKY_MAX_WRITE_CHUNK_SIZE); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptStep, + &tmp, NULL, CKY_SIZE_UNKNOWN, + CKYAppletFill_AppendBuffer, result, apduRC); + if (ret != CKYSUCCESS) { + goto done; + } + } + CKYBuffer_Resize(&tmp,0); + CKYBuffer_AppendBuffer(&tmp, data, offset, dataSize - offset); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptFinal, + &tmp, NULL, CKY_SIZE_UNKNOWN, + CKYAppletFill_AppendBuffer, + result, apduRC); + + if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != dataSize)) { + /* RSA returns the same data size as input, didn't happen, so + * something is wrong. */ + } + +done: + CKYBuffer_FreeData(&tmp); return ret; } @@ -895,6 +971,63 @@ } return ret; } + +/* + * Read a CAC Tag/Value file + */ +CKYStatus +CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, CKYBuffer *buffer, + CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYISOStatus status; + CKYByte maxtransfer; + unsigned short offset = 0; + unsigned short size; + CACAppletArgReadFile rfs; + + CKYBuffer_Resize(buffer,0); + if (apduRC == NULL) { + apduRC = &status; + } + rfs.offset = 0; + rfs.count = 2; + rfs.type = type; + + /* APDU's are expensive, Grab a big chunk of the file first if possible */ + ret = CKYApplet_HandleAPDU(conn, + CACAppletFactory_ReadFile, &rfs, NULL, + rfs.count, CKYAppletFill_AppendBuffer, + buffer, apduRC); + /* file is probably smaller than 100 bytes, get the actual size first */ + if (ret != CKYSUCCESS) { + return ret; + } + size = CKYBuffer_GetShortLE(buffer, 0) + 2 /* include the length itself */; + maxtransfer = CKY_MAX_READ_CHUNK_SIZE; + /* get the rest of the buffer if necessary */ + for (offset = CKYBuffer_Size(buffer); size > offset; + offset = CKYBuffer_Size(buffer)) { + rfs.offset = offset; + rfs.count = MIN(size - offset, maxtransfer); + ret = CKYApplet_HandleAPDU(conn, + CACAppletFactory_ReadFile, &rfs, NULL, + rfs.count, CKYAppletFill_AppendBuffer, + buffer, apduRC); + if (ret != CKYSUCCESS) { + if (*apduRC == CAC_INVALID_PARAMS) { + maxtransfer = maxtransfer/2; + if (maxtransfer == 0) { + return ret; + } + } else { + return ret; + } + } + } + return ret; +} + CKYStatus CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, CKYSize *nextSize, CKYISOStatus *apduRC) --- a/src/libckyapplet/cky_applet.h +++ b/src/libckyapplet/cky_applet.h @@ -43,6 +43,7 @@ #define CKYISO_MORE_MASK 0xff00 /* More data mask */ #define CKYISO_MORE 0x6300 /* More data available */ #define CKYISO_DATA_INVALID 0x6984 +#define CKYISO_CONDITION_NOT_SATISFIED 0x6985 /* AKA not logged in */ /* Applet Defined Return codes */ #define CKYISO_NO_MEMORY_LEFT 0x9c01 /* There have been memory * problems on the card */ @@ -71,6 +72,15 @@ #define CKYISO_INTERNAL_ERROR 0x9cff /* Reserved for debugging, * shouldn't happen */ +#define CAC_INVALID_PARAMS 0x6a83 +#define CAC_TAG_FILE 1 +#define CAC_VALUE_FILE 2 + + +#define CAC_TAG_CARDURL 0xf3 +#define CAC_TAG_CERTIFICATE 0x70 +#define CAC_TLV_APP_PKI 0x04 + /* * Pin Constants as used by our applet */ @@ -209,6 +219,12 @@ const CKYBuffer *sig; } CKYAppletArgComputeCrypt; +typedef struct _CACAppletArgReadFile { + CKYByte type; + CKYByte count; + unsigned short offset; +} CACAppletArgReadFile; + /* fills in an APDU from a structure -- form of all the generic factories*/ typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param); /* fills in an a structure from a response -- form of all the fill structures*/ @@ -451,9 +467,17 @@ /* Select the CAC card manager. Can happen with either applet selected */ CKYStatus CACApplet_SelectCardManager(CKYCardConnection *conn, CKYISOStatus *apduRC); -/* Can happen with either applet selected */ -CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, - CKYISOStatus *apduRC); +/* Select the CAC CC container. Can happen with either applet selected */ +CKYStatus CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC); +/* Select an old CAC applet and fill in the cardAID */ +CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cardAid, + CKYByte instance, CKYISOStatus *apduRC); +/* read a TLV file */ +CKYStatus CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, + CKYBuffer *buffer, CKYISOStatus *apduRC); +CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef, + CKYISOStatus *apduRC); + /* must happen with PKI applet selected */ CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC); --- a/src/libckyapplet/cky_base.c +++ b/src/libckyapplet/cky_base.c @@ -220,6 +220,22 @@ return CKYSUCCESS; } +/* append a short in network order */ +CKYStatus +CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val) +{ + CKYStatus ret; + + ret = CKYBuffer_Reserve(buf, buf->len + 2); + if (ret != CKYSUCCESS) { + return ret; + } + buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff); + buf->len += 2; + return CKYSUCCESS; +} + /* append a long in applet order */ CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val) @@ -238,6 +254,24 @@ return CKYSUCCESS; } +/* append a long in applet order */ +CKYStatus +CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val) +{ + CKYStatus ret; + + ret = CKYBuffer_Reserve(buf, buf->len + 4); + if (ret != CKYSUCCESS) { + return ret; + } + buf->data[buf->len+3] = (CKYByte) ((val >> 24) & 0xff); + buf->data[buf->len+2] = (CKYByte) ((val >> 16) & 0xff); + buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff); + buf->len += 4; + return CKYSUCCESS; +} + CKYStatus CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data, CKYSize len) { @@ -351,6 +385,22 @@ } CKYStatus +CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val) +{ + CKYStatus ret; + + if (buf->len < offset+2) { + ret = CKYBuffer_Resize(buf,offset+2); + if (ret != CKYSUCCESS) { + return ret; + } + } + buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff); + return CKYSUCCESS; +} + +CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val) { CKYStatus ret; @@ -368,6 +418,24 @@ return CKYSUCCESS; } +CKYStatus +CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val) +{ + CKYStatus ret; + + if (buf->len < offset+4) { + ret = CKYBuffer_Resize(buf,offset+4); + if (ret != CKYSUCCESS) { + return ret; + } + } + buf->data[offset+3] = (CKYByte) ((val >> 24) & 0xff); + buf->data[offset+2] = (CKYByte) ((val >> 16) & 0xff); + buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff); + return CKYSUCCESS; +} + CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset) { @@ -388,6 +456,18 @@ val |= ((unsigned short)buf->data[offset+1]) << 0; return val; } + +unsigned short +CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset) +{ + unsigned short val; + if (buf->len < offset+2) { + return 0; + } + val = ((unsigned short)buf->data[offset+1]) << 8; + val |= ((unsigned short)buf->data[offset+0]) << 0; + return val; +} unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset) @@ -402,6 +482,20 @@ val |= ((unsigned long)buf->data[offset+3]) << 0; return val; } + +unsigned long +CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset) +{ + unsigned long val; + if (buf->len < offset+4) { + return 0; + } + val = ((unsigned long)buf->data[offset+3]) << 24; + val |= ((unsigned long)buf->data[offset+2]) << 16; + val |= ((unsigned long)buf->data[offset+1]) << 8; + val |= ((unsigned long)buf->data[offset+0]) << 0; + return val; +} CKYStatus CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen) --- a/src/libckyapplet/cky_base.h +++ b/src/libckyapplet/cky_base.h @@ -170,9 +170,15 @@ /* append a short in applet order */ CKYStatus CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val); +/* append a short in little endian order */ +CKYStatus CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val); + /* append a long in applet order */ CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val); +/* append a long in little endian order */ +CKYStatus CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val); + /* append data. the data starts at data and extends len bytes */ CKYStatus CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len); @@ -210,12 +216,18 @@ CKYStatus CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val); CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val); +/* These functions work in little endian order */ +CKYStatus CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val); +CKYStatus CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val); /* read a character from offset. If offset is beyond the end of the buffer, * then the function returns '0' */ CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset); /* These functions work in applet order */ unsigned short CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset); unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset); +/* These functions work in little endian order */ +unsigned short CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset); +unsigned long CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset); /* clear out all the data in a buffer */ void CKYBuffer_Zero(CKYBuffer *buf); --- a/src/libckyapplet/cky_factory.c +++ b/src/libckyapplet/cky_factory.c @@ -25,12 +25,13 @@ * special commands can be issued at any time */ CKYStatus -CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID) +CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2, + const CKYBuffer *AID) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE); - CKYAPDU_SetP1(apdu, 0x04); - CKYAPDU_SetP2(apdu, 0x00); + CKYAPDU_SetP1(apdu, p1); + CKYAPDU_SetP2(apdu, p2); return CKYAPDU_SetSendDataBuffer(apdu, AID); } @@ -131,6 +132,7 @@ return ret; } + CKYStatus CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber, CKYByte location, const CKYBuffer *data, const CKYBuffer *sig) @@ -572,11 +574,11 @@ } CKYStatus -CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data) +CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, const CKYBuffer *data) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); CKYAPDU_SetINS(apdu, CAC_INS_SIGN_DECRYPT); - CKYAPDU_SetP1(apdu, 0x00); + CKYAPDU_SetP1(apdu, type); CKYAPDU_SetP2(apdu, 0x00); return CKYAPDU_SetSendDataBuffer(apdu, data); } @@ -592,6 +594,36 @@ } CKYStatus +CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, + CKYByte type, CKYByte count) +{ + CKYStatus ret; + CKYBuffer buf; + + CKYBuffer_InitEmpty(&buf); + CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM); + CKYAPDU_SetINS(apdu, CAC_INS_READ_FILE); + CKYAPDU_SetP1(apdu, (offset >> 8) & 0xff); + CKYAPDU_SetP2(apdu, offset & 0xff); + ret = CKYBuffer_Reserve(&buf, 2); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendChar(&buf, type); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendChar(&buf, count); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYAPDU_SetSendDataBuffer(apdu, &buf); +fail: + CKYBuffer_FreeData(&buf); + return ret; +} + +CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); --- a/src/libckyapplet/cky_factory.h +++ b/src/libckyapplet/cky_factory.h @@ -86,7 +86,11 @@ #define CAC_INS_SIGN_DECRYPT 0x42 #define CAC_INS_VERIFY_PIN 0x20 #define CAC_INS_GET_PROPERTIES 0x56 +#define CAC_INS_READ_FILE 0x52 + #define CAC_SIZE_GET_PROPERTIES 48 +#define CAC_P1_STEP 0x80 +#define CAC_P1_FINAL 0x00 /* * Fixed return sized from various commands @@ -169,7 +173,8 @@ CKY_BEGIN_PROTOS /* function based factorys */ -CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID); +CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2, + const CKYBuffer *AID); CKYStatus CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence); @@ -211,9 +216,12 @@ CKYStatus CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu); -CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data); +CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, + const CKYBuffer *data); CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin); CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size); +CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, + CKYByte type, CKYByte count); CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu); CKY_END_PROTOS debian/patches/coolkey-pcsc-lite0000644000000000000000000000567012266506371014106 0ustar Description: fix compiler errors using recent pcsc-lite Author: Ludovic Rousseau Last-Update: 2011-03-27 --- a/src/libckyapplet/cky_card.h +++ b/src/libckyapplet/cky_card.h @@ -41,23 +41,23 @@ CKYLIST_DECLARE(CKYCardConnection, CKYCardConnection *) CKY_BEGIN_PROTOS -void CKYReader_Init(SCARD_READERSTATE_A *reader); -void CKYReader_FreeData(SCARD_READERSTATE_A *reader); +void CKYReader_Init(SCARD_READERSTATE *reader); +void CKYReader_FreeData(SCARD_READERSTATE *reader); /* - * "Accessors": for SCARD_READERSTATE_A structure as a class. - * These functions take an SCARD_READERSTATE_A which can also be referenced + * "Accessors": for SCARD_READERSTATE structure as a class. + * These functions take an SCARD_READERSTATE which can also be referenced * directly. */ -CKYStatus CKYReader_SetReaderName(SCARD_READERSTATE_A *reader, const char *name); -const char *CKYReader_GetReaderName(const SCARD_READERSTATE_A *reader); -CKYStatus CKYReader_SetKnownState(SCARD_READERSTATE_A *reader, +CKYStatus CKYReader_SetReaderName(SCARD_READERSTATE *reader, const char *name); +const char *CKYReader_GetReaderName(const SCARD_READERSTATE *reader); +CKYStatus CKYReader_SetKnownState(SCARD_READERSTATE *reader, unsigned long state); -unsigned long CKYReader_GetKnownState(const SCARD_READERSTATE_A *reader); -unsigned long CKYReader_GetEventState(const SCARD_READERSTATE_A *reader); -CKYStatus CKYReader_GetATR(const SCARD_READERSTATE_A *reader, CKYBuffer *buf); +unsigned long CKYReader_GetKnownState(const SCARD_READERSTATE *reader); +unsigned long CKYReader_GetEventState(const SCARD_READERSTATE *reader); +CKYStatus CKYReader_GetATR(const SCARD_READERSTATE *reader, CKYBuffer *buf); /* create an array of READERSTATEs from a LIST of Readers */ -SCARD_READERSTATE_A *CKYReader_CreateArray(const CKYReaderNameList readerNames, +SCARD_READERSTATE *CKYReader_CreateArray(const CKYReaderNameList readerNames, unsigned long *readerCount); /* frees the reader, then the full array */ void CKYReader_DestroyArray(SCARD_READERSTATE *reader, unsigned long count); @@ -88,7 +88,7 @@ const CKYBuffer *targetATR); /* return if any of the readers in our array has changed in status */ CKYStatus CKYCardContext_WaitForStatusChange(CKYCardContext *context, - SCARD_READERSTATE_A *readers, + SCARD_READERSTATE *readers, unsigned long readerCount, unsigned long timeout); /* cancel any current operation (such as wait for status change) on this --- a/src/libckyapplet/cky_card.c +++ b/src/libckyapplet/cky_card.c @@ -27,7 +27,6 @@ #ifndef WINAPI #define WINAPI -typedef SCARD_READERSTATE *LPSCARD_READERSTATE; #endif #ifndef SCARD_E_NO_READERS_AVAILABLE @@ -108,7 +107,7 @@ typedef long (WINAPI * SCardGetStatusChangeFn) ( SCARDCONTEXT hContext, unsigned long dwTimeout, - LPSCARD_READERSTATE rgReaderStates, + SCARD_READERSTATE *rgReaderStates, unsigned long cReaders); typedef long (WINAPI * SCardCancelFn) ( debian/patches/Handle-pcscd-restarting0000644000000000000000000000543712266506371015226 0ustar Description: Handle pcscd restarting. Author: rrelyea Date: Wed Jul 13 22:19:42 2011 +0000 Origin: https://fedorahosted.org/coolkey/changeset?reponame=&new=95%40%2F&old=94%40%2F svn.fedorahosted.org/svn/coolkey@95 --- a/src/libckyapplet/cky_card.c +++ b/src/libckyapplet/cky_card.c @@ -843,6 +843,11 @@ rv = ctx->scard->SCardGetStatusChange(ctx->context, timeout, readers, readerCount); if (rv != SCARD_S_SUCCESS) { + if ((rv == SCARD_E_NO_SERVICE) || (rv == SCARD_E_SERVICE_STOPPED)) { + /* if we were stopped, don't reuse the old context, + * pcsc-lite hangs */ + ckyCardContext_release(ctx); + } ctx->lastError = rv; return CKYSCARDERR; } --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -237,9 +237,14 @@ CKYStatus status = CKYCardContext_ListReaders(context, &readerNames); if ( status != CKYSUCCESS ) { - throw PKCS11Exception(CKR_GENERAL_ERROR, - "Failed to list readers: 0x%x\n", - CKYCardContext_GetLastError(context)); + /* if the service is stopped, treat it as if we have no readers */ + if ((CKYCardContext_GetLastError(context) != SCARD_E_NO_SERVICE) && + (CKYCardContext_GetLastError(context) != SCARD_E_SERVICE_STOPPED)) { + throw PKCS11Exception(CKR_GENERAL_ERROR, + "Failed to list readers: 0x%x\n", + CKYCardContext_GetLastError(context)); + } + } if (!readerStates) { @@ -1282,7 +1287,9 @@ #endif } while ((status == CKYSUCCESS) || (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) || - ( CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE)); + (CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE) || + (CKYCardContext_GetLastError(context) == SCARD_E_NO_SERVICE) || + (CKYCardContext_GetLastError(context) == SCARD_E_SERVICE_STOPPED) ); #else do { OSSleep(100); @@ -3398,10 +3405,12 @@ status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction, input, NULL, output, getNonce(), &result); } +#ifdef notdef /* CAC pin cachine is incomplete, don't enable it */ /* map the ISO not logged in code to the coolkey one */ if (status == CKYISO_CONDITION_NOT_SATISFIED) { status = (CKYStatus) CKYISO_UNAUTHORIZED; } +#endif if (status != CKYSUCCESS) { if ( status == CKYSCARDERR ) { handleConnectionError(); --- a/src/coolkey/Makefile.am +++ b/src/coolkey/Makefile.am @@ -64,7 +64,7 @@ # coreconf .def file to a simplistic but acceptable libtool .sym file # coolkeypk11.sym: coolkeypk11.def - grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@ + grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' | grep -v '^$$'> $@ clean-generic: rm -f coolkeypk11.sym debian/patches/coolkey-gcc43.patch0000644000000000000000000000243712266506371014222 0ustar Description: Fix for gcc 4.3, bug#427666, rev. rrelyea. Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=57d00878ae19f39b297c3dd410a791a54a50cd90 Reviewed-by: Jack Magne Date: Thu Feb 14 23:51:04 2008 +0000 https://fedorahosted.org/coolkey/browser/?rev=72 Fix for gcc 4.3, bug#427666, rev. rrelyea. --- a/src/coolkey/log.cpp +++ b/src/coolkey/log.cpp @@ -18,6 +18,8 @@ * ***** END COPYRIGHT BLOCK *****/ #include +#include +#include #include "mypkcs11.h" #include #include --- a/src/coolkey/machdep.cpp +++ b/src/coolkey/machdep.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #endif #ifdef _WIN32 --- a/src/coolkey/object.cpp +++ b/src/coolkey/object.cpp @@ -21,6 +21,7 @@ #include "PKCS11Exception.h" #include "object.h" #include +#include using std::find_if; --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -25,7 +25,6 @@ #include "PKCS11Exception.h" #include #include "slot.h" -#include #include "zlib.h" #include "params.h" @@ -33,7 +32,6 @@ #define MIN(x, y) ((x) < (y) ? (x) : (y)) -using std::auto_ptr; #ifdef DEBUG debian/patches/coolkey-cac.patch0000644000000000000000000007225212266506371014047 0ustar Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=b9b0c7ddc389a55bdc265500bb857c2794a9a06a Author: Robert Relyea Description: Better CAC support. SVN rev 87 New CAC support --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -372,7 +372,7 @@ : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL), slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), isVersion1Key(false), needLogin(false), fullTokenName(false), - mCoolkey(false), + mCoolkey(false), mOldCAC(false), #ifdef USE_SHMEM shmem(readerName_), #endif @@ -412,6 +412,9 @@ } CKYBuffer_InitEmpty(&cardATR); CKYBuffer_InitEmpty(&mCUID); + for (int i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_InitEmpty(&cardAID[i]); + } } catch(PKCS11Exception &) { if (conn) { CKYCardConnection_Destroy(conn); @@ -479,6 +482,9 @@ CKYBuffer_FreeData(&nonce); CKYBuffer_FreeData(&cardATR); CKYBuffer_FreeData(&mCUID); + for (int i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_FreeData(&cardAID[i]); + } } template @@ -671,15 +677,9 @@ status = CKYApplet_SelectCoolKeyManager(conn, NULL); if (status != CKYSUCCESS) { log->log("CoolKey Select failed 0x%x\n", status); - status = CACApplet_SelectPKI(conn, 0, NULL); + status = getCACAid(); if (status != CKYSUCCESS) { - log->log("CAC Select failed 0x%x\n", status); - if (status == CKYSCARDERR) { - log->log("CAC Card Failure 0x%x\n", - CKYCardConnection_GetLastError(conn)); - disconnect(); - } - return; + goto loser; } state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; /* skip the read of the cuid. We really don't need it and, @@ -690,6 +690,15 @@ needLogin = 1; mCoolkey = 0; return; + +loser: + log->log("CAC Select failed 0x%x\n", status); + if (status == CKYSCARDERR) { + log->log("CAC Card Failure 0x%x\n", + CKYCardConnection_GetLastError(conn)); + disconnect(); + } + return; } mCoolkey = 1; log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time); @@ -771,17 +780,111 @@ invalidateLogin(false); } +CKYStatus +Slot::getCACAid() +{ + CKYBuffer tBuf; + CKYBuffer vBuf; + CKYSize tlen, vlen; + CKYOffset toffset, voffset; + int certSlot = 0; + int i,length = 0; + CKYStatus status; + + CKYBuffer_InitEmpty(&tBuf); + CKYBuffer_InitEmpty(&vBuf); + + /* clear out the card AID's */ + for (i=0; i < MAX_CERT_SLOTS; i++) { + CKYBuffer_Resize(&cardAID[i],0); + } + + status = CACApplet_SelectCCC(conn,NULL); + if (status != CKYSUCCESS) { + /* are we an old CAC */ + status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL); + if (status != CKYSUCCESS) { + /* no, just fail */ + return status; + } + /* yes, fill in the old applets */ + mOldCAC = true; + for (i=1; i< MAX_CERT_SLOTS; i++) { + CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); + } + return CKYSUCCESS; + } + /* definately not an old CAC */ + mOldCAC = false; + + /* read the TLV */ + status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + tlen = CKYBuffer_Size(&tBuf); + vlen = CKYBuffer_Size(&vBuf); + + for(toffset = 2, voffset=2; + certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ; + voffset += length) { + + CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset); + length = CKYBuffer_GetChar(&tBuf, toffset+1); + toffset += 2; + if (length == 0xff) { + length = CKYBuffer_GetShortLE(&tBuf, toffset); + toffset +=2; + } + if (tag != CAC_TAG_CARDURL) { + continue; + } + /* CARDURL tags must be at least 10 bytes long */ + if (length < 10) { + continue; + } + /* check the app type, should be TLV_APP_PKI */ + if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) { + continue; + } + status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5); + if (status != CKYSUCCESS) { + goto done; + } + status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, + voffset+8, 2); + if (status != CKYSUCCESS) { + goto done; + } + cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6); + + certSlot++; + } + status = CKYSUCCESS; + if (certSlot == 0) { + status = CKYAPDUFAIL; /* probably neeed a beter error code */ + } + +done: + CKYBuffer_FreeData(&tBuf); + CKYBuffer_FreeData(&vBuf); + return status; +} + void Slot::refreshTokenState() { if( cardStateMayHaveChanged() ) { -log->log("card changed\n"); + log->log("card changed\n"); invalidateLogin(true); closeAllSessions(); unloadObjects(); connectToToken(); - if( state & APPLET_PERSONALIZED ) { try { loadObjects(); @@ -1019,7 +1122,7 @@ struct _manList { unsigned short type; - char *string; + const char *string; }; static const struct _manList manList[] = { @@ -1280,13 +1383,30 @@ Slot::selectCACApplet(CKYByte instance) { CKYStatus status; - status = CACApplet_SelectPKI(conn, instance, NULL); + CKYBuffer *aid = &cardAID[instance]; + + if (CKYBuffer_Size(aid) == 0) { + disconnect(); + throw PKCS11Exception(CKR_DEVICE_REMOVED); + return; + } + + status = CKYApplet_SelectFile(conn, aid, NULL); if ( status == CKYSCARDERR ) handleConnectionError(); if ( status != CKYSUCCESS) { // could not select applet: this just means it's not there disconnect(); throw PKCS11Exception(CKR_DEVICE_REMOVED); } + if (mOldCAC) { + return; + } + status = CACApplet_SelectFile(conn, cardEF[instance], NULL); + if ( status == CKYSCARDERR ) handleConnectionError(); + if ( status != CKYSUCCESS) { + disconnect(); + throw PKCS11Exception(CKR_DEVICE_REMOVED); + } } // assume we are already in a transaction void @@ -2059,10 +2179,85 @@ return objInfoList; } +CKYStatus +Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, + bool throwException) +{ + CKYStatus status; + CKYISOStatus apduRC; + + if (mOldCAC) { + /* get the first 100 bytes of the cert */ + status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); + if (throwException && (status != CKYSUCCESS)) { + handleConnectionError(); + } + return status; + } + + CKYBuffer tBuf; + CKYBuffer vBuf; + CKYSize tlen, vlen; + CKYOffset toffset, voffset; + int length = 0; + + CKYBuffer_InitEmpty(&tBuf); + CKYBuffer_InitEmpty(&vBuf); + CKYBuffer_Resize(cert, 0); + + /* handle the new CAC card read */ + /* read the TLV */ + status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); + if (status != CKYSUCCESS) { + goto done; + } + tlen = CKYBuffer_Size(&tBuf); + vlen = CKYBuffer_Size(&vBuf); + + /* look for the Cert out of the TLV */ + for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ; + voffset += length) { + + CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset); + length = CKYBuffer_GetChar(&tBuf, toffset+1); + toffset += 2; + if (length == 0xff) { + length = CKYBuffer_GetShortLE(&tBuf, toffset); + toffset +=2; + } + if (tag != CAC_TAG_CERTIFICATE) { + continue; + } + CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length); + break; + } + status = CKYSUCCESS; + +done: + CKYBuffer_FreeData(&tBuf); + CKYBuffer_FreeData(&vBuf); + return status; +} + +/* + * only necessary for old CAC cards. New CAC cards have to read the + * whole cert in anyway above.... + */ +CKYStatus +Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize) +{ + CKYISOStatus apduRC; + assert(mOldCAC); + return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC); +} + void Slot::loadCACCert(CKYByte instance) { - CKYISOStatus apduRC; CKYStatus status = CKYSUCCESS; CKYBuffer cert; CKYBuffer rawCert; @@ -2097,12 +2292,7 @@ instance, OSTimeNow() - time); if (instance == 0) { - /* get the first 100 bytes of the cert */ - status = CACApplet_GetCertificateFirst(conn, &rawCert, - &nextSize, &apduRC); - if (status != CKYSUCCESS) { - handleConnectionError(); - } + readCACCertificateFirst(&rawCert, &nextSize, true); log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", instance, OSTimeNow() - time); } @@ -2143,8 +2333,7 @@ shmem.setVersion(SHMEM_VERSION); shmem.setDataVersion(dataVersion); } else { - status = CACApplet_GetCertificateFirst(conn, &rawCert, - &nextSize, &apduRC); + status = readCACCertificateFirst(&rawCert, &nextSize, false); if (status != CKYSUCCESS) { /* CAC only requires the Certificate in pki '0' */ @@ -2159,8 +2348,7 @@ } if (nextSize) { - status = CACApplet_GetCertificateAppend(conn, &rawCert, - nextSize, &apduRC); + status = readCACCertificateAppend(&rawCert, nextSize); } log->log("CAC Cert %d: Fetch rest : %d ms\n", instance, OSTimeNow() - time); @@ -2176,9 +2364,10 @@ log->log("CAC Cert %d: Cert has been read: %d ms\n", instance, OSTimeNow() - time); - if (CKYBuffer_GetChar(&rawCert,0) == 1) { + if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) { CKYSize guessFinalSize = CKYBuffer_Size(&rawCert); CKYSize certSize = 0; + CKYOffset offset = mOldCAC ? 1 : 0; int zret = Z_MEM_ERROR; do { @@ -2189,7 +2378,8 @@ } certSize = guessFinalSize; zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize, - CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1); + CKYBuffer_Data(&rawCert)+offset, + CKYBuffer_Size(&rawCert)-offset); } while (zret == Z_BUF_ERROR); if (zret != Z_OK) { @@ -2526,7 +2716,7 @@ switch( result ) { case CKYISO_SUCCESS: break; - case 6981: + case 0x6981: throw PKCS11Exception(CKR_PIN_LOCKED); default: if ((result & 0xff00) == 0x6300) { --- a/src/coolkey/slot.h +++ b/src/coolkey/slot.h @@ -294,6 +294,7 @@ const CKYBuffer *paddedOutput) const = 0; }; +#define MAX_CERT_SLOTS 3 class Slot { public: @@ -328,6 +329,8 @@ CKYBuffer nonce; CKYBuffer cardATR; CKYBuffer mCUID; + CKYBuffer cardAID[MAX_CERT_SLOTS]; + unsigned short cardEF[MAX_CERT_SLOTS]; bool isVersion1Key; bool needLogin; long publicFree; @@ -335,6 +338,7 @@ long privateFree; bool fullTokenName; bool mCoolkey; + bool mOldCAC; //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 }; @@ -398,6 +402,11 @@ list fetchCombinedObjects(const CKYBuffer *header); list fetchSeparateObjects(); + CKYStatus getCACAid(); + CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, + bool throwException); + CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); + void selectApplet(); void selectCACApplet(CKYByte instance); void unloadObjects(); --- a/src/libckyapplet/cky_applet.c +++ b/src/libckyapplet/cky_applet.c @@ -41,7 +41,13 @@ CKYStatus CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param) { - return CKYAPDUFactory_SelectFile(apdu,(const CKYBuffer *)param); + return CKYAPDUFactory_SelectFile(apdu, 4, 0, (const CKYBuffer *)param); +} + +CKYStatus +CACAppletFactory_SelectFile(CKYAPDU *apdu, const void *param) +{ + return CKYAPDUFactory_SelectFile(apdu, 2, 12, (const CKYBuffer *)param); } CKYStatus @@ -225,10 +231,17 @@ } CKYStatus -CACAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param) +CACAppletFactory_SignDecryptStep(CKYAPDU *apdu, const void *param) +{ + const CKYBuffer *buf=(CKYBuffer *)param; + return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_STEP, buf); +} + +CKYStatus +CACAppletFactory_SignDecryptFinal(CKYAPDU *apdu, const void *param) { const CKYBuffer *buf=(CKYBuffer *)param; - return CACAPDUFactory_SignDecrypt(apdu, buf); + return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_FINAL, buf); } CKYStatus @@ -246,6 +259,13 @@ } CKYStatus +CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param) +{ + const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param; + return CACAPDUFactory_ReadFile(apdu, rfs->offset, rfs->type, rfs->count); +} + +CKYStatus CACAppletFactory_GetProperties(CKYAPDU *apdu, const void *param) { return CACAPDUFactory_GetProperties(apdu); @@ -457,7 +477,7 @@ CKYISOStatus *apduRC) { return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, AID, NULL, - 0, CKYAppletFill_Null, NULL, apduRC); + CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); } static CKYByte coolkeyid[] = {0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00 }; @@ -477,22 +497,23 @@ return ret; } -static CKYByte CACPKIid[] = {0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; +static CKYByte CACPKIid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01 }; /* * Select the CoolKey applet. Must happen after we start a transaction and * before we issue any applet specific command. */ CKYStatus -CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, - CKYISOStatus *apduRC) +CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cacAID, + CKYByte instance, CKYISOStatus *apduRC) { CKYStatus ret; - CKYBuffer CACPKIAID; - CKYBuffer_InitFromData(&CACPKIAID, CACPKIid, sizeof(CACPKIid)); - CKYBuffer_SetChar(&CACPKIAID, 6, instance); - ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CACPKIAID, + CKYBuffer_AppendData(cacAID, CACPKIid, sizeof(CACPKIid)); + CKYBuffer_AppendChar(cacAID, instance); + ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, cacAID, NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); - CKYBuffer_FreeData(&CACPKIAID); + if (ret != CKYSUCCESS) { + CKYBuffer_Resize(cacAID, 0); + } return ret; } @@ -515,11 +536,38 @@ CKYBuffer CAC_CM_AID; CKYBuffer_InitFromData(&CAC_CM_AID, cacmgrid, sizeof(cacmgrid)); ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID, - NULL, 0, CKYAppletFill_Null, NULL, apduRC); + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); CKYBuffer_FreeData(&CAC_CM_AID); return ret; } +static CKYByte cacCCCid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00 }; +CKYStatus +CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYBuffer CAC_CM_AID; + CKYBuffer_InitFromData(&CAC_CM_AID, cacCCCid, sizeof(cacCCCid)); + ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID, + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); + CKYBuffer_FreeData(&CAC_CM_AID); + return ret; +} + +CKYStatus +CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef, + CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYBuffer efBuf; + CKYBuffer_InitEmpty(&efBuf); + CKYBuffer_AppendShortLE(&efBuf, ef); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SelectFile, &efBuf, + NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); + CKYBuffer_FreeData(&efBuf); + return ret; +} + /* * GetCPLC cluster -- must be called with CM selected */ @@ -673,8 +721,8 @@ ccd.keyNumber = keyNumber; ccd.location = location; ccd.data = data; - return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, &ccd, - nonce, 0, CKYAppletFill_Null, NULL, apduRC); + return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, + &ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC); } /* computeCrypt returns data in the form : @@ -832,11 +880,39 @@ CKYBuffer *result, CKYISOStatus *apduRC) { CKYStatus ret; - - ret = CKYApplet_HandleAPDU(conn, - CACAppletFactory_SignDecrypt, data, NULL, - CKYBuffer_Size(data), CKYAppletFill_ReplaceBuffer, + CKYSize dataSize = CKYBuffer_Size(data); + CKYOffset offset = 0; + CKYBuffer tmp; + + CKYBuffer_InitEmpty(&tmp); + + CKYBuffer_Resize(result, 0); + for(offset = 0; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; + offset += CKY_MAX_WRITE_CHUNK_SIZE) { + CKYBuffer_Resize(&tmp,0); + CKYBuffer_AppendBuffer(&tmp, data, offset, CKY_MAX_WRITE_CHUNK_SIZE); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptStep, + &tmp, NULL, CKY_SIZE_UNKNOWN, + CKYAppletFill_AppendBuffer, result, apduRC); + if (ret != CKYSUCCESS) { + goto done; + } + } + CKYBuffer_Resize(&tmp,0); + CKYBuffer_AppendBuffer(&tmp, data, offset, dataSize - offset); + ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptFinal, + &tmp, NULL, CKY_SIZE_UNKNOWN, + CKYAppletFill_AppendBuffer, + result, apduRC); + + if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != dataSize)) { + /* RSA returns the same data size as input, didn't happen, so + * something is wrong. */ + } + +done: + CKYBuffer_FreeData(&tmp); return ret; } @@ -895,6 +971,63 @@ } return ret; } + +/* + * Read a CAC Tag/Value file + */ +CKYStatus +CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, CKYBuffer *buffer, + CKYISOStatus *apduRC) +{ + CKYStatus ret; + CKYISOStatus status; + CKYByte maxtransfer; + unsigned short offset = 0; + unsigned short size; + CACAppletArgReadFile rfs; + + CKYBuffer_Resize(buffer,0); + if (apduRC == NULL) { + apduRC = &status; + } + rfs.offset = 0; + rfs.count = 2; + rfs.type = type; + + /* APDU's are expensive, Grab a big chunk of the file first if possible */ + ret = CKYApplet_HandleAPDU(conn, + CACAppletFactory_ReadFile, &rfs, NULL, + rfs.count, CKYAppletFill_AppendBuffer, + buffer, apduRC); + /* file is probably smaller than 100 bytes, get the actual size first */ + if (ret != CKYSUCCESS) { + return ret; + } + size = CKYBuffer_GetShortLE(buffer, 0) + 2 /* include the length itself */; + maxtransfer = CKY_MAX_READ_CHUNK_SIZE; + /* get the rest of the buffer if necessary */ + for (offset = CKYBuffer_Size(buffer); size > offset; + offset = CKYBuffer_Size(buffer)) { + rfs.offset = offset; + rfs.count = MIN(size - offset, maxtransfer); + ret = CKYApplet_HandleAPDU(conn, + CACAppletFactory_ReadFile, &rfs, NULL, + rfs.count, CKYAppletFill_AppendBuffer, + buffer, apduRC); + if (ret != CKYSUCCESS) { + if (*apduRC == CAC_INVALID_PARAMS) { + maxtransfer = maxtransfer/2; + if (maxtransfer == 0) { + return ret; + } + } else { + return ret; + } + } + } + return ret; +} + CKYStatus CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, CKYSize *nextSize, CKYISOStatus *apduRC) --- a/src/libckyapplet/cky_applet.h +++ b/src/libckyapplet/cky_applet.h @@ -71,6 +71,15 @@ #define CKYISO_INTERNAL_ERROR 0x9cff /* Reserved for debugging, * shouldn't happen */ +#define CAC_INVALID_PARAMS 0x6a83 +#define CAC_TAG_FILE 1 +#define CAC_VALUE_FILE 2 + + +#define CAC_TAG_CARDURL 0xf3 +#define CAC_TAG_CERTIFICATE 0x70 +#define CAC_TLV_APP_PKI 0x04 + /* * Pin Constants as used by our applet */ @@ -209,6 +218,12 @@ const CKYBuffer *sig; } CKYAppletArgComputeCrypt; +typedef struct _CACAppletArgReadFile { + CKYByte type; + CKYByte count; + unsigned short offset; +} CACAppletArgReadFile; + /* fills in an APDU from a structure -- form of all the generic factories*/ typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param); /* fills in an a structure from a response -- form of all the fill structures*/ @@ -451,9 +466,17 @@ /* Select the CAC card manager. Can happen with either applet selected */ CKYStatus CACApplet_SelectCardManager(CKYCardConnection *conn, CKYISOStatus *apduRC); -/* Can happen with either applet selected */ -CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, - CKYISOStatus *apduRC); +/* Select the CAC CC container. Can happen with either applet selected */ +CKYStatus CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC); +/* Select an old CAC applet and fill in the cardAID */ +CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cardAid, + CKYByte instance, CKYISOStatus *apduRC); +/* read a TLV file */ +CKYStatus CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, + CKYBuffer *buffer, CKYISOStatus *apduRC); +CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef, + CKYISOStatus *apduRC); + /* must happen with PKI applet selected */ CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC); --- a/src/libckyapplet/cky_base.c +++ b/src/libckyapplet/cky_base.c @@ -220,6 +220,22 @@ return CKYSUCCESS; } +/* append a short in network order */ +CKYStatus +CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val) +{ + CKYStatus ret; + + ret = CKYBuffer_Reserve(buf, buf->len + 2); + if (ret != CKYSUCCESS) { + return ret; + } + buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff); + buf->len += 2; + return CKYSUCCESS; +} + /* append a long in applet order */ CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val) @@ -238,6 +254,24 @@ return CKYSUCCESS; } +/* append a long in applet order */ +CKYStatus +CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val) +{ + CKYStatus ret; + + ret = CKYBuffer_Reserve(buf, buf->len + 4); + if (ret != CKYSUCCESS) { + return ret; + } + buf->data[buf->len+3] = (CKYByte) ((val >> 24) & 0xff); + buf->data[buf->len+2] = (CKYByte) ((val >> 16) & 0xff); + buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff); + buf->len += 4; + return CKYSUCCESS; +} + CKYStatus CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data, CKYSize len) { @@ -351,6 +385,22 @@ } CKYStatus +CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val) +{ + CKYStatus ret; + + if (buf->len < offset+2) { + ret = CKYBuffer_Resize(buf,offset+2); + if (ret != CKYSUCCESS) { + return ret; + } + } + buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff); + return CKYSUCCESS; +} + +CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val) { CKYStatus ret; @@ -368,6 +418,24 @@ return CKYSUCCESS; } +CKYStatus +CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val) +{ + CKYStatus ret; + + if (buf->len < offset+4) { + ret = CKYBuffer_Resize(buf,offset+4); + if (ret != CKYSUCCESS) { + return ret; + } + } + buf->data[offset+3] = (CKYByte) ((val >> 24) & 0xff); + buf->data[offset+2] = (CKYByte) ((val >> 16) & 0xff); + buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff); + buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff); + return CKYSUCCESS; +} + CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset) { @@ -388,6 +456,18 @@ val |= ((unsigned short)buf->data[offset+1]) << 0; return val; } + +unsigned short +CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset) +{ + unsigned short val; + if (buf->len < offset+2) { + return 0; + } + val = ((unsigned short)buf->data[offset+1]) << 8; + val |= ((unsigned short)buf->data[offset+0]) << 0; + return val; +} unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset) @@ -402,6 +482,20 @@ val |= ((unsigned long)buf->data[offset+3]) << 0; return val; } + +unsigned long +CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset) +{ + unsigned long val; + if (buf->len < offset+4) { + return 0; + } + val = ((unsigned long)buf->data[offset+3]) << 24; + val |= ((unsigned long)buf->data[offset+2]) << 16; + val |= ((unsigned long)buf->data[offset+1]) << 8; + val |= ((unsigned long)buf->data[offset+0]) << 0; + return val; +} CKYStatus CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen) --- a/src/libckyapplet/cky_base.h +++ b/src/libckyapplet/cky_base.h @@ -170,9 +170,15 @@ /* append a short in applet order */ CKYStatus CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val); +/* append a short in little endian order */ +CKYStatus CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val); + /* append a long in applet order */ CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val); +/* append a long in little endian order */ +CKYStatus CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val); + /* append data. the data starts at data and extends len bytes */ CKYStatus CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len); @@ -210,12 +216,18 @@ CKYStatus CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val); CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val); +/* These functions work in little endian order */ +CKYStatus CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val); +CKYStatus CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val); /* read a character from offset. If offset is beyond the end of the buffer, * then the function returns '0' */ CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset); /* These functions work in applet order */ unsigned short CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset); unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset); +/* These functions work in little endian order */ +unsigned short CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset); +unsigned long CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset); /* clear out all the data in a buffer */ void CKYBuffer_Zero(CKYBuffer *buf); --- a/src/libckyapplet/cky_factory.c +++ b/src/libckyapplet/cky_factory.c @@ -25,12 +25,13 @@ * special commands can be issued at any time */ CKYStatus -CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID) +CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2, + const CKYBuffer *AID) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE); - CKYAPDU_SetP1(apdu, 0x04); - CKYAPDU_SetP2(apdu, 0x00); + CKYAPDU_SetP1(apdu, p1); + CKYAPDU_SetP2(apdu, p2); return CKYAPDU_SetSendDataBuffer(apdu, AID); } @@ -131,6 +132,7 @@ return ret; } + CKYStatus CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber, CKYByte location, const CKYBuffer *data, const CKYBuffer *sig) @@ -572,11 +574,11 @@ } CKYStatus -CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data) +CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, const CKYBuffer *data) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); CKYAPDU_SetINS(apdu, CAC_INS_SIGN_DECRYPT); - CKYAPDU_SetP1(apdu, 0x00); + CKYAPDU_SetP1(apdu, type); CKYAPDU_SetP2(apdu, 0x00); return CKYAPDU_SetSendDataBuffer(apdu, data); } @@ -592,6 +594,36 @@ } CKYStatus +CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, + CKYByte type, CKYByte count) +{ + CKYStatus ret; + CKYBuffer buf; + + CKYBuffer_InitEmpty(&buf); + CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM); + CKYAPDU_SetINS(apdu, CAC_INS_READ_FILE); + CKYAPDU_SetP1(apdu, (offset >> 8) & 0xff); + CKYAPDU_SetP2(apdu, offset & 0xff); + ret = CKYBuffer_Reserve(&buf, 2); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendChar(&buf, type); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendChar(&buf, count); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYAPDU_SetSendDataBuffer(apdu, &buf); +fail: + CKYBuffer_FreeData(&buf); + return ret; +} + +CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu) { CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); --- a/src/libckyapplet/cky_factory.h +++ b/src/libckyapplet/cky_factory.h @@ -86,7 +86,11 @@ #define CAC_INS_SIGN_DECRYPT 0x42 #define CAC_INS_VERIFY_PIN 0x20 #define CAC_INS_GET_PROPERTIES 0x56 +#define CAC_INS_READ_FILE 0x52 + #define CAC_SIZE_GET_PROPERTIES 48 +#define CAC_P1_STEP 0x80 +#define CAC_P1_FINAL 0x00 /* * Fixed return sized from various commands @@ -169,7 +173,8 @@ CKY_BEGIN_PROTOS /* function based factorys */ -CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID); +CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2, + const CKYBuffer *AID); CKYStatus CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence); @@ -211,9 +216,12 @@ CKYStatus CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu); -CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data); +CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, + const CKYBuffer *data); CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin); CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size); +CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, + CKYByte type, CKYByte count); CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu); CKY_END_PROTOS debian/patches/coolkey-nextSize.patch0000644000000000000000000000076312266512141015120 0ustar Description: Fix Firefox crash due to "Assertion `mOldCAC' failed" error Author: Eric Reischer Origin: http://www.spinics.net/linux/fedora/coolkey/msg00368.html Bug-Debian: http://bugs.debian.org/698230 --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -2215,6 +2215,8 @@ CKYBuffer_InitEmpty(&vBuf); CKYBuffer_Resize(cert, 0); + *nextSize = 0; + /* handle the new CAC card read */ /* read the TLV */ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); debian/patches/series0000644000000000000000000000045412266512141012035 0ustar spelling-error-in-binary coolkey-pcsc-lite coolkey-cache-dir-move.patch coolkey-gcc43.patch coolkey-latest.patch coolkey-simple-bugs.patch coolkey-thread-fix.patch coolkey-cac-rhl5.patch 0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch Handle-pcscd-restarting coolkey-nextSize.patch debian/patches/coolkey-latest.patch0000644000000000000000000004741512266506371014620 0ustar Description: Latest fixes for Safenet 330J and Gemalto 64K cards. Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=e23c66c534b9cef842bb74e373a1582684de2920 Author: Jack Magne Date: Tue Sep 15 20:52:45 2009 +0000 SVN revisions 73-77 https://fedorahosted.org/coolkey/changeset?reponame=&new=77%40%2F&old=73%40%2F --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -203,6 +203,29 @@ return FALSE; } +bool +SlotList::readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList) +{ + if( !readerName || !readerNameList) { + return FALSE; + } + + int i = 0; + int readerNameCnt = CKYReaderNameList_GetCount(*readerNameList); + + const char *curReaderName = NULL; + for(i=0; i < readerNameCnt; i++) { + curReaderName = CKYReaderNameList_GetValue(*readerNameList,i); + + if(!strcmp(curReaderName,readerName)) { + return TRUE; + } + + } + + return FALSE; +} + /* * you need to hold the ReaderList Lock before you can update the ReaderList */ @@ -256,6 +279,27 @@ * don't recognize. */ + /* first though, let's check to see if any previously removed readers have + * come back from the dead. If the ignored bit has been set, we do not need + * it any more. + */ + + const char *curReaderName = NULL; + unsigned long knownState = 0; + for(int ri = 0 ; ri < numReaders; ri ++) { + + knownState = CKYReader_GetKnownState(&readerStates[ri]); + if( !(knownState & SCARD_STATE_IGNORE)) { + continue; + } + + curReaderName = CKYReader_GetReaderName(&readerStates[ri]); + if(readerNameExistsInList(curReaderName,&readerNames)) { + CKYReader_SetKnownState(&readerStates[ri], knownState & ~SCARD_STATE_IGNORE); + + } + } + const char *newReadersData[MAX_READER_DELTA]; const char **newReaders = &newReadersData[0]; unsigned int newReaderCount = 0; @@ -528,7 +572,7 @@ void Slot::connectToToken() { - CKYStatus status; + CKYStatus status = CKYSCARDERR; OSTime time = OSTimeNow(); mCoolkey = 0; @@ -537,13 +581,31 @@ // try to connect to the card if( ! CKYCardConnection_IsConnected(conn) ) { - status = CKYCardConnection_Connect(conn, readerName); - if( status != CKYSUCCESS ) { - log->log("Unable to connect to token\n"); + int i = 0; + //for cranky readers try again a few more times + while( i++ < 5 && status != CKYSUCCESS ) + { + status = CKYCardConnection_Connect(conn, readerName); + if( status != CKYSUCCESS && + CKYCardConnection_GetLastError(conn) == SCARD_E_PROTO_MISMATCH ) + { + log->log("Unable to connect to token status %d ConnGetGetLastError %x .\n",status,CKYCardConnection_GetLastError(conn)); + + } + else + { + break; + } + OSSleep(100000); + } + + if( status != CKYSUCCESS) + { state = UNKNOWN; return; } } + log->log("time connect: Connect Time %d ms\n", OSTimeNow() - time); if (!slotInfoFound) { readSlotInfo(); @@ -562,15 +624,10 @@ state = CARD_PRESENT; } - if ( CKYBuffer_DataIsEqual(&cardATR, ATR, sizeof (ATR)) || - CKYBuffer_DataIsEqual(&cardATR, ATR1, sizeof(ATR1)) || - CKYBuffer_DataIsEqual(&cardATR, ATR2, sizeof(ATR2)) ) { - - if (Params::hasParam("noAppletOK")) - { - state |= APPLET_SELECTABLE; - mCoolkey = 1; - } + if (Params::hasParam("noAppletOK")) + { + state |= APPLET_SELECTABLE; + mCoolkey = 1; } /* support CAC card. identify the card based on applets, not the ATRS */ @@ -631,7 +688,7 @@ * unfriendly */ isVersion1Key = 0; needLogin = 1; - + mCoolkey = 0; return; } mCoolkey = 1; @@ -1077,6 +1134,7 @@ } throw; } + if (myNumReaders != numReaders) { if (myReaderStates) { delete [] myReaderStates; @@ -1103,6 +1161,7 @@ } } } + if (found || (flag == CKF_DONT_BLOCK) || shuttingDown) { break; } @@ -1272,6 +1331,19 @@ } }; +class KeyNumMatch { + private: + CKYByte keyNum; + const Slot &slot; + public: + KeyNumMatch(CKYByte keyNum_, const Slot &s) : keyNum(keyNum_), slot(s) { } + bool operator() (const PKCS11Object& obj) { + unsigned long objID = obj.getMuscleObjID(); + return (slot.getObjectClass(objID) == 'k') + && (slot.getObjectIndex(objID) == keyNum); + } +}; + class ObjectCertCKAIDMatch { private: CKYByte cka_id; @@ -3007,8 +3079,9 @@ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { + RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE); cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen, - RSASignatureParams(CryptParams::FIXED_KEY_SIZE)); + params); } void @@ -3016,14 +3089,15 @@ CK_ULONG ulDataLen, CK_BYTE_PTR pDecryptedData, CK_ULONG_PTR pulDecryptedDataLen) { + RSADecryptParams params(CryptParams::DEFAULT_KEY_SIZE); cryptRSA(suffix, pData, ulDataLen, pDecryptedData, pulDecryptedDataLen, - RSADecryptParams(CryptParams::FIXED_KEY_SIZE)); + params); } void Slot::cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput, CK_ULONG ulInputLen, CK_BYTE_PTR pOutput, - CK_ULONG_PTR pulOutputLen, const CryptParams& params) + CK_ULONG_PTR pulOutputLen, CryptParams& params) { refreshTokenState(); SessionIter session = findSession(suffix); @@ -3041,6 +3115,11 @@ CKYBuffer *result = &opState.result; CKYByte keyNum = opState.keyNum; + unsigned int keySize = getKeySize(keyNum); + + if(keySize != CryptParams::DEFAULT_KEY_SIZE) + params.setKeySize(keySize); + if( CKYBuffer_Size(result) == 0 ) { // we haven't already peformed the decryption, so do it now. if( pInput == NULL || ulInputLen == 0) { @@ -3243,3 +3322,36 @@ throw PKCS11Exception(CKR_DEVICE_ERROR); } } + +#define MAX_NUM_KEYS 8 +unsigned int +Slot::getKeySize(CKYByte keyNum) +{ + unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE; + int modSize = 0; + + if(keyNum >= MAX_NUM_KEYS) { + return keySize; + } + + ObjectConstIter iter; + iter = find_if(tokenObjects.begin(), tokenObjects.end(), + KeyNumMatch(keyNum,*this)); + + if( iter == tokenObjects.end() ) { + return keySize; + } + + CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS); + + if(modulus) { + modSize = CKYBuffer_Size(modulus); + if(CKYBuffer_GetChar(modulus,0) == 0x0) { + modSize--; + } + if(modSize > 0) + keySize = modSize * 8; + } + + return keySize; +} --- a/src/coolkey/slot.h +++ b/src/coolkey/slot.h @@ -270,10 +270,9 @@ protected: unsigned int getKeySize() const { return keySize; } public: - // !!!XXX hack. The right way to get the key size is to get all the - // key information from the token with MSCListKeys, the same way - // we get all the object information with MSCListObjects. - enum { FIXED_KEY_SIZE = 1024 }; + // set the actual key size obtained from the card + void setKeySize(unsigned int newKeySize) { keySize = newKeySize; } + enum { DEFAULT_KEY_SIZE = 1024 }; CryptParams(unsigned int keySize_) : keySize(keySize_) { } @@ -422,7 +421,7 @@ void cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput, CK_ULONG ulInputLen, CK_BYTE_PTR pOutput, - CK_ULONG_PTR pulOutputLen, const CryptParams& params); + CK_ULONG_PTR pulOutputLen, CryptParams& params); void performRSAOp(CKYBuffer *out, const CKYBuffer *input, CKYByte keyNum, CKYByte direction); @@ -460,6 +459,8 @@ return (char )((objectID >> 16) & 0xff) - '0'; } + // actually get the size of a key in bits from the card + unsigned int getKeySize(CKYByte keyNum); SessionHandleSuffix openSession(Session::Type type); void closeSession(SessionHandleSuffix handleSuffix); @@ -527,6 +528,8 @@ * has called 'C_GetSlotList' with a NULL parameter */ void updateReaderList(); + /* see if a reader name exists in a caller provided reader name list. */ + bool readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList ); bool readerExists(const char *readerName, unsigned int *hint = 0); public: SlotList(Log *log); --- a/src/libckyapplet/cky_applet.c +++ b/src/libckyapplet/cky_applet.c @@ -134,6 +134,13 @@ /* Future add WriteObject */ CKYStatus +CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param) +{ + const CKYAppletArgWriteObject *wos = (const CKYAppletArgWriteObject *)param; + return CKYAPDUFactory_WriteObject(apdu,wos->objectID,wos->offset,wos->size,wos->data); +} + +CKYStatus CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param) { const CKYAppletArgCreateObject *cos=(const CKYAppletArgCreateObject *)param; @@ -192,7 +199,6 @@ { return CKYAPDUFactory_GetLifeCycleV2(apdu); } - CKYStatus CKYAppletFactory_GetRandom(CKYAPDU *apdu, const void *param) { @@ -725,24 +731,48 @@ CKYAppletArgComputeCrypt ccd; CKYBuffer empty; CKYISOStatus status; + short dataSize = 0; int use2APDUs = 0; + int use_dl_object = CKYBuffer_Size(data) > 200 ; CKYBuffer_InitEmpty(&empty); ccd.keyNumber = keyNumber; ccd.mode = mode; ccd.direction = direction; - ccd.location = CKY_DL_APDU; + ccd.location = use_dl_object ? CKY_DL_OBJECT : CKY_DL_APDU; if (!apduRC) apduRC = &status; + if (use_dl_object) { + CKYBuffer sizeBuf; + + CKYBuffer_InitEmpty(&sizeBuf); + CKYBuffer_AppendShort(&sizeBuf, CKYBuffer_Size(data)); + + ret = CKYApplet_WriteObjectFull(conn, 0xffffffff, + 0, CKYBuffer_Size(&sizeBuf), nonce, + &sizeBuf, apduRC); + + CKYBuffer_FreeData(&sizeBuf); + if( ret != CKYSUCCESS) + goto fail; + + ret = CKYApplet_WriteObjectFull(conn, 0xffffffff, + 2, CKYBuffer_Size(data), nonce, + data, apduRC); + + if(ret != CKYSUCCESS) + goto fail; + } + if (mode == CKY_RSA_NO_PAD) { - ccd.data = data; + ccd.data = use_dl_object ? &empty : data; ccd.sig = sig; ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptOneStep, &ccd, nonce, CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal, - result, apduRC); + use_dl_object ? NULL : result, apduRC); if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) { use2APDUs = 1; /* maybe it's an old applet */ } @@ -759,13 +789,38 @@ CKYAppletFactory_ComputeCryptInit, &ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC); if (ret == CKYSUCCESS) { - ccd.data = data; + ccd.data = use_dl_object ? &empty : data; ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptFinal, &ccd, nonce, CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal, - result, apduRC); + use_dl_object ? NULL : result, apduRC); } } + + if (use_dl_object && ret == CKYSUCCESS) { + CKYBuffer sizeOutBuf; + CKYBuffer_InitEmpty(&sizeOutBuf); + + ret = CKYApplet_ReadObjectFull(conn,0xffffffff, + 0, 2, + nonce,&sizeOutBuf,apduRC); + + if(ret != CKYSUCCESS) { + CKYBuffer_FreeData(&sizeOutBuf); + goto fail; + } + + dataSize = CKYBuffer_GetShort(&sizeOutBuf, 0); + + CKYBuffer_FreeData(&sizeOutBuf); + + ret = CKYApplet_ReadObjectFull(conn,0xffffffff, + 2, dataSize, + nonce,result,apduRC); + } + +fail: + return ret; } @@ -1033,6 +1088,44 @@ } while ((size > 0) && (ret == CKYSUCCESS)); return ret; +} + +/* + * Write Object + * This makes multiple APDU calls to write the entire object. + * + */ + +CKYStatus +CKYApplet_WriteObjectFull(CKYCardConnection *conn, unsigned long objectID, + CKYOffset offset, CKYSize size, const CKYBuffer *nonce, + const CKYBuffer *data, CKYISOStatus *apduRC) +{ + + CKYBuffer chunk; + CKYOffset srcOffset = 0; + CKYAppletArgWriteObject wod; + CKYStatus ret = CKYSUCCESS; + + wod.objectID = objectID; + wod.offset = offset; + do { + wod.size = (CKYByte) MIN(size, 220); + ret = CKYBuffer_InitFromBuffer(&chunk, data, + srcOffset, wod.size); + if(ret == CKYSUCCESS) { + wod.data = &chunk; + ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_WriteObject, &wod, + nonce, 0, CKYAppletFill_Null, NULL, apduRC); + size -= wod.size; + wod.offset += wod.size; + srcOffset += wod.size; + CKYBuffer_FreeData(&chunk); + } + + } while ((size > 0) && (ret == CKYSUCCESS)); + + return ret; } /* --- a/src/libckyapplet/cky_applet.h +++ b/src/libckyapplet/cky_applet.h @@ -192,6 +192,14 @@ CKYByte size; } CKYAppletArgReadObject; +typedef struct _CKYAppletArgWriteObject { + unsigned long objectID; + CKYOffset offset; + CKYByte size; + CKYBuffer *data; + +} CKYAppletArgWriteObject; + typedef struct _CKYAppletArgComputeCrypt { CKYByte keyNumber; CKYByte mode; @@ -250,6 +258,8 @@ /* param == CKYByte * (pointer to pinNumber) */ CKYStatus CKYAppletFactory_Logout(CKYAPDU *apdu, const void *param); /* Future add WriteObject */ +/* parm == CKYAppletArgWriteObject */ +CKYStatus CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param); /* param == CKYAppletArgCreateObject */ CKYStatus CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param); /* param == CKYAppletArgDeleteObject */ @@ -482,6 +492,17 @@ CKYStatus CKYApplet_ReadObjectFull(CKYCardConnection *conn, unsigned long objectID, CKYOffset offset, CKYSize size, const CKYBuffer *nonce, CKYBuffer *data, CKYISOStatus *apduRC); +/* + * There is 1 write command: + * CKYApplet_WriteObjectFull can write an entire data object. It makes multiple + * apdu calls in order to write the full amount into the buffer. The buffer is + * overwritten. +*/ + +CKYStatus CKYApplet_WriteObjectFull(CKYCardConnection *conn, + unsigned long objectID, CKYOffset offset, CKYSize size, + const CKYBuffer *nonce, const CKYBuffer *data, CKYISOStatus *apduRC); + CKYStatus CKYApplet_ListObjects(CKYCardConnection *conn, CKYByte seq, CKYAppletRespListObjects *lop, CKYISOStatus *apduRC); CKYStatus CKYApplet_GetStatus(CKYCardConnection *conn, --- a/src/libckyapplet/cky_card.c +++ b/src/libckyapplet/cky_card.c @@ -128,6 +128,7 @@ SCardGetStatusChangeFn SCardGetStatusChange; SCardCancelFn SCardCancel; SCARD_IO_REQUEST *SCARD_PCI_T0_; + SCARD_IO_REQUEST *SCARD_PCI_T1_; } SCard; #define GET_ADDRESS(library, scard, name) \ @@ -194,6 +195,12 @@ if( status != CKYSUCCESS ) { goto fail; } + + status = ckyShLibrary_getAddress( library, + (void**) &scard->SCARD_PCI_T1_, MAKE_DLL_SYMBOL(g_rgSCardT1Pci)); + if( status != CKYSUCCESS ) { + goto fail; + } return scard; fail: @@ -883,6 +890,7 @@ SCARDHANDLE cardHandle; unsigned long lastError; CKYBool inTransaction; + unsigned long protocol; }; static void @@ -893,6 +901,7 @@ conn->cardHandle = 0; conn->lastError = 0; conn->inTransaction = 0; + conn->protocol = SCARD_PROTOCOL_T0; } CKYCardConnection * @@ -933,14 +942,13 @@ { CKYStatus ret; unsigned long rv; - unsigned long protocol; ret = CKYCardConnection_Disconnect(conn); if (ret != CKYSUCCESS) { return ret; } rv = conn->scard->SCardConnect( conn->ctx->context, readerName, - SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &conn->cardHandle, &protocol); + SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &conn->cardHandle, &conn->protocol); if (rv != SCARD_S_SUCCESS) { conn->lastError = rv; return CKYSCARDERR; @@ -977,7 +985,7 @@ unsigned long protocol; rv = conn->scard->SCardReconnect(conn->cardHandle, - SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, init, &protocol); + SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 , init, &protocol); if (rv != SCARD_S_SUCCESS) { conn->lastError = rv; return CKYSCARDERR; @@ -1038,10 +1046,17 @@ return ret; } - rv = conn->scard->SCardTransmit(conn->cardHandle, - conn->scard->SCARD_PCI_T0_, - CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf), - NULL, response->data, &response->len); + if( conn->protocol == SCARD_PROTOCOL_T0 ) { + rv = conn->scard->SCardTransmit(conn->cardHandle, + conn->scard->SCARD_PCI_T0_, + CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf), + NULL, response->data, &response->len); + } else { + rv = conn->scard->SCardTransmit(conn->cardHandle, + conn->scard->SCARD_PCI_T1_, + CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf), + NULL, response->data, &response->len); + } if (rv != SCARD_S_SUCCESS) { conn->lastError =rv; --- a/src/libckyapplet/cky_factory.c +++ b/src/libckyapplet/cky_factory.c @@ -190,8 +190,11 @@ CKYSize len; CKYBuffer buf; - if (!idata || !(len = CKYBuffer_Size(idata)) || location != CKY_DL_APDU) - return ret; + if (!idata) + return ret; + + if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT) + return ret; CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY); CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT); @@ -314,8 +317,6 @@ return CKYSUCCESS; } -/* Future add WriteObject */ - CKYStatus CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID, CKYSize size, unsigned short readACL, unsigned short writeACL, unsigned short deleteACL) @@ -415,6 +416,58 @@ fail: CKYBuffer_FreeData(&buf); return ret; + +} + +CKYStatus +CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID, + CKYOffset offset,CKYSize size,CKYBuffer *data) +{ + CKYBuffer buf; + CKYStatus ret = CKYSUCCESS; + unsigned short dataSize = 0; + + CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY); + CKYAPDU_SetINS(apdu, CKY_INS_WRITE_OBJ); + CKYAPDU_SetP1(apdu, 0x00); + CKYAPDU_SetP2(apdu, 0x00); + CKYBuffer_InitEmpty(&buf); + + dataSize = (unsigned short) CKYBuffer_Size(data); + + if(!dataSize) { + ret = CKYINVALIDARGS; + goto fail; + } + + ret = CKYBuffer_AppendLong(&buf,objectID); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendLong(&buf,offset); + if (ret != CKYSUCCESS) { + goto fail; + } + ret = CKYBuffer_AppendChar(&buf, size); + if (ret != CKYSUCCESS) { + goto fail; + } + + ret = CKYAPDU_SetSendDataBuffer(apdu,&buf); + + if (ret != CKYSUCCESS) { + goto fail; + } + + ret = CKYAPDU_AppendSendDataBuffer(apdu, data); + + if (ret != CKYSUCCESS) { + goto fail; + } + +fail: + CKYBuffer_FreeData(&buf); + return ret; } --- a/src/libckyapplet/cky_factory.h +++ b/src/libckyapplet/cky_factory.h @@ -190,7 +190,8 @@ const char *oldPin, const char *newPin); CKYStatus CKYAPDUFactory_ListPINs(CKYAPDU *apdu); CKYStatus CKYAPDUFactory_Logout(CKYAPDU *apdu, CKYByte pinNumber); - +CKYStatus CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID, + CKYOffset offset,CKYSize size,CKYBuffer *data); /* Future add WriteObject */ CKYStatus CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID, CKYSize size, unsigned short readACL, unsigned short writeACL, debian/patches/coolkey-simple-bugs.patch0000644000000000000000000000417112266506371015543 0ustar Description: Misc bug fixes. Resolves: #485032, #250738, #497758. Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=35fc0905e715f5851f0093726e1f5d5fd335e390 Author: Jack Magne Date: Thu Sep 17 00:09:52 2009 +0000 SVN rev 81 --- a/Makefile.am +++ b/Makefile.am @@ -25,7 +25,6 @@ SUBDIRS += src/install endif -ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = cookey.spec LICENSE --- a/configure.in +++ b/configure.in @@ -124,9 +124,9 @@ if test $WINDOWS -ne 1; then PKG_CHECK_MODULES(NSS, nss, true, [ AC_MSG_ERROR(could not find NSS Crypto libraries) ]) fi - enable_pk11install = "yes" + enable_pk11install="yes" else - enable_pk11install = "no" + enable_pk11install="no" AC_MSG_WARN([skipping pk11install]) fi --- a/src/coolkey/object.cpp +++ b/src/coolkey/object.cpp @@ -397,7 +397,7 @@ { // clean up old one if (label) { - delete label; + delete [] label; label = NULL; } // find matching attribute --- a/src/coolkey/object.h +++ b/src/coolkey/object.h @@ -82,7 +82,7 @@ PKCS11Object(unsigned long muscleObjID, CK_OBJECT_HANDLE handle); PKCS11Object(unsigned long muscleObjID, const CKYBuffer *data, CK_OBJECT_HANDLE handle); - ~PKCS11Object() { delete label; delete name; CKYBuffer_FreeData(&pubKey); } + ~PKCS11Object() { delete [] label; delete [] name; CKYBuffer_FreeData(&pubKey); } PKCS11Object(const PKCS11Object& cpy) : attributes(cpy.attributes), muscleObjID(cpy.muscleObjID), --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -979,7 +979,7 @@ // #define COOLKEY "CoolKey" #define POSSESSION " for " - if (!personName || personName == "") { + if (!personName || personName[0] == '\0' ) { const int coolKeySize = sizeof(COOLKEY) ; memcpy(label, COOLKEY, coolKeySize-1); makeSerialString(&label[coolKeySize], maxSize-coolKeySize, cuid); @@ -1528,7 +1528,7 @@ } sprintf(segName,SEGMENT_PREFIX"%s",readerName); segment = SHMem::initSegment(segName, MAX_OBJECT_STORE_SIZE, needInit); - delete segName; + delete [] segName; if (!segment) { // just run without shared memory return; debian/patches/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch0000644000000000000000000000115212266506371024335 0ustar From f184e5a538caa9412fa3b0e99afe92473fbd6739 Mon Sep 17 00:00:00 2001 From: Vladimir Kravets Date: Mon, 23 May 2011 17:17:43 +0300 Subject: [PATCH] Fix working with empty certificates in not zero slots. --- coolkey-1.1.0/src/coolkey/slot.cpp | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) --- a/src/coolkey/slot.cpp +++ b/src/coolkey/slot.cpp @@ -2192,7 +2192,7 @@ handleConnectionError(); } - if(CKYBuffer_Size(cert) == 0) { + if(throwException && CKYBuffer_Size(cert) == 0) { handleConnectionError(); } return status; debian/patches/coolkey-cache-dir-move.patch0000644000000000000000000001024612266506371016077 0ustar Description: Include patch for moving the cache directory to a safe location. Origin: https://fedorahosted.org/coolkey/changeset/67 Author: rrelyea Reviewed-by: Jack Magne Date: Thu Sep 27 23:32:51 2007 +0000 http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=ad9b6d26933ab3dfd88d42a571f7958c5b9588f8 --- a/src/coolkey/machdep.cpp +++ b/src/coolkey/machdep.cpp @@ -185,12 +185,20 @@ #define MAP_INHERIT 0 #endif +#ifndef BASEPATH +#ifdef MAC +#define BASEPATH "/var" +#else +#define BASEPATH "/var/cache" +#endif +#endif + #ifdef FULL_CLEANUP #define RESERVED_OFFSET 256 -#define MEMSEGPATH "/tmp/.pk11ipc" +#define MEMSEGPATH BASEPATH"/coolkey-lock" #else #define RESERVED_OFFSET 0 -#define MEMSEGPATH "/tmp/.pk11ipc1" +#define MEMSEGPATH BASEPATH"/coolkey" #endif struct SHMemData { @@ -208,11 +216,6 @@ #ifdef FULL_CLEANUP flock(fd,LOCK_EX); unsigned long ref = --(*(unsigned long *)addr); -#ifdef notdef - if (ref == 0) { - unlink(path); - } -#endif flock(fd, LOCK_UN); #endif munmap(addr,size+RESERVED_OFFSET); @@ -225,6 +228,73 @@ } } +/* + * The cache directory is shared and accessible by anyone, make + * sure the cache file we are opening is really a valid cache file. + */ +int safe_open(char *path, int flags, int mode, int size) +{ + struct stat buf; + int fd, ret; + + fd = open (path, flags|O_NOFOLLOW, mode); + + if (fd < 0) { + return fd; + } + + ret = fstat(fd, &buf); + if (ret < 0) { + close (fd); + return ret; + } + + /* our cache files are pretty specific, make sure we are looking + * at the correct one */ + + /* first, we should own the file ourselves, don't open a file + * that someone else wanted us to see. */ + if (buf.st_uid != getuid()) { + close(fd); + errno = EACCES; + return -1; + } + + /* next, there should only be one link in this file. Don't + * use this code to trash another file */ + if (buf.st_nlink != 1) { + close(fd); + errno = EMLINK; + return -1; + } + + /* next, This better be a regular file */ + if (!S_ISREG(buf.st_mode)) { + close(fd); + errno = EACCES; + return -1; + } + + /* if the permissions don't match, something is wrong */ + if ((buf.st_mode & 03777) != mode) { + close(fd); + errno = EACCES; + return -1; + } + + /* finally the file should be the correct size. This + * check isn't so much to protect from an attack, as it is to + * detect a corrupted cache file */ + if (buf.st_size != size) { + close(fd); + errno = EACCES; + return -1; + } + + /* OK, the file checked out, ok to continue */ + return fd; +} + SHMem::SHMem(): shmemData(0) {} SHMem * @@ -248,7 +318,7 @@ return NULL; } int mask = umask(0); - int ret = mkdir (MEMSEGPATH, 0777); + int ret = mkdir (MEMSEGPATH, 01777); umask(mask); if ((ret == -1) && (errno != EEXIST)) { delete shmemData; @@ -264,21 +334,16 @@ shmemData->path[sizeof(MEMSEGPATH)-1] = '/'; strcpy(&shmemData->path[sizeof(MEMSEGPATH)],name); - int mode = 0777; - if (strcmp(name,"token_names") != 0) { - /* each user gets his own uid array */ - sprintf(uid_str, "-%u",getuid()); - strcat(shmemData->path,uid_str); - mode = 0700; - } + sprintf(uid_str, "-%u",getuid()); + strcat(shmemData->path,uid_str); + int mode = 0600; + shmemData->fd = open(shmemData->path, O_CREAT|O_RDWR|O_EXCL|O_APPEND|O_EXLOCK, mode); - if (shmemData->fd < 0) { - needInit = false; - shmemData->fd = open(shmemData->path,O_RDWR|O_EXLOCK, mode); - } else { + if (shmemData->fd >= 0) { char *buf; int len = size+RESERVED_OFFSET; + int ret; buf = (char *)calloc(1,len); if (!buf) { @@ -289,8 +354,22 @@ delete shmemData; return NULL; } - write(shmemData->fd,buf,len); + ret = write(shmemData->fd,buf,len); + if (ret != len) { + unlink(shmemData->path); +#ifdef FULL_CLEANUP + flock(shmemData->fd, LOCK_UN); +#endif + delete shmemData; + return NULL; + } + free(buf); + } else if (errno == EEXIST) { + needInit = false; + + shmemData->fd = safe_open(shmemData->path,O_RDWR|O_EXLOCK, mode, + size+RESERVED_OFFSET); } if (shmemData->fd < 0) { delete shmemData; debian/libckyapplet1-dev.lintian-overrides0000644000000000000000000000013112266506371016071 0ustar libckyapplet1-dev: wrong-section-according-to-package-name libckyapplet1-dev => libdevel debian/rules0000755000000000000000000000105312266654205010255 0ustar #!/usr/bin/make -f %: dh $@ --with autoreconf # copy up to date files override_dh_auto_configure: ( PCSC_CFLAGS=`/usr/bin/pkg-config --cflags libpcsclite` ; PCSC_LIBS=`/usr/bin/pkg-config --libs libpcsclite` ; dh_auto_configure -- --with-debug --disable-dependency-tracking ) # avoid libtool -rpath problems override_dh_auto_build: sed < libtool > libtool-2 -e 's/^hardcode_libdir_flag_spec.*$$/hardcode_libdir_flag_spec=" -D__LIBTOOL_IS_A_FOOL__ "/' -e '/^archive_cmds="/s/"$$/ \\$$deplibs"/' mv libtool-2 libtool chmod 755 libtool dh_auto_build debian/coolkey.dirs0000644000000000000000000000003511740575742011530 0ustar usr/lib/pkcs11 usr/share/doc