[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: