Bug#670367: pu: package coolkey/1.1.0-6 debdiff attached
Retry.
diff -u coolkey-1.1.0/debian/changelog coolkey-1.1.0/debian/changelog
--- coolkey-1.1.0/debian/changelog
+++ coolkey-1.1.0/debian/changelog
@@ -1,3 +1,18 @@
+coolkey (1.1.0-6+squeeze1) stable; urgency=low
+
+ * updated to follow the new Card Compatibility Container (CCC) specification
+ to support recently issued smartcards in Debian stable. (Closes: #670367)
+ * debian/patches/
+ 06_machdep_cpp_CVE-2007-4129.dpatch
+ 07_coolkey_latest.dpatch
+ 08_coolkey_simple_bugs.dpatch
+ 09_coolkey_thread_fix.dpatch
+ 10_coolkey_cac_rhl5.dpatch
+ 11_empty_certificates.dpatch
+ 12_pcscd_restarting.dpatch
+
+ -- A. Maitland Bottoms <bottoms@debian.org> Wed, 25 Apr 2012 22:55:05 -0400
+
coolkey (1.1.0-6) unstable; urgency=low
* debian/control: Standards-Version: 3.7.3 => 3.8.3
diff -u coolkey-1.1.0/debian/patches/00list coolkey-1.1.0/debian/patches/00list
--- coolkey-1.1.0/debian/patches/00list
+++ coolkey-1.1.0/debian/patches/00list
@@ -6,0 +7,6 @@
+07_coolkey_latest.dpatch
+08_coolkey_simple_bugs.dpatch
+09_coolkey_thread_fix.dpatch
+10_coolkey_cac_rhl5.dpatch
+11_empty_certificates.dpatch
+12_pcscd_restarting.dpatch
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/12_pcscd_restarting.dpatch
+++ coolkey-1.1.0/debian/patches/12_pcscd_restarting.dpatch
@@ -0,0 +1,83 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 12_pcscd_restarting.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Handle pcscd restarting.
+
+@DPATCH@
+
+Description: Handle pcscd restarting.
+Author: rrelyea <rrelyea@fedoraproject.org>
+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
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/07_coolkey_latest.dpatch
+++ coolkey-1.1.0/debian/patches/07_coolkey_latest.dpatch
@@ -0,0 +1,694 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 07_coolkey_latest.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Latest fixes for Safenet 330J and Gemalto 64K cards.
+
+@DPATCH@
+
+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 <jmagne@fedoraproject.org>
+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,
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/09_coolkey_thread_fix.dpatch
+++ coolkey-1.1.0/debian/patches/09_coolkey_thread_fix.dpatch
@@ -0,0 +1,164 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 09_coolkey_thread_fix.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Fix coolkey thread issues
+
+@DPATCH@
+
+Description: Fix coolkey thread issues
+Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=4099f2251ffdf1e8be0e96ede91183557ba1aaba
+Author: Robert Relyea <rrelyea@fedoraproject.org>
+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 <stdlib.h>
+ #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;
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/10_coolkey_cac_rhl5.dpatch
+++ coolkey-1.1.0/debian/patches/10_coolkey_cac_rhl5.dpatch
@@ -0,0 +1,1040 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 10_coolkey_cac_rhl5.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: work with new piv-like CAC cards
+
+@DPATCH@
+
+Date: Wed Jul 20 2010 Robert Relyea <rrelyea@redhat.com> - 1.1.0-15
+Description: work with new piv-like CAC cards
+Author: Robert Relyea <rrelyea@redhat.com>
+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 <class C>
+@@ -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<ListObjectInfo> fetchCombinedObjects(const CKYBuffer *header);
+ list<ListObjectInfo> 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
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/11_empty_certificates.dpatch
+++ coolkey-1.1.0/debian/patches/11_empty_certificates.dpatch
@@ -0,0 +1,28 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 11_empty_certificates.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Fix working with empty certificates in not zero slots.
+
+@DPATCH@
+
+From f184e5a538caa9412fa3b0e99afe92473fbd6739 Mon Sep 17 00:00:00 2001
+From: Vladimir Kravets <vova.kravets@gmail.com>
+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;
only in patch2:
unchanged:
--- coolkey-1.1.0.orig/debian/patches/08_coolkey_simple_bugs.dpatch
+++ coolkey-1.1.0/debian/patches/08_coolkey_simple_bugs.dpatch
@@ -0,0 +1,80 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 08_coolkey_simple_bugs.dpatch by <bottoms@petros.rf.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Misc bug fixes. Resolves: #485032, #250738, #497758.
+
+@DPATCH@
+
+Description: Misc bug fixes. Resolves: #485032, #250738, #497758.
+Origin: http://pkgs.fedoraproject.org/gitweb/?p=coolkey.git;a=commit;h=35fc0905e715f5851f0093726e1f5d5fd335e390
+Author: Jack Magne <jmagne@fedoraproject.org>
+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;
Reply to: