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, 
