Blame SOURCES/coolkey-cac.patch

d98f6e
diff -up ./src/coolkey/slot.cpp.cac ./src/coolkey/slot.cpp
d98f6e
--- ./src/coolkey/slot.cpp.cac	2010-06-16 13:43:51.477181000 -0700
d98f6e
+++ ./src/coolkey/slot.cpp	2010-06-16 13:43:51.535179000 -0700
d98f6e
@@ -372,7 +372,7 @@ Slot::Slot(const char *readerName_, Log 
d98f6e
     : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
d98f6e
 	slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), 
d98f6e
 	isVersion1Key(false), needLogin(false), fullTokenName(false), 
d98f6e
-	mCoolkey(false),
d98f6e
+	mCoolkey(false), mOldCAC(false),
d98f6e
 #ifdef USE_SHMEM
d98f6e
 	shmem(readerName_),
d98f6e
 #endif
d98f6e
@@ -412,6 +412,9 @@ Slot::Slot(const char *readerName_, Log 
d98f6e
     }
d98f6e
     CKYBuffer_InitEmpty(&cardATR);
d98f6e
     CKYBuffer_InitEmpty(&mCUID);
d98f6e
+    for (int i=0; i < MAX_CERT_SLOTS; i++) {
d98f6e
+	CKYBuffer_InitEmpty(&cardAID[i]);
d98f6e
+    }
d98f6e
   } catch(PKCS11Exception &) {
d98f6e
 	if (conn) {
d98f6e
 	    CKYCardConnection_Destroy(conn);
d98f6e
@@ -479,6 +482,9 @@ Slot::~Slot()
d98f6e
     CKYBuffer_FreeData(&nonce);
d98f6e
     CKYBuffer_FreeData(&cardATR);
d98f6e
     CKYBuffer_FreeData(&mCUID);
d98f6e
+    for (int i=0; i < MAX_CERT_SLOTS; i++) {
d98f6e
+	CKYBuffer_FreeData(&cardAID[i]);
d98f6e
+    }
d98f6e
 }
d98f6e
 
d98f6e
 template <class C>
d98f6e
@@ -671,15 +677,9 @@ Slot::connectToToken()
d98f6e
     status = CKYApplet_SelectCoolKeyManager(conn, NULL);
d98f6e
     if (status != CKYSUCCESS) {
d98f6e
         log->log("CoolKey Select failed 0x%x\n", status);
d98f6e
-	status = CACApplet_SelectPKI(conn, 0, NULL);
d98f6e
+	status = getCACAid();
d98f6e
 	if (status != CKYSUCCESS) {
d98f6e
-            log->log("CAC Select failed 0x%x\n", status);
d98f6e
-	    if (status == CKYSCARDERR) {
d98f6e
-		log->log("CAC Card Failure 0x%x\n", 
d98f6e
-			CKYCardConnection_GetLastError(conn));
d98f6e
-		disconnect();
d98f6e
-	    }
d98f6e
-	    return;
d98f6e
+	    goto loser;
d98f6e
 	}
d98f6e
 	state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
d98f6e
 	/* skip the read of the cuid. We really don't need it and,
d98f6e
@@ -690,6 +690,15 @@ Slot::connectToToken()
d98f6e
 	needLogin = 1;
d98f6e
         mCoolkey = 0;
d98f6e
 	return;
d98f6e
+
d98f6e
+loser:
d98f6e
+        log->log("CAC Select failed 0x%x\n", status);
d98f6e
+	if (status == CKYSCARDERR) {
d98f6e
+	    log->log("CAC Card Failure 0x%x\n", 
d98f6e
+			CKYCardConnection_GetLastError(conn));
d98f6e
+	    disconnect();
d98f6e
+	}
d98f6e
+	return;
d98f6e
     }
d98f6e
     mCoolkey = 1;
d98f6e
     log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time);
d98f6e
@@ -771,17 +780,111 @@ Slot::disconnect()
d98f6e
     invalidateLogin(false);
d98f6e
 }
d98f6e
 
d98f6e
+CKYStatus
d98f6e
+Slot::getCACAid()
d98f6e
+{
d98f6e
+    CKYBuffer tBuf;
d98f6e
+    CKYBuffer vBuf;
d98f6e
+    CKYSize tlen, vlen;
d98f6e
+    CKYOffset toffset, voffset;
d98f6e
+    int certSlot = 0;
d98f6e
+    int i,length = 0;
d98f6e
+    CKYStatus status;
d98f6e
+
d98f6e
+    CKYBuffer_InitEmpty(&tBuf);
d98f6e
+    CKYBuffer_InitEmpty(&vBuf);
d98f6e
+
d98f6e
+    /* clear out the card AID's */
d98f6e
+    for (i=0; i < MAX_CERT_SLOTS; i++) {
d98f6e
+	CKYBuffer_Resize(&cardAID[i],0);
d98f6e
+    }
d98f6e
+
d98f6e
+    status = CACApplet_SelectCCC(conn,NULL);
d98f6e
+    if (status != CKYSUCCESS) {
d98f6e
+	/* are we an old CAC */
d98f6e
+	status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL);
d98f6e
+	if (status != CKYSUCCESS) {
d98f6e
+	   /* no, just fail */
d98f6e
+	   return status;
d98f6e
+	}
d98f6e
+	/* yes, fill in the old applets */
d98f6e
+	mOldCAC = true;
d98f6e
+	for (i=1; i< MAX_CERT_SLOTS; i++) {
d98f6e
+	    CACApplet_SelectPKI(conn, &cardAID[i], i, NULL);
d98f6e
+	}
d98f6e
+	return CKYSUCCESS;
d98f6e
+    }
d98f6e
+    /* definately not an old CAC */
d98f6e
+    mOldCAC = false;
d98f6e
+
d98f6e
+    /* read the TLV */
d98f6e
+    status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
d98f6e
+    if (status != CKYSUCCESS) {
d98f6e
+	goto done;
d98f6e
+    }
d98f6e
+    status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
d98f6e
+    if (status != CKYSUCCESS) {
d98f6e
+	goto done;
d98f6e
+    }
d98f6e
+    tlen = CKYBuffer_Size(&tBuf);
d98f6e
+    vlen = CKYBuffer_Size(&vBuf);
d98f6e
+
d98f6e
+    for(toffset = 2, voffset=2; 
d98f6e
+	certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ; 
d98f6e
+		voffset += length) {
d98f6e
+
d98f6e
+	CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
d98f6e
+	length = CKYBuffer_GetChar(&tBuf, toffset+1);
d98f6e
+	toffset += 2;
d98f6e
+	if (length == 0xff) {
d98f6e
+	    length = CKYBuffer_GetShortLE(&tBuf, toffset);
d98f6e
+	    toffset +=2;
d98f6e
+	}
d98f6e
+	if (tag != CAC_TAG_CARDURL) {
d98f6e
+	    continue;
d98f6e
+	}
d98f6e
+	/* CARDURL tags must be at least 10 bytes long */
d98f6e
+	if (length < 10) {
d98f6e
+	    continue;
d98f6e
+	}
d98f6e
+	/* check the app type, should be TLV_APP_PKI */
d98f6e
+	if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) {
d98f6e
+	    continue;
d98f6e
+	}
d98f6e
+	status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5);
d98f6e
+	if (status != CKYSUCCESS) {
d98f6e
+	    goto done;
d98f6e
+	}
d98f6e
+	status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, 
d98f6e
+								voffset+8, 2);
d98f6e
+	if (status != CKYSUCCESS) {
d98f6e
+	    goto done;
d98f6e
+	}
d98f6e
+	cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6);
d98f6e
+
d98f6e
+	certSlot++;
d98f6e
+    }
d98f6e
+    status = CKYSUCCESS;
d98f6e
+    if (certSlot == 0) {
d98f6e
+	status = CKYAPDUFAIL; /* probably neeed a beter error code */
d98f6e
+    }
d98f6e
+
d98f6e
+done:
d98f6e
+    CKYBuffer_FreeData(&tBuf);
d98f6e
+    CKYBuffer_FreeData(&vBuf);
d98f6e
+    return status;
d98f6e
+}
d98f6e
+
d98f6e
 void
d98f6e
 Slot::refreshTokenState()
d98f6e
 {
d98f6e
     if( cardStateMayHaveChanged() ) {
d98f6e
-log->log("card changed\n");
d98f6e
+        log->log("card changed\n");
d98f6e
 	invalidateLogin(true);
d98f6e
         closeAllSessions();
d98f6e
 	unloadObjects();
d98f6e
         connectToToken();
d98f6e
 
d98f6e
-
d98f6e
         if( state & APPLET_PERSONALIZED ) {
d98f6e
             try {
d98f6e
                 loadObjects();
d98f6e
@@ -1019,7 +1122,7 @@ Slot::makeModelString(char *model, int m
d98f6e
 
d98f6e
 struct _manList {
d98f6e
      unsigned short type;
d98f6e
-     char *string;
d98f6e
+     const char *string;
d98f6e
 };
d98f6e
 
d98f6e
 static const struct _manList  manList[] = {
d98f6e
@@ -1280,13 +1383,30 @@ void
d98f6e
 Slot::selectCACApplet(CKYByte instance)
d98f6e
 {
d98f6e
     CKYStatus status;
d98f6e
-    status = CACApplet_SelectPKI(conn, instance, NULL);
d98f6e
+    CKYBuffer *aid = &cardAID[instance];
d98f6e
+
d98f6e
+    if (CKYBuffer_Size(aid) == 0) {
d98f6e
+        disconnect();
d98f6e
+        throw PKCS11Exception(CKR_DEVICE_REMOVED);
d98f6e
+	return;
d98f6e
+    }
d98f6e
+    
d98f6e
+    status = CKYApplet_SelectFile(conn, aid, NULL);
d98f6e
     if ( status == CKYSCARDERR ) handleConnectionError();
d98f6e
     if ( status != CKYSUCCESS) {
d98f6e
         // could not select applet: this just means it's not there
d98f6e
         disconnect();
d98f6e
         throw PKCS11Exception(CKR_DEVICE_REMOVED);
d98f6e
     }
d98f6e
+    if (mOldCAC) {
d98f6e
+	return;
d98f6e
+    }
d98f6e
+    status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
d98f6e
+    if ( status == CKYSCARDERR ) handleConnectionError();
d98f6e
+    if ( status != CKYSUCCESS) {
d98f6e
+        disconnect();
d98f6e
+        throw PKCS11Exception(CKR_DEVICE_REMOVED);
d98f6e
+    }
d98f6e
 }
d98f6e
 // assume we are already in a transaction
d98f6e
 void
d98f6e
@@ -2059,10 +2179,85 @@ Slot::fetchCombinedObjects(const CKYBuff
d98f6e
     return objInfoList;
d98f6e
 }
d98f6e
 
d98f6e
+CKYStatus
d98f6e
+Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, 
d98f6e
+			      bool throwException)
d98f6e
+{
d98f6e
+    CKYStatus status;
d98f6e
+    CKYISOStatus apduRC;
d98f6e
+
d98f6e
+    if (mOldCAC) {
d98f6e
+	/* get the first 100 bytes of the cert */
d98f6e
+	status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC);
d98f6e
+	if (throwException && (status != CKYSUCCESS)) {
d98f6e
+	    handleConnectionError();
d98f6e
+	}
d98f6e
+	return status;
d98f6e
+    }
d98f6e
+
d98f6e
+    CKYBuffer tBuf;
d98f6e
+    CKYBuffer vBuf;
d98f6e
+    CKYSize tlen, vlen;
d98f6e
+    CKYOffset toffset, voffset;
d98f6e
+    int length = 0;
d98f6e
+
d98f6e
+    CKYBuffer_InitEmpty(&tBuf);
d98f6e
+    CKYBuffer_InitEmpty(&vBuf);
d98f6e
+    CKYBuffer_Resize(cert, 0);
d98f6e
+
d98f6e
+    /* handle the new CAC card read */
d98f6e
+    /* read the TLV */
d98f6e
+    status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
d98f6e
+    if (status != CKYSUCCESS) {
d98f6e
+	goto done;
d98f6e
+    }
d98f6e
+    status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
d98f6e
+    if (status != CKYSUCCESS) {
d98f6e
+	goto done;
d98f6e
+    }
d98f6e
+    tlen = CKYBuffer_Size(&tBuf);
d98f6e
+    vlen = CKYBuffer_Size(&vBuf);
d98f6e
+
d98f6e
+    /* look for the Cert out of the TLV */
d98f6e
+    for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ; 
d98f6e
+		voffset += length) {
d98f6e
+
d98f6e
+	CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
d98f6e
+	length = CKYBuffer_GetChar(&tBuf, toffset+1);
d98f6e
+	toffset += 2;
d98f6e
+	if (length == 0xff) {
d98f6e
+	    length = CKYBuffer_GetShortLE(&tBuf, toffset);
d98f6e
+	    toffset +=2;
d98f6e
+	}
d98f6e
+	if (tag != CAC_TAG_CERTIFICATE) {
d98f6e
+	    continue;
d98f6e
+	}
d98f6e
+	CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
d98f6e
+	break;
d98f6e
+    }
d98f6e
+    status = CKYSUCCESS;
d98f6e
+
d98f6e
+done:
d98f6e
+    CKYBuffer_FreeData(&tBuf);
d98f6e
+    CKYBuffer_FreeData(&vBuf);
d98f6e
+    return status;
d98f6e
+}
d98f6e
+
d98f6e
+/*
d98f6e
+ * only necessary for old CAC cards. New CAC cards have to read the
d98f6e
+ * whole cert in anyway above....
d98f6e
+ */
d98f6e
+CKYStatus
d98f6e
+Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize)
d98f6e
+{
d98f6e
+    CKYISOStatus apduRC;
d98f6e
+    assert(mOldCAC);
d98f6e
+    return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC);
d98f6e
+}
d98f6e
+
d98f6e
 void
d98f6e
 Slot::loadCACCert(CKYByte instance)
d98f6e
 {
d98f6e
-    CKYISOStatus apduRC;
d98f6e
     CKYStatus status = CKYSUCCESS;
d98f6e
     CKYBuffer cert;
d98f6e
     CKYBuffer rawCert;
d98f6e
@@ -2097,12 +2292,7 @@ Slot::loadCACCert(CKYByte instance)
d98f6e
 						 instance, OSTimeNow() - time);
d98f6e
 
d98f6e
     if (instance == 0) {
d98f6e
-	/* get the first 100 bytes of the cert */
d98f6e
-	status = CACApplet_GetCertificateFirst(conn, &rawCert, 
d98f6e
-						&nextSize, &apduRC);
d98f6e
-	if (status != CKYSUCCESS) {
d98f6e
-	    handleConnectionError();
d98f6e
-	}
d98f6e
+	readCACCertificateFirst(&rawCert, &nextSize, true);
d98f6e
 	log->log("CAC Cert %d: fetch CAC Cert:  %d ms\n", 
d98f6e
 						instance, OSTimeNow() - time);
d98f6e
     }
d98f6e
@@ -2143,8 +2333,7 @@ Slot::loadCACCert(CKYByte instance)
d98f6e
 	    shmem.setVersion(SHMEM_VERSION);
d98f6e
 	    shmem.setDataVersion(dataVersion);
d98f6e
 	} else {
d98f6e
-	    status = CACApplet_GetCertificateFirst(conn, &rawCert, 
d98f6e
-						&nextSize, &apduRC);
d98f6e
+	    status = readCACCertificateFirst(&rawCert, &nextSize, false);
d98f6e
 	
d98f6e
 	    if (status != CKYSUCCESS) {
d98f6e
 		/* CAC only requires the Certificate in pki '0' */
d98f6e
@@ -2159,8 +2348,7 @@ Slot::loadCACCert(CKYByte instance)
d98f6e
 	}
d98f6e
 
d98f6e
 	if (nextSize) {
d98f6e
-	    status = CACApplet_GetCertificateAppend(conn, &rawCert, 
d98f6e
-						nextSize, &apduRC);
d98f6e
+	    status = readCACCertificateAppend(&rawCert, nextSize);
d98f6e
 	}
d98f6e
 	log->log("CAC Cert %d: Fetch rest :  %d ms\n", 
d98f6e
 						instance, OSTimeNow() - time);
d98f6e
@@ -2176,9 +2364,10 @@ Slot::loadCACCert(CKYByte instance)
d98f6e
 
d98f6e
     log->log("CAC Cert %d: Cert has been read:  %d ms\n",
d98f6e
 						instance, OSTimeNow() - time);
d98f6e
-    if (CKYBuffer_GetChar(&rawCert,0) == 1) {
d98f6e
+    if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) {
d98f6e
 	CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
d98f6e
 	CKYSize certSize = 0;
d98f6e
+	CKYOffset offset = mOldCAC ? 1 : 0;
d98f6e
 	int zret = Z_MEM_ERROR;
d98f6e
 
d98f6e
 	do {
d98f6e
@@ -2189,7 +2378,8 @@ Slot::loadCACCert(CKYByte instance)
d98f6e
 	    }
d98f6e
 	    certSize = guessFinalSize;
d98f6e
 	    zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
d98f6e
-			CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1);
d98f6e
+			CKYBuffer_Data(&rawCert)+offset, 
d98f6e
+			CKYBuffer_Size(&rawCert)-offset);
d98f6e
 	} while (zret == Z_BUF_ERROR);
d98f6e
 
d98f6e
 	if (zret != Z_OK) {
d98f6e
@@ -2526,7 +2716,7 @@ Slot::attemptCACLogin()
d98f6e
     switch( result ) {
d98f6e
       case CKYISO_SUCCESS:
d98f6e
         break;
d98f6e
-      case 6981:
d98f6e
+      case 0x6981:
d98f6e
         throw PKCS11Exception(CKR_PIN_LOCKED);
d98f6e
       default:
d98f6e
 	if ((result & 0xff00) == 0x6300) {
d98f6e
diff -up ./src/coolkey/slot.h.cac ./src/coolkey/slot.h
d98f6e
--- ./src/coolkey/slot.h.cac	2010-06-16 13:43:51.344185000 -0700
d98f6e
+++ ./src/coolkey/slot.h	2010-06-16 13:43:51.546179000 -0700
d98f6e
@@ -294,6 +294,7 @@ class CryptParams {
d98f6e
 				 const CKYBuffer *paddedOutput) const = 0;
d98f6e
 };
d98f6e
 
d98f6e
+#define MAX_CERT_SLOTS 3
d98f6e
 class Slot {
d98f6e
 
d98f6e
   public:
d98f6e
@@ -328,6 +329,8 @@ class Slot {
d98f6e
     CKYBuffer nonce;
d98f6e
     CKYBuffer cardATR;
d98f6e
     CKYBuffer mCUID;
d98f6e
+    CKYBuffer cardAID[MAX_CERT_SLOTS];
d98f6e
+    unsigned short cardEF[MAX_CERT_SLOTS];
d98f6e
     bool isVersion1Key;
d98f6e
     bool needLogin;
d98f6e
     long publicFree;
d98f6e
@@ -335,6 +338,7 @@ class Slot {
d98f6e
     long privateFree;
d98f6e
     bool fullTokenName;
d98f6e
     bool mCoolkey;
d98f6e
+    bool mOldCAC;
d98f6e
 
d98f6e
     //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 };
d98f6e
 
d98f6e
@@ -398,6 +402,11 @@ class Slot {
d98f6e
     list<ListObjectInfo> fetchCombinedObjects(const CKYBuffer *header);
d98f6e
     list<ListObjectInfo> fetchSeparateObjects();
d98f6e
 
d98f6e
+    CKYStatus getCACAid();
d98f6e
+    CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize,
d98f6e
+                              bool throwException);
d98f6e
+    CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize);
d98f6e
+
d98f6e
     void selectApplet();
d98f6e
     void selectCACApplet(CKYByte instance);
d98f6e
     void unloadObjects();
d98f6e
diff -up ./src/libckyapplet/cky_applet.c.cac ./src/libckyapplet/cky_applet.c
d98f6e
--- ./src/libckyapplet/cky_applet.c.cac	2010-06-16 13:43:51.357181000 -0700
d98f6e
+++ ./src/libckyapplet/cky_applet.c	2010-06-16 14:47:41.305529000 -0700
d98f6e
@@ -41,7 +41,13 @@
d98f6e
 CKYStatus
d98f6e
 CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
d98f6e
 {
d98f6e
-    return CKYAPDUFactory_SelectFile(apdu,(const CKYBuffer *)param);
d98f6e
+    return CKYAPDUFactory_SelectFile(apdu, 4, 0, (const CKYBuffer *)param);
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
+CACAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
d98f6e
+{
d98f6e
+    return CKYAPDUFactory_SelectFile(apdu, 2, 12, (const CKYBuffer *)param);
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
@@ -225,10 +231,17 @@ CKYAppletFactory_GetBuiltinACL(CKYAPDU *
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
-CACAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param)
d98f6e
+CACAppletFactory_SignDecryptStep(CKYAPDU *apdu, const void *param)
d98f6e
+{
d98f6e
+    const CKYBuffer *buf=(CKYBuffer *)param;
d98f6e
+    return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_STEP, buf);
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
+CACAppletFactory_SignDecryptFinal(CKYAPDU *apdu, const void *param)
d98f6e
 {
d98f6e
     const CKYBuffer *buf=(CKYBuffer *)param;
d98f6e
-    return CACAPDUFactory_SignDecrypt(apdu, buf);
d98f6e
+    return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_FINAL, buf);
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
@@ -246,6 +259,13 @@ CACAppletFactory_GetCertificate(CKYAPDU 
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
+CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param)
d98f6e
+{
d98f6e
+    const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param;
d98f6e
+    return CACAPDUFactory_ReadFile(apdu, rfs->offset, rfs->type, rfs->count);
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
 CACAppletFactory_GetProperties(CKYAPDU *apdu, const void *param)
d98f6e
 {
d98f6e
     return CACAPDUFactory_GetProperties(apdu);
d98f6e
@@ -457,7 +477,7 @@ CKYApplet_SelectFile(CKYCardConnection *
d98f6e
 							 CKYISOStatus *apduRC)
d98f6e
 {
d98f6e
     return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, AID, NULL,
d98f6e
-		0, CKYAppletFill_Null, NULL, apduRC);
d98f6e
+		CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
d98f6e
 }
d98f6e
 
d98f6e
 static CKYByte coolkeyid[] = {0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00 };
d98f6e
@@ -477,22 +497,23 @@ CKYApplet_SelectCoolKeyManager(CKYCardCo
d98f6e
     return ret;
d98f6e
 }
d98f6e
 
d98f6e
-static CKYByte CACPKIid[] = {0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
d98f6e
+static CKYByte CACPKIid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01 };
d98f6e
 /*
d98f6e
  * Select the CoolKey applet. Must happen after we start a transaction and 
d98f6e
  * before we issue any applet specific command.
d98f6e
  */
d98f6e
 CKYStatus
d98f6e
-CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, 
d98f6e
-			       CKYISOStatus *apduRC)
d98f6e
+CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cacAID, 
d98f6e
+				CKYByte instance, CKYISOStatus *apduRC)
d98f6e
 {
d98f6e
     CKYStatus ret;
d98f6e
-    CKYBuffer CACPKIAID;
d98f6e
-    CKYBuffer_InitFromData(&CACPKIAID, CACPKIid, sizeof(CACPKIid));
d98f6e
-    CKYBuffer_SetChar(&CACPKIAID, 6, instance);
d98f6e
-    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CACPKIAID,
d98f6e
+    CKYBuffer_AppendData(cacAID, CACPKIid, sizeof(CACPKIid));
d98f6e
+    CKYBuffer_AppendChar(cacAID, instance);
d98f6e
+    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, cacAID,
d98f6e
 		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
d98f6e
-    CKYBuffer_FreeData(&CACPKIAID);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	CKYBuffer_Resize(cacAID, 0);
d98f6e
+    }
d98f6e
     return ret;
d98f6e
 }
d98f6e
 
d98f6e
@@ -515,11 +536,38 @@ CACApplet_SelectCardManager(CKYCardConne
d98f6e
     CKYBuffer CAC_CM_AID;
d98f6e
     CKYBuffer_InitFromData(&CAC_CM_AID, cacmgrid, sizeof(cacmgrid));
d98f6e
     ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
d98f6e
-		 NULL, 0, CKYAppletFill_Null, NULL, apduRC);
d98f6e
+		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
d98f6e
     CKYBuffer_FreeData(&CAC_CM_AID);
d98f6e
     return ret;
d98f6e
 }
d98f6e
 
d98f6e
+static CKYByte cacCCCid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00 };
d98f6e
+CKYStatus
d98f6e
+CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+    CKYBuffer CAC_CM_AID;
d98f6e
+    CKYBuffer_InitFromData(&CAC_CM_AID, cacCCCid, sizeof(cacCCCid));
d98f6e
+    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
d98f6e
+		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
d98f6e
+    CKYBuffer_FreeData(&CAC_CM_AID);
d98f6e
+    return ret;
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
+CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
d98f6e
+						 CKYISOStatus *apduRC)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+    CKYBuffer efBuf;
d98f6e
+    CKYBuffer_InitEmpty(&efBuf);
d98f6e
+    CKYBuffer_AppendShortLE(&efBuf, ef);
d98f6e
+    ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SelectFile, &efBuf,
d98f6e
+		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
d98f6e
+    CKYBuffer_FreeData(&efBuf);
d98f6e
+    return ret;
d98f6e
+}
d98f6e
+
d98f6e
 /*
d98f6e
  * GetCPLC cluster -- must be called with CM selected
d98f6e
  */
d98f6e
@@ -673,8 +721,8 @@ CKYApplet_ComputeCryptProcess(CKYCardCon
d98f6e
     ccd.keyNumber = keyNumber;
d98f6e
     ccd.location = location;
d98f6e
     ccd.data = data;
d98f6e
-    return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, &ccd,
d98f6e
-	nonce, 0, CKYAppletFill_Null, NULL, apduRC);
d98f6e
+    return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, 
d98f6e
+	&ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC);
d98f6e
 }
d98f6e
 
d98f6e
 /* computeCrypt returns data in the form :
d98f6e
@@ -832,11 +880,39 @@ CACApplet_SignDecrypt(CKYCardConnection 
d98f6e
 	 	CKYBuffer *result, CKYISOStatus *apduRC)
d98f6e
 {
d98f6e
     CKYStatus ret;
d98f6e
-
d98f6e
-    ret = CKYApplet_HandleAPDU(conn, 
d98f6e
-			    CACAppletFactory_SignDecrypt, data, NULL, 
d98f6e
-			    CKYBuffer_Size(data), CKYAppletFill_ReplaceBuffer, 
d98f6e
+    CKYSize dataSize = CKYBuffer_Size(data);
d98f6e
+    CKYOffset offset = 0;
d98f6e
+    CKYBuffer tmp;
d98f6e
+
d98f6e
+    CKYBuffer_InitEmpty(&tmp);
d98f6e
+
d98f6e
+    CKYBuffer_Resize(result, 0);
d98f6e
+    for(offset = 0; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; 
d98f6e
+				offset += CKY_MAX_WRITE_CHUNK_SIZE) {
d98f6e
+	CKYBuffer_Resize(&tmp,0);
d98f6e
+	CKYBuffer_AppendBuffer(&tmp, data, offset, CKY_MAX_WRITE_CHUNK_SIZE);
d98f6e
+        ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptStep, 
d98f6e
+			    &tmp, NULL, CKY_SIZE_UNKNOWN, 
d98f6e
+			    CKYAppletFill_AppendBuffer, 
d98f6e
 			    result, apduRC);
d98f6e
+	if (ret != CKYSUCCESS) {
d98f6e
+	    goto done;
d98f6e
+	}
d98f6e
+    }
d98f6e
+    CKYBuffer_Resize(&tmp,0);
d98f6e
+    CKYBuffer_AppendBuffer(&tmp, data, offset, dataSize - offset);
d98f6e
+    ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptFinal, 
d98f6e
+			    &tmp, NULL, CKY_SIZE_UNKNOWN, 
d98f6e
+			    CKYAppletFill_AppendBuffer, 
d98f6e
+			    result, apduRC);
d98f6e
+
d98f6e
+    if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != dataSize)) {
d98f6e
+	/* RSA returns the same data size as input, didn't happen, so
d98f6e
+	 * something is wrong. */
d98f6e
+    }
d98f6e
+
d98f6e
+done:
d98f6e
+    CKYBuffer_FreeData(&tmp);
d98f6e
     return ret;
d98f6e
 }
d98f6e
 
d98f6e
@@ -895,6 +971,63 @@ CACApplet_GetCertificate(CKYCardConnecti
d98f6e
     }
d98f6e
     return ret;
d98f6e
 }
d98f6e
+
d98f6e
+/*
d98f6e
+ * Read a CAC Tag/Value file 
d98f6e
+ */
d98f6e
+CKYStatus
d98f6e
+CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, CKYBuffer *buffer, 
d98f6e
+		    CKYISOStatus *apduRC)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+    CKYISOStatus status;
d98f6e
+    CKYByte maxtransfer;
d98f6e
+    unsigned short offset = 0;
d98f6e
+    unsigned short size;
d98f6e
+    CACAppletArgReadFile rfs;
d98f6e
+
d98f6e
+    CKYBuffer_Resize(buffer,0);
d98f6e
+    if (apduRC == NULL) {
d98f6e
+	apduRC = &status;
d98f6e
+    }
d98f6e
+    rfs.offset = 0;
d98f6e
+    rfs.count = 2;
d98f6e
+    rfs.type = type;
d98f6e
+
d98f6e
+    /* APDU's are expensive, Grab a big chunk of the file first if possible */
d98f6e
+    ret = CKYApplet_HandleAPDU(conn, 
d98f6e
+			    CACAppletFactory_ReadFile, &rfs, NULL, 
d98f6e
+			    rfs.count, CKYAppletFill_AppendBuffer,
d98f6e
+			    buffer, apduRC);
d98f6e
+    /* file is probably smaller than 100 bytes, get the actual size first */
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	return ret;
d98f6e
+    }
d98f6e
+    size = CKYBuffer_GetShortLE(buffer, 0) + 2 /* include the length itself */;
d98f6e
+    maxtransfer = CKY_MAX_READ_CHUNK_SIZE;
d98f6e
+    /* get the rest of the buffer if necessary */
d98f6e
+    for (offset = CKYBuffer_Size(buffer); size > offset; 
d98f6e
+				offset = CKYBuffer_Size(buffer)) {
d98f6e
+	rfs.offset = offset;
d98f6e
+	rfs.count = MIN(size - offset, maxtransfer);
d98f6e
+	ret = CKYApplet_HandleAPDU(conn, 
d98f6e
+			    CACAppletFactory_ReadFile, &rfs, NULL, 
d98f6e
+			    rfs.count, CKYAppletFill_AppendBuffer,
d98f6e
+			    buffer, apduRC);
d98f6e
+	if (ret != CKYSUCCESS) {
d98f6e
+	    if (*apduRC == CAC_INVALID_PARAMS) {
d98f6e
+		maxtransfer = maxtransfer/2;
d98f6e
+		if (maxtransfer == 0) {
d98f6e
+		    return ret;
d98f6e
+		}
d98f6e
+	    } else {
d98f6e
+		return ret;
d98f6e
+	    }
d98f6e
+ 	}
d98f6e
+    }
d98f6e
+    return ret;
d98f6e
+}
d98f6e
+
d98f6e
 CKYStatus 
d98f6e
 CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, 
d98f6e
 			CKYSize *nextSize, CKYISOStatus *apduRC)
d98f6e
diff -up ./src/libckyapplet/cky_applet.h.cac ./src/libckyapplet/cky_applet.h
d98f6e
--- ./src/libckyapplet/cky_applet.h.cac	2010-06-16 13:43:51.370181000 -0700
d98f6e
+++ ./src/libckyapplet/cky_applet.h	2010-06-16 13:43:51.572179000 -0700
d98f6e
@@ -71,6 +71,15 @@ typedef unsigned short CKYISOStatus; /* 
d98f6e
 #define CKYISO_INTERNAL_ERROR        0x9cff  /* Reserved for debugging, 
d98f6e
 					     * shouldn't happen */
d98f6e
 
d98f6e
+#define CAC_INVALID_PARAMS	    0x6a83
d98f6e
+#define CAC_TAG_FILE			1
d98f6e
+#define CAC_VALUE_FILE			2
d98f6e
+
d98f6e
+
d98f6e
+#define CAC_TAG_CARDURL			0xf3
d98f6e
+#define CAC_TAG_CERTIFICATE		0x70
d98f6e
+#define CAC_TLV_APP_PKI			0x04
d98f6e
+
d98f6e
 /*
d98f6e
  * Pin Constants as used by our applet
d98f6e
  */
d98f6e
@@ -209,6 +218,12 @@ typedef struct _CKYAppletArgComputeCrypt
d98f6e
     const CKYBuffer *sig;
d98f6e
 } CKYAppletArgComputeCrypt;
d98f6e
 
d98f6e
+typedef struct _CACAppletArgReadFile {
d98f6e
+    CKYByte   type;
d98f6e
+    CKYByte   count;
d98f6e
+    unsigned short offset;
d98f6e
+} CACAppletArgReadFile;
d98f6e
+
d98f6e
 /* fills in an APDU from a structure -- form of all the generic factories*/
d98f6e
 typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param);
d98f6e
 /* fills in an a structure from a response -- form of all the fill structures*/
d98f6e
@@ -451,9 +466,17 @@ CKYStatus CKYApplet_DeleteObject(CKYCard
d98f6e
 /* Select the CAC card manager.  Can happen with either applet selected */
d98f6e
 CKYStatus CACApplet_SelectCardManager(CKYCardConnection *conn, 
d98f6e
 							CKYISOStatus *apduRC);
d98f6e
-/* Can happen with either applet selected */
d98f6e
-CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance,
d98f6e
-			      CKYISOStatus *apduRC);
d98f6e
+/* Select the CAC CC container. Can happen with either applet selected */
d98f6e
+CKYStatus CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC);
d98f6e
+/* Select an old CAC applet and fill in the cardAID */
d98f6e
+CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cardAid,
d98f6e
+			      CKYByte instance, CKYISOStatus *apduRC);
d98f6e
+/* read a TLV file */
d98f6e
+CKYStatus CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, 
d98f6e
+			     CKYBuffer *buffer, CKYISOStatus *apduRC);
d98f6e
+CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
d98f6e
+			     CKYISOStatus *apduRC);
d98f6e
+
d98f6e
 /* must happen with PKI applet selected */
d98f6e
 CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data,
d98f6e
 		CKYBuffer *result, CKYISOStatus *apduRC);
d98f6e
diff -up ./src/libckyapplet/cky_base.c.cac ./src/libckyapplet/cky_base.c
d98f6e
--- ./src/libckyapplet/cky_base.c.cac	2006-06-09 11:44:17.000000000 -0700
d98f6e
+++ ./src/libckyapplet/cky_base.c	2010-06-16 13:43:51.583179000 -0700
d98f6e
@@ -220,6 +220,22 @@ CKYBuffer_AppendShort(CKYBuffer *buf, un
d98f6e
     return CKYSUCCESS;
d98f6e
 }
d98f6e
 
d98f6e
+/* append a short in network order */
d98f6e
+CKYStatus
d98f6e
+CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+
d98f6e
+    ret = CKYBuffer_Reserve(buf, buf->len + 2);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	return ret;
d98f6e
+    }
d98f6e
+    buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff);
d98f6e
+    buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff);
d98f6e
+    buf->len += 2;
d98f6e
+    return CKYSUCCESS;
d98f6e
+}
d98f6e
+
d98f6e
 /* append a long in applet order */
d98f6e
 CKYStatus
d98f6e
 CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val)
d98f6e
@@ -238,6 +254,24 @@ CKYBuffer_AppendLong(CKYBuffer *buf, uns
d98f6e
     return CKYSUCCESS;
d98f6e
 }
d98f6e
 
d98f6e
+/* append a long in applet order */
d98f6e
+CKYStatus
d98f6e
+CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+
d98f6e
+    ret = CKYBuffer_Reserve(buf, buf->len + 4);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	return ret;
d98f6e
+    }
d98f6e
+    buf->data[buf->len+3] = (CKYByte) ((val >> 24) & 0xff);
d98f6e
+    buf->data[buf->len+2] = (CKYByte) ((val >> 16) & 0xff);
d98f6e
+    buf->data[buf->len+1] = (CKYByte) ((val >>  8) & 0xff);
d98f6e
+    buf->data[buf->len+0] = (CKYByte) ((val >>  0) & 0xff);
d98f6e
+    buf->len += 4;
d98f6e
+    return CKYSUCCESS;
d98f6e
+}
d98f6e
+
d98f6e
 CKYStatus
d98f6e
 CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data, CKYSize len)
d98f6e
 {
d98f6e
@@ -351,6 +385,22 @@ CKYBuffer_SetShort(CKYBuffer *buf, CKYOf
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
+CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+
d98f6e
+    if (buf->len < offset+2) {
d98f6e
+	ret = CKYBuffer_Resize(buf,offset+2);
d98f6e
+	if (ret != CKYSUCCESS) {
d98f6e
+	    return ret;
d98f6e
+	}
d98f6e
+    }
d98f6e
+    buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff);
d98f6e
+    buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff);
d98f6e
+    return CKYSUCCESS;
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
 CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val)
d98f6e
 {
d98f6e
     CKYStatus ret;
d98f6e
@@ -368,6 +418,24 @@ CKYBuffer_SetLong(CKYBuffer *buf, CKYOff
d98f6e
     return CKYSUCCESS;
d98f6e
 }
d98f6e
 
d98f6e
+CKYStatus
d98f6e
+CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+
d98f6e
+    if (buf->len < offset+4) {
d98f6e
+	ret = CKYBuffer_Resize(buf,offset+4);
d98f6e
+	if (ret != CKYSUCCESS) {
d98f6e
+	    return ret;
d98f6e
+	}
d98f6e
+    }
d98f6e
+    buf->data[offset+3] = (CKYByte) ((val >> 24) & 0xff);
d98f6e
+    buf->data[offset+2] = (CKYByte) ((val >> 16) & 0xff);
d98f6e
+    buf->data[offset+1] = (CKYByte) ((val >>  8) & 0xff);
d98f6e
+    buf->data[offset+0] = (CKYByte) ((val >>  0) & 0xff);
d98f6e
+    return CKYSUCCESS;
d98f6e
+}
d98f6e
+
d98f6e
 CKYByte
d98f6e
 CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset)
d98f6e
 {
d98f6e
@@ -388,6 +456,18 @@ CKYBuffer_GetShort(const CKYBuffer *buf,
d98f6e
     val |= ((unsigned short)buf->data[offset+1]) << 0;
d98f6e
     return val;
d98f6e
 }
d98f6e
+
d98f6e
+unsigned short
d98f6e
+CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset)
d98f6e
+{
d98f6e
+    unsigned short val;
d98f6e
+    if (buf->len < offset+2) {
d98f6e
+	return 0;
d98f6e
+    }
d98f6e
+    val  = ((unsigned short)buf->data[offset+1]) << 8;
d98f6e
+    val |= ((unsigned short)buf->data[offset+0]) << 0;
d98f6e
+    return val;
d98f6e
+}
d98f6e
 	
d98f6e
 unsigned long
d98f6e
 CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset)
d98f6e
@@ -402,6 +482,20 @@ CKYBuffer_GetLong(const CKYBuffer *buf, 
d98f6e
     val |= ((unsigned long)buf->data[offset+3]) << 0;
d98f6e
     return val;
d98f6e
 }
d98f6e
+
d98f6e
+unsigned long
d98f6e
+CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset)
d98f6e
+{
d98f6e
+    unsigned long val;
d98f6e
+    if (buf->len < offset+4) {
d98f6e
+	return 0;
d98f6e
+    }
d98f6e
+    val  = ((unsigned long)buf->data[offset+3]) << 24;
d98f6e
+    val |= ((unsigned long)buf->data[offset+2]) << 16;
d98f6e
+    val |= ((unsigned long)buf->data[offset+1]) << 8;
d98f6e
+    val |= ((unsigned long)buf->data[offset+0]) << 0;
d98f6e
+    return val;
d98f6e
+}
d98f6e
 	
d98f6e
 CKYStatus
d98f6e
 CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen)
d98f6e
diff -up ./src/libckyapplet/cky_base.h.cac ./src/libckyapplet/cky_base.h
d98f6e
--- ./src/libckyapplet/cky_base.h.cac	2006-06-09 11:44:17.000000000 -0700
d98f6e
+++ ./src/libckyapplet/cky_base.h	2010-06-16 13:43:51.592179000 -0700
d98f6e
@@ -170,9 +170,15 @@ CKYStatus CKYBuffer_AppendChar(CKYBuffer
d98f6e
 /* append a short in applet order */
d98f6e
 CKYStatus CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val);
d98f6e
 
d98f6e
+/* append a short in little endian order */
d98f6e
+CKYStatus CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val);
d98f6e
+
d98f6e
 /* append a long in applet order */
d98f6e
 CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val);
d98f6e
 
d98f6e
+/* append a long in little endian order */
d98f6e
+CKYStatus CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val);
d98f6e
+
d98f6e
 /* append data. the data starts at data and extends len bytes */
d98f6e
 CKYStatus CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len);
d98f6e
 
d98f6e
@@ -210,12 +216,18 @@ CKYStatus CKYBuffer_SetChars(CKYBuffer *
d98f6e
 CKYStatus CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val);
d98f6e
 CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val);
d98f6e
 
d98f6e
+/* These functions work in little endian order */
d98f6e
+CKYStatus CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val);
d98f6e
+CKYStatus CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val);
d98f6e
 /* read a character from offset. If offset is beyond the end of the buffer,
d98f6e
  * then the function returns '0' */
d98f6e
 CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset);
d98f6e
 /* These functions work in applet order */
d98f6e
 unsigned short CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset);
d98f6e
 unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset);
d98f6e
+/* These functions work in little endian order */
d98f6e
+unsigned short CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset);
d98f6e
+unsigned long CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset);
d98f6e
 
d98f6e
 /* clear out all the data in a buffer */
d98f6e
 void CKYBuffer_Zero(CKYBuffer *buf);
d98f6e
diff -up ./src/libckyapplet/cky_factory.c.cac ./src/libckyapplet/cky_factory.c
d98f6e
--- ./src/libckyapplet/cky_factory.c.cac	2010-06-16 13:43:51.393185000 -0700
d98f6e
+++ ./src/libckyapplet/cky_factory.c	2010-06-16 14:48:08.885473000 -0700
d98f6e
@@ -25,12 +25,13 @@
d98f6e
  * special commands can be issued at any time 
d98f6e
  */
d98f6e
 CKYStatus
d98f6e
-CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID)
d98f6e
+CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
d98f6e
+			  const CKYBuffer *AID)
d98f6e
 {
d98f6e
     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
d98f6e
     CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE);
d98f6e
-    CKYAPDU_SetP1(apdu, 0x04);
d98f6e
-    CKYAPDU_SetP2(apdu, 0x00);
d98f6e
+    CKYAPDU_SetP1(apdu, p1);
d98f6e
+    CKYAPDU_SetP2(apdu, p2);
d98f6e
     return CKYAPDU_SetSendDataBuffer(apdu, AID);
d98f6e
 }
d98f6e
 
d98f6e
@@ -131,6 +132,7 @@ fail:
d98f6e
     return ret;
d98f6e
 }
d98f6e
 
d98f6e
+
d98f6e
 CKYStatus
d98f6e
 CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber, 
d98f6e
 		CKYByte location, const CKYBuffer *data, const CKYBuffer *sig)
d98f6e
@@ -572,11 +574,11 @@ CKYAPDUFactory_GetBuiltinACL(CKYAPDU *ap
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
-CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data)
d98f6e
+CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, const CKYBuffer *data)
d98f6e
 {
d98f6e
     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
d98f6e
     CKYAPDU_SetINS(apdu, CAC_INS_SIGN_DECRYPT);
d98f6e
-    CKYAPDU_SetP1(apdu, 0x00);
d98f6e
+    CKYAPDU_SetP1(apdu, type);
d98f6e
     CKYAPDU_SetP2(apdu, 0x00);
d98f6e
     return CKYAPDU_SetSendDataBuffer(apdu, data);
d98f6e
 }
d98f6e
@@ -592,6 +594,36 @@ CACAPDUFactory_GetCertificate(CKYAPDU *a
d98f6e
 }
d98f6e
 
d98f6e
 CKYStatus
d98f6e
+CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, 	
d98f6e
+					CKYByte type, CKYByte count)
d98f6e
+{
d98f6e
+    CKYStatus ret;
d98f6e
+    CKYBuffer buf;
d98f6e
+
d98f6e
+    CKYBuffer_InitEmpty(&buf;;
d98f6e
+    CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM);
d98f6e
+    CKYAPDU_SetINS(apdu, CAC_INS_READ_FILE);
d98f6e
+    CKYAPDU_SetP1(apdu, (offset >> 8) & 0xff);
d98f6e
+    CKYAPDU_SetP2(apdu, offset & 0xff);
d98f6e
+    ret = CKYBuffer_Reserve(&buf, 2);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	    goto fail;
d98f6e
+    }
d98f6e
+    ret = CKYBuffer_AppendChar(&buf, type);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	    goto fail;
d98f6e
+    }
d98f6e
+    ret = CKYBuffer_AppendChar(&buf, count);
d98f6e
+    if (ret != CKYSUCCESS) {
d98f6e
+	    goto fail;
d98f6e
+    } 
d98f6e
+    ret = CKYAPDU_SetSendDataBuffer(apdu, &buf;;
d98f6e
+fail:
d98f6e
+    CKYBuffer_FreeData(&buf;;
d98f6e
+    return ret;
d98f6e
+}
d98f6e
+
d98f6e
+CKYStatus
d98f6e
 CACAPDUFactory_GetProperties(CKYAPDU *apdu)
d98f6e
 {
d98f6e
     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
d98f6e
diff -up ./src/libckyapplet/cky_factory.h.cac ./src/libckyapplet/cky_factory.h
d98f6e
--- ./src/libckyapplet/cky_factory.h.cac	2010-06-16 13:43:51.402181000 -0700
d98f6e
+++ ./src/libckyapplet/cky_factory.h	2010-06-16 14:43:20.867049000 -0700
d98f6e
@@ -86,7 +86,11 @@
d98f6e
 #define CAC_INS_SIGN_DECRYPT	0x42
d98f6e
 #define CAC_INS_VERIFY_PIN	0x20
d98f6e
 #define CAC_INS_GET_PROPERTIES	0x56
d98f6e
+#define CAC_INS_READ_FILE	0x52
d98f6e
+
d98f6e
 #define CAC_SIZE_GET_PROPERTIES	48
d98f6e
+#define CAC_P1_STEP		0x80
d98f6e
+#define CAC_P1_FINAL		0x00
d98f6e
 
d98f6e
 /*
d98f6e
  * Fixed return sized from various commands
d98f6e
@@ -169,7 +173,8 @@
d98f6e
 CKY_BEGIN_PROTOS
d98f6e
 
d98f6e
 /* function based factorys */
d98f6e
-CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID);
d98f6e
+CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
d98f6e
+				    const CKYBuffer *AID);
d98f6e
 CKYStatus CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu);
d98f6e
 CKYStatus CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu);
d98f6e
 CKYStatus CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence);
d98f6e
@@ -211,9 +216,12 @@ CKYStatus CKYAPDUFactory_SeedRandom(CKYA
d98f6e
 CKYStatus CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu);
d98f6e
 CKYStatus CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu);
d98f6e
 
d98f6e
-CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data);
d98f6e
+CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, 
d98f6e
+				     const CKYBuffer *data);
d98f6e
 CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin);
d98f6e
 CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size);
d98f6e
+CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, 
d98f6e
+				  CKYByte type, CKYByte count);
d98f6e
 CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu);
d98f6e
 
d98f6e
 CKY_END_PROTOS