6399N/AUpstream fixes already included in the latest community updates to coolkey v1.1.0
6399N/A
6399N/AAdds support and fixes for newer versions of CAC and PIV cards.
6399N/AAddresses issues seen with pcscd restart.
6399N/A
6399N/A--- ORIGINAL/./src/coolkey/slot.cpp 2016-06-24 16:07:20.111616788 -0400
6399N/A+++ ././src/coolkey/slot.cpp 2016-06-27 21:05:04.901200633 -0400
6996N/A@@ -25,7 +25,6 @@
6996N/A #include "PKCS11Exception.h"
6996N/A #include <winscard.h>
6996N/A #include "slot.h"
6996N/A-#include <memory.h>
6996N/A #include "zlib.h"
6996N/A #include "params.h"
6996N/A
6996N/A@@ -33,9 +32,7 @@
6996N/A
6996N/A #define MIN(x, y) ((x) < (y) ? (x) : (y))
6996N/A
6996N/A-using std::auto_ptr;
6996N/A
6996N/A-
6996N/A #ifdef DEBUG
6996N/A #define PRINTF(args) printf args
6996N/A #else
6399N/A@@ -56,6 +56,34 @@
6399N/A { 0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72,
6399N/A 0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 };
6399N/A
6399N/A+
6399N/A+/* ECC curve information
6399N/A+ * Provide information for the limited set of curves supported by our smart card(s).
6399N/A+ *
6399N/A+ */
6399N/A+
6399N/A+typedef struct curveBytes2Name {
6399N/A+ const CKYByte * bytes;
6399N/A+ const char *curveName;
6399N/A+ unsigned int length;
6399N/A+
6399N/A+} CurveBytes2Name;
6399N/A+
6399N/A+/* First byte is length of oid byte array. */
6399N/A+
6399N/A+const CKYByte nistp256[] = { 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
6399N/A+const CKYByte nistp384[] = { 0x5, 0x2b, 0x81, 0x04, 0x00, 0x22 };
6399N/A+const CKYByte nistp521[] = { 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23 };
6399N/A+
6399N/A+const int numECCurves = 3;
6399N/A+
6399N/A+static CurveBytes2Name curveBytesNamePair[] =
6399N/A+{
6399N/A+ { nistp256, "nistp256", 256 },
6399N/A+ { nistp384, "nistp384", 384 },
6399N/A+ { nistp521, "nistp521", 521 }
6399N/A+};
6399N/A+
6399N/A SlotList::SlotList(Log *log_) : log(log_)
6399N/A {
6399N/A // initialize things to NULL so we can recover from an exception
6399N/A@@ -138,7 +166,11 @@
6399N/A throw PKCS11Exception(CKR_HOST_MEMORY);
6399N/A memset(newSlots, 0, numReaders*sizeof(Slot*));
6399N/A
6399N/A- memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
6399N/A+ /* keep coverity happy, even though slot == NULL implies that
6399N/A+ * numSlots == 0 */
6399N/A+ if (slots) {
6399N/A+ memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
6399N/A+ }
6399N/A
6399N/A for (unsigned int i=numSlots; i < numReaders; i++) {
6399N/A newSlots[i] = new
6399N/A@@ -205,6 +237,29 @@
6399N/A return FALSE;
6399N/A }
6399N/A
6399N/A+bool
6399N/A+SlotList::readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList)
6399N/A+{
6399N/A+ if( !readerName || !readerNameList) {
6399N/A+ return FALSE;
6399N/A+ }
6399N/A+
6399N/A+ int i = 0;
6399N/A+ int readerNameCnt = CKYReaderNameList_GetCount(*readerNameList);
6399N/A+
6399N/A+ const char *curReaderName = NULL;
6399N/A+ for(i=0; i < readerNameCnt; i++) {
6399N/A+ curReaderName = CKYReaderNameList_GetValue(*readerNameList,i);
6399N/A+
6399N/A+ if(!strcmp(curReaderName,readerName)) {
6399N/A+ return TRUE;
6399N/A+ }
6399N/A+
6399N/A+ }
6399N/A+
6399N/A+ return FALSE;
6399N/A+}
6399N/A+
6399N/A /*
6399N/A * you need to hold the ReaderList Lock before you can update the ReaderList
6399N/A */
6399N/A@@ -216,32 +271,19 @@
6399N/A
6399N/A CKYStatus status = CKYCardContext_ListReaders(context, &readerNames);
6399N/A if ( status != CKYSUCCESS ) {
6399N/A- throw PKCS11Exception(CKR_GENERAL_ERROR,
6399N/A+ /* if the service is stopped, treat it as if we have no readers */
6399N/A+ if ((CKYCardContext_GetLastError(context) != SCARD_E_NO_SERVICE) &&
6399N/A+ (CKYCardContext_GetLastError(context) != SCARD_E_SERVICE_STOPPED)) {
6399N/A+ throw PKCS11Exception(CKR_GENERAL_ERROR,
6399N/A "Failed to list readers: 0x%x\n",
6399N/A CKYCardContext_GetLastError(context));
6399N/A+ }
6399N/A }
6399N/A
6399N/A- if (!readerStates) {
6399N/A+ if (readerStates == NULL && readerNames != NULL) {
6399N/A /* fresh Reader State list, just create it */
6399N/A readerStates = CKYReader_CreateArray(readerNames, (CKYSize *)&numReaders);
6399N/A
6399N/A- /* if we have no readers, make sure we have at least one to keep things
6399N/A- * happy */
6399N/A- if (readerStates == NULL &&
6399N/A- CKYReaderNameList_GetCount(readerNames) == 0) {
6399N/A- readerStates = (SCARD_READERSTATE *)
6399N/A- malloc(sizeof(SCARD_READERSTATE));
6399N/A- if (readerStates) {
6399N/A- CKYReader_Init(readerStates);
6399N/A- status = CKYReader_SetReaderName(readerStates, "E-Gate 0 0");
6399N/A- if (status != CKYSUCCESS) {
6399N/A- CKYReader_DestroyArray(readerStates, 1);
6399N/A- readerStates = NULL;
6399N/A- } else {
6399N/A- numReaders = 1;
6399N/A- }
6399N/A- }
6399N/A- }
6399N/A CKYReaderNameList_Destroy(readerNames);
6399N/A
6399N/A if (readerStates == NULL) {
6399N/A@@ -251,6 +293,16 @@
6399N/A return;
6399N/A }
6399N/A
6399N/A+ if (readerStates == NULL) {
6399N/A+ /* if we didn't have any readers before and we did get new names,
6399N/A+ * that is handled above. If we didn't have any readers before, and
6399N/A+ * we didn't get any names, there is nothing to update. blow out now.
6399N/A+ * This more efficient and makes coverity happy (since coverity doesn't
6399N/A+ * know numReaders and readerStates are linked). */
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+
6399N/A /* it would be tempting at this point just to see if we have more readers
6399N/A * then specified previously. The problem with this is it is possible that
6399N/A * some readers have been deleted, so the only way to tell if we have
6399N/A@@ -258,6 +310,33 @@
6399N/A * don't recognize.
6399N/A */
6399N/A
6399N/A+ /* Iterate through all the readers to see if we need to make unavailable any
6399N/A+ * freshly removed readers. Also, see if any previously removed
6399N/A+ * readers have come back from the dead and don't need to be ignored.
6399N/A+ */
6399N/A+
6399N/A+ const char *curReaderName = NULL;
6399N/A+ unsigned long knownState = 0;
6399N/A+ for(unsigned int ri = 0 ; ri < numReaders; ri ++) {
6399N/A+ knownState = CKYReader_GetKnownState(&readerStates[ri]);
6399N/A+
6399N/A+ curReaderName = CKYReader_GetReaderName(&readerStates[ri]);
6399N/A+ if(readerNames && readerNameExistsInList(curReaderName,&readerNames)) {
6399N/A+ CKYReader_SetKnownState(&readerStates[ri],
6399N/A+ knownState & ~SCARD_STATE_IGNORE);
6399N/A+ } else {
6399N/A+ if (!(knownState & SCARD_STATE_UNAVAILABLE))
6399N/A+ CKYReader_SetKnownState(&readerStates[ri],
6399N/A+ knownState | SCARD_STATE_UNAVAILABLE | SCARD_STATE_CHANGED);
6399N/A+ }
6399N/A+ }
6399N/A+
6399N/A+ if (readerNames == NULL) {
6399N/A+ /* OK we've marked everything unavailable, we clearly
6399N/A+ * aren't adding any readers, so we can blow out here */
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A const char *newReadersData[MAX_READER_DELTA];
6399N/A const char **newReaders = &newReadersData[0];
6399N/A unsigned int newReaderCount = 0;
6399N/A@@ -330,7 +409,9 @@
6399N/A : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
6399N/A slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN),
6399N/A isVersion1Key(false), needLogin(false), fullTokenName(false),
6399N/A- mCoolkey(false),
6399N/A+ mCoolkey(false), mOldCAC(false),mCACLocalLogin(false),
6399N/A+ pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS),
6399N/A+ algs(ALG_NONE),
6399N/A #ifdef USE_SHMEM
6399N/A shmem(readerName_),
6399N/A #endif
6399N/A@@ -370,6 +451,9 @@
6399N/A }
6399N/A CKYBuffer_InitEmpty(&cardATR);
6399N/A CKYBuffer_InitEmpty(&mCUID);
6399N/A+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
6399N/A+ CKYBuffer_InitEmpty(&cardAID[i]);
6399N/A+ }
6399N/A } catch(PKCS11Exception &) {
6399N/A if (conn) {
6399N/A CKYCardConnection_Destroy(conn);
6399N/A@@ -437,6 +521,9 @@
6399N/A CKYBuffer_FreeData(&nonce);
6399N/A CKYBuffer_FreeData(&cardATR);
6399N/A CKYBuffer_FreeData(&mCUID);
6399N/A+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
6399N/A+ CKYBuffer_FreeData(&cardAID[i]);
6399N/A+ }
6399N/A }
6399N/A
6399N/A template <class C>
6399N/A@@ -527,10 +614,39 @@
6399N/A return rv;
6399N/A }
6399N/A
6399N/A+bool
6399N/A+Slot::getPIVLoginType(void)
6399N/A+{
6399N/A+ CKYStatus status;
6399N/A+ CKYISOStatus apduRC;
6399N/A+ CKYBuffer buffer;
6399N/A+ bool local = true;
6399N/A+
6399N/A+ CKYBuffer_InitEmpty(&buffer);
6399N/A+
6399N/A+ /* get the discovery object */
6399N/A+ status = PIVApplet_GetCertificate(conn, &buffer, 0x7e, &apduRC);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ /* Discovery object optional, PIV defaults to local */
6399N/A+ goto done;
6399N/A+ }
6399N/A+ /* techically we probably should parse out the TLVs, but the PIV
6399N/A+ * specifies exactly what they should be, so we know exactly which
6399N/A+ * byte to look at */
6399N/A+ if ((CKYBuffer_Size(&buffer) >= 20) &&
6399N/A+ (CKYBuffer_GetChar(&buffer,17) == 0x60)) {
6399N/A+ /* This tells us we should use global login for this piv card */
6399N/A+ local = false;
6399N/A+ }
6399N/A+done:
6399N/A+ CKYBuffer_FreeData(&buffer);
6399N/A+ return true;
6399N/A+}
6399N/A+
6399N/A void
6399N/A Slot::connectToToken()
6399N/A {
6399N/A- CKYStatus status;
6399N/A+ CKYStatus status = CKYSCARDERR;
6399N/A OSTime time = OSTimeNow();
6399N/A
6399N/A mCoolkey = 0;
6399N/A@@ -539,13 +655,32 @@
6399N/A
6399N/A // try to connect to the card
6399N/A if( ! CKYCardConnection_IsConnected(conn) ) {
6399N/A- status = CKYCardConnection_Connect(conn, readerName);
6399N/A- if( status != CKYSUCCESS ) {
6399N/A- log->log("Unable to connect to token\n");
6399N/A+ int i = 0;
6399N/A+ //for cranky readers try again a few more times
6399N/A+ status = CKYSCARDERR;
6399N/A+ while( i++ < 5 && status != CKYSUCCESS )
6399N/A+ {
6399N/A+ status = CKYCardConnection_Connect(conn, readerName);
6399N/A+ if( status != CKYSUCCESS &&
6399N/A+ CKYCardConnection_GetLastError(conn) == SCARD_E_PROTO_MISMATCH )
6399N/A+ {
6399N/A+ log->log("Unable to connect to token status %d ConnGetGetLastError %x .\n",status,CKYCardConnection_GetLastError(conn));
6399N/A+
6399N/A+ }
6399N/A+ else
6399N/A+ {
6399N/A+ break;
6399N/A+ }
6399N/A+ OSSleep(100000);
6399N/A+ }
6399N/A+
6399N/A+ if( status != CKYSUCCESS)
6399N/A+ {
6399N/A state = UNKNOWN;
6399N/A return;
6399N/A }
6399N/A }
6399N/A+
6399N/A log->log("time connect: Connect Time %d ms\n", OSTimeNow() - time);
6399N/A if (!slotInfoFound) {
6399N/A readSlotInfo();
6399N/A@@ -564,15 +699,10 @@
6399N/A state = CARD_PRESENT;
6399N/A }
6399N/A
6399N/A- if ( CKYBuffer_DataIsEqual(&cardATR, ATR, sizeof (ATR)) ||
6399N/A- CKYBuffer_DataIsEqual(&cardATR, ATR1, sizeof(ATR1)) ||
6399N/A- CKYBuffer_DataIsEqual(&cardATR, ATR2, sizeof(ATR2)) ) {
6399N/A-
6399N/A- if (Params::hasParam("noAppletOK"))
6399N/A- {
6399N/A- state |= APPLET_SELECTABLE;
6399N/A- mCoolkey = 1;
6399N/A- }
6399N/A+ if (Params::hasParam("noAppletOK"))
6399N/A+ {
6399N/A+ state |= APPLET_SELECTABLE;
6399N/A+ mCoolkey = 1;
6399N/A }
6399N/A
6399N/A /* support CAC card. identify the card based on applets, not the ATRS */
6399N/A@@ -613,17 +743,30 @@
6399N/A // see if the applet is selectable
6399N/A
6399N/A log->log("time connnect: Begin transaction %d ms\n", OSTimeNow() - time);
6399N/A+ status = PIVApplet_Select(conn, NULL);
6399N/A+ if (status == CKYSUCCESS) {
6399N/A+ /* CARD is a PIV card */
6399N/A+ state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
6399N/A+ isVersion1Key = 0;
6399N/A+ needLogin = 1;
6399N/A+ maxCacCerts = MAX_CERT_SLOTS;
6399N/A+ mCoolkey = 0;
6399N/A+ mOldCAC = 0;
6399N/A+ mCACLocalLogin = getPIVLoginType();
6399N/A+ return;
6399N/A+ }
6399N/A status = CKYApplet_SelectCoolKeyManager(conn, NULL);
6399N/A if (status != CKYSUCCESS) {
6399N/A log->log("CoolKey Select failed 0x%x\n", status);
6399N/A- status = CACApplet_SelectPKI(conn, 0, NULL);
6399N/A+ status = getCACAid();
6399N/A if (status != CKYSUCCESS) {
6399N/A- log->log("CAC Select failed 0x%x\n", status);
6399N/A+ log->log("CAC Select failed 0x%x\n", status);
6399N/A if (status == CKYSCARDERR) {
6399N/A- log->log("CAC Card Failure 0x%x\n",
6399N/A- CKYCardConnection_GetLastError(conn));
6399N/A- disconnect();
6399N/A+ log->log("Card Failure 0x%x\n",
6399N/A+ CKYCardConnection_GetLastError(conn));
6399N/A+ disconnect();
6399N/A }
6399N/A+ /* CARD is unknown */
6399N/A return;
6399N/A }
6399N/A state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
6399N/A@@ -633,10 +776,11 @@
6399N/A * unfriendly */
6399N/A isVersion1Key = 0;
6399N/A needLogin = 1;
6399N/A-
6399N/A+ mCoolkey = 0;
6399N/A+ mCACLocalLogin = false;
6399N/A return;
6399N/A }
6399N/A- mCoolkey = 1;
6399N/A+ mCoolkey = 1; /* coolkey applet selected */
6399N/A log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time);
6399N/A
6399N/A state |= APPLET_SELECTABLE;
6399N/A@@ -700,8 +844,8 @@
6399N/A }
6399N/A } else {
6399N/A loggedIn = false;
6399N/A+ pinCache.invalidate();
6399N/A if (hard) {
6399N/A- pinCache.invalidate();
6399N/A pinCache.clearPin();
6399N/A }
6399N/A }
6399N/A@@ -716,17 +860,113 @@
6399N/A invalidateLogin(false);
6399N/A }
6399N/A
6399N/A+CKYStatus
6399N/A+Slot::getCACAid()
6399N/A+{
6399N/A+ CKYBuffer tBuf;
6399N/A+ CKYBuffer vBuf;
6399N/A+ CKYSize tlen, vlen;
6399N/A+ CKYOffset toffset, voffset;
6399N/A+ int certSlot = 0;
6399N/A+ int i,length = 0;
6399N/A+ CKYStatus status;
6399N/A+
6399N/A+ CKYBuffer_InitEmpty(&tBuf);
6399N/A+ CKYBuffer_InitEmpty(&vBuf);
6399N/A+
6399N/A+ /* clear out the card AID's */
6399N/A+ for (i=0; i < MAX_CERT_SLOTS; i++) {
6399N/A+ CKYBuffer_Resize(&cardAID[i],0);
6399N/A+ }
6399N/A+
6399N/A+ status = CACApplet_SelectCCC(conn,NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ /* are we an old CAC */
6399N/A+ status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ /* no, just fail */
6399N/A+ return status;
6399N/A+ }
6399N/A+ /* yes, fill in the old applets */
6399N/A+ mOldCAC = true;
6399N/A+ for (i=1; i< MAX_CERT_SLOTS; i++) {
6399N/A+ CACApplet_SelectPKI(conn, &cardAID[i], i, NULL);
6399N/A+ }
6399N/A+ maxCacCerts = 3;
6399N/A+ return CKYSUCCESS;
6399N/A+ }
6399N/A+ /* definately not an old CAC */
6399N/A+ mOldCAC = false;
6399N/A+
6399N/A+ /* read the TLV */
6399N/A+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ tlen = CKYBuffer_Size(&tBuf);
6399N/A+ vlen = CKYBuffer_Size(&vBuf);
6399N/A+
6399N/A+ for(toffset = 2, voffset=2;
6399N/A+ certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ;
6399N/A+ voffset += length) {
6399N/A+
6399N/A+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
6399N/A+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
6399N/A+ toffset += 2;
6399N/A+ if (length == 0xff) {
6399N/A+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
6399N/A+ toffset +=2;
6399N/A+ }
6399N/A+ if (tag != CAC_TAG_CARDURL) {
6399N/A+ continue;
6399N/A+ }
6399N/A+ /* CARDURL tags must be at least 10 bytes long */
6399N/A+ if (length < 10) {
6399N/A+ continue;
6399N/A+ }
6399N/A+ /* check the app type, should be TLV_APP_PKI */
6399N/A+ if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) {
6399N/A+ continue;
6399N/A+ }
6399N/A+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf,
6399N/A+ voffset+8, 2);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6);
6399N/A+
6399N/A+ certSlot++;
6399N/A+ }
6399N/A+ status = CKYSUCCESS;
6399N/A+ if (certSlot == 0) {
6399N/A+ status = CKYAPDUFAIL; /* probably neeed a beter error code */
6399N/A+ }
6399N/A+ maxCacCerts = certSlot;
6399N/A+
6399N/A+done:
6399N/A+ CKYBuffer_FreeData(&tBuf);
6399N/A+ CKYBuffer_FreeData(&vBuf);
6399N/A+ return status;
6399N/A+}
6399N/A+
6399N/A void
6399N/A Slot::refreshTokenState()
6399N/A {
6399N/A if( cardStateMayHaveChanged() ) {
6399N/A-log->log("card changed\n");
6399N/A+ log->log("card changed\n");
6399N/A invalidateLogin(true);
6399N/A closeAllSessions();
6399N/A unloadObjects();
6399N/A connectToToken();
6399N/A
6399N/A-
6399N/A if( state & APPLET_PERSONALIZED ) {
6399N/A try {
6399N/A loadObjects();
6399N/A@@ -924,7 +1164,7 @@
6399N/A //
6399N/A #define COOLKEY "CoolKey"
6399N/A #define POSSESSION " for "
6399N/A- if (!personName || personName == "") {
6399N/A+ if (!personName || personName[0] == '\0' ) {
6399N/A const int coolKeySize = sizeof(COOLKEY) ;
6399N/A memcpy(label, COOLKEY, coolKeySize-1);
6399N/A makeSerialString(&label[coolKeySize], maxSize-coolKeySize, cuid);
6399N/A@@ -964,7 +1204,7 @@
6399N/A
6399N/A struct _manList {
6399N/A unsigned short type;
6399N/A- char *string;
6399N/A+ const char *string;
6399N/A };
6399N/A
6399N/A static const struct _manList manList[] = {
6399N/A@@ -1046,6 +1286,7 @@
6399N/A
6399N/A
6399N/A return CKR_OK;
6399N/A+
6399N/A }
6399N/A
6399N/A void
6399N/A@@ -1066,7 +1307,16 @@
6399N/A bool found = FALSE;
6399N/A CKYStatus status;
6399N/A SCARD_READERSTATE *myReaderStates = NULL;
6399N/A+ static SCARD_READERSTATE pnp = { 0 };
6399N/A unsigned int myNumReaders = 0;
6399N/A+
6399N/A+ readerListLock.getLock();
6399N/A+ if (pnp.szReader == 0) {
6399N/A+ CKYReader_Init(&pnp);
6399N/A+ pnp.szReader = "\\\\?PnP?\\Notification";
6399N/A+ }
6399N/A+ readerListLock.releaseLock();
6399N/A+
6399N/A #ifndef notdef
6399N/A do {
6399N/A readerListLock.getLock();
6399N/A@@ -1079,52 +1329,98 @@
6399N/A }
6399N/A throw;
6399N/A }
6399N/A- if (myNumReaders != numReaders) {
6399N/A+
6399N/A+ /* Before round-tripping to the daemon for the duration of the
6399N/A+ * timeout, first see if we lost any readers, and pick a slot
6399N/A+ * from that set to return
6399N/A+ */
6399N/A+ for (i=0; i < numReaders; i++) {
6399N/A+ unsigned long knownState =
6399N/A+ CKYReader_GetKnownState(&readerStates[i]);
6399N/A+
6399N/A+ if ((knownState & SCARD_STATE_UNAVAILABLE) &&
6399N/A+ (knownState & SCARD_STATE_CHANGED)) {
6399N/A+ CKYReader_SetKnownState(&readerStates[i],
6399N/A+ knownState & ~SCARD_STATE_CHANGED);
6399N/A+ readerListLock.releaseLock();
6399N/A+ *slotp = slotIndexToID(i);
6399N/A+ found = TRUE;
6399N/A+ break;
6399N/A+ }
6399N/A+ }
6399N/A+
6399N/A+ if (found) {
6399N/A+ break;
6399N/A+ }
6399N/A+
6399N/A+ if (shuttingDown) {
6399N/A+ readerListLock.releaseLock();
6399N/A+ break;
6399N/A+ }
6399N/A+
6399N/A+ if (myNumReaders != numReaders + 1) {
6399N/A if (myReaderStates) {
6399N/A delete [] myReaderStates;
6399N/A }
6399N/A- myReaderStates = new SCARD_READERSTATE [numReaders];
6399N/A+ myReaderStates = new SCARD_READERSTATE [numReaders + 1];
6399N/A+ myNumReaders = numReaders + 1;
6399N/A }
6399N/A- memcpy(myReaderStates, readerStates,
6399N/A- sizeof(SCARD_READERSTATE)*numReaders);
6399N/A- myNumReaders = numReaders;
6399N/A+
6399N/A+ memcpy(myReaderStates, readerStates,
6399N/A+ sizeof(SCARD_READERSTATE) * numReaders);
6399N/A+ memcpy(&myReaderStates[numReaders], &pnp, sizeof(pnp));
6399N/A readerListLock.releaseLock();
6399N/A status = CKYCardContext_WaitForStatusChange(context,
6399N/A- myReaderStates, myNumReaders, timeout);
6399N/A+ myReaderStates, myNumReaders, timeout);
6399N/A if (status == CKYSUCCESS) {
6399N/A- for (i=0; i < myNumReaders; i++) {
6399N/A- SCARD_READERSTATE *rsp = &myReaderStates[i];
6399N/A- unsigned long eventState = CKYReader_GetEventState(rsp);
6399N/A+ unsigned long eventState;
6399N/A+ for (i=0; i < myNumReaders - 1; i++) {
6399N/A+ eventState = CKYReader_GetEventState(&myReaderStates[i]);
6399N/A if (eventState & SCARD_STATE_CHANGED) {
6399N/A readerListLock.getLock();
6399N/A- CKYReader_SetKnownState(&readerStates[i], eventState & ~SCARD_STATE_CHANGED);
6399N/A+ CKYReader_SetKnownState(&readerStates[i],
6399N/A+ eventState & ~SCARD_STATE_CHANGED);
6399N/A readerListLock.releaseLock();
6399N/A *slotp = slotIndexToID(i);
6399N/A found = TRUE;
6399N/A break;
6399N/A }
6399N/A }
6399N/A+ /* No real need to check for an additional card, we already update
6399N/A+ * the list when we iterate. */
6399N/A+ if (!found) {
6399N/A+ eventState = CKYReader_GetEventState(
6399N/A+ &myReaderStates[myNumReaders-1]);
6399N/A+ if (eventState & SCARD_STATE_CHANGED) {
6399N/A+ readerListLock.getLock();
6399N/A+ CKYReader_SetKnownState(&pnp,
6399N/A+ eventState & ~SCARD_STATE_CHANGED);
6399N/A+ readerListLock.releaseLock();
6399N/A+ log->log("Reader insertion/removal detected\n");
6399N/A+ continue; /* get the update */
6399N/A+ }
6399N/A+ }
6399N/A }
6399N/A+
6399N/A if (found || (flag == CKF_DONT_BLOCK) || shuttingDown) {
6399N/A break;
6399N/A }
6399N/A
6399N/A #ifndef WIN32
6399N/A- if (status != CKYSUCCESS) {
6399N/A-
6399N/A- if ( (CKYCardContext_GetLastError(context) ==
6399N/A- SCARD_E_READER_UNAVAILABLE) ||
6399N/A- (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT))
6399N/A- {
6399N/A- OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
6399N/A- }
6399N/A-
6399N/A-
6399N/A- }
6399N/A+ /* pcsc-lite needs to make progress or something */
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ if ((CKYCardContext_GetLastError(context) ==
6399N/A+ SCARD_E_READER_UNAVAILABLE) ||
6399N/A+ (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT)) {
6399N/A+ OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
6399N/A+ }
6399N/A+ }
6399N/A #endif
6399N/A } while ((status == CKYSUCCESS) ||
6399N/A (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) ||
6399N/A- ( CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE));
6399N/A+ (CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE) ||
6399N/A+ (CKYCardContext_GetLastError(context) == SCARD_E_NO_SERVICE) ||
6399N/A+ (CKYCardContext_GetLastError(context) == SCARD_E_SERVICE_STOPPED) );
6399N/A #else
6399N/A do {
6399N/A OSSleep(100);
6399N/A@@ -1161,6 +1457,7 @@
6399N/A case SCARD_W_REMOVED_CARD:
6399N/A ckrv = CKR_DEVICE_REMOVED;
6399N/A break;
6399N/A+
6399N/A default:
6399N/A ckrv = CKR_DEVICE_ERROR;
6399N/A break;
6399N/A@@ -1220,14 +1517,68 @@
6399N/A }
6399N/A
6399N/A void
6399N/A-Slot::selectCACApplet(CKYByte instance)
6399N/A+Slot::selectCACApplet(CKYByte instance, bool doDisconnect)
6399N/A {
6399N/A CKYStatus status;
6399N/A- status = CACApplet_SelectPKI(conn, instance, NULL);
6399N/A+ /* PIV containers and keys by instance */
6399N/A+ static const int container[] = {
6399N/A+ 0x5fc105, 0x5fc10a, 0x5fc10b, 0x5fc101,
6399N/A+ 0x5fc10d, 0x5fc10e, 0x5fc10f, 0x5fc110,
6399N/A+ 0x5fc111, 0x5fc112, 0x5fc113, 0x5fc114,
6399N/A+ 0x5fc115, 0x5fc116, 0x5fc117, 0x5fc118,
6399N/A+ 0x5fc119, 0x5fc11a, 0x5fc11b, 0x5fc11c,
6399N/A+ 0x5fc11d, 0x5fc11e, 0x5fc11f, 0x5fc120
6399N/A+ };
6399N/A+ static const int keyRef[] = {
6399N/A+ 0x9a, 0x9c, 0x9d, 0x9e,
6399N/A+ 0x82, 0x83, 0x84, 0x85,
6399N/A+ 0x86, 0x87, 0x88, 0x89,
6399N/A+ 0x8a, 0x8b, 0x8c, 0x8d,
6399N/A+ 0x8e, 0x8f, 0x90, 0x91,
6399N/A+ 0x92, 0x93, 0x94, 0x95
6399N/A+ };
6399N/A+
6399N/A+ if (state & PIV_CARD) {
6399N/A+ status = PIVApplet_Select(conn, NULL);
6399N/A+ if (status == CKYSCARDERR) handleConnectionError();
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ if (doDisconnect) {
6399N/A+ disconnect();
6399N/A+ }
6399N/A+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
6399N/A+ }
6399N/A+ pivContainer = container[instance];
6399N/A+ pivKey = keyRef[instance];
6399N/A+ return;
6399N/A+ }
6399N/A+ CKYBuffer *aid = &cardAID[instance];
6399N/A+
6399N/A+ if (CKYBuffer_Size(aid) == 0) {
6399N/A+ if (doDisconnect) {
6399N/A+ disconnect();
6399N/A+ }
6399N/A+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ status = CKYApplet_SelectFile(conn, aid, NULL);
6399N/A if ( status == CKYSCARDERR ) handleConnectionError();
6399N/A if ( status != CKYSUCCESS) {
6399N/A // could not select applet: this just means it's not there
6399N/A- disconnect();
6399N/A+ if (doDisconnect) {
6399N/A+ disconnect();
6399N/A+ }
6399N/A+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
6399N/A+ }
6399N/A+ if (mOldCAC) {
6399N/A+ return;
6399N/A+ }
6399N/A+ status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
6399N/A+ if ( status == CKYSCARDERR ) handleConnectionError();
6399N/A+ if ( status != CKYSUCCESS) {
6399N/A+ if (doDisconnect) {
6399N/A+ disconnect();
6399N/A+ }
6399N/A throw PKCS11Exception(CKR_DEVICE_REMOVED);
6399N/A }
6399N/A }
6399N/A@@ -1274,6 +1625,19 @@
6399N/A }
6399N/A };
6399N/A
6399N/A+class KeyNumMatch {
6399N/A+ private:
6399N/A+ CKYByte keyNum;
6399N/A+ const Slot &slot;
6399N/A+ public:
6399N/A+ KeyNumMatch(CKYByte keyNum_, const Slot &s) : keyNum(keyNum_), slot(s) { }
6399N/A+ bool operator() (const PKCS11Object& obj) {
6399N/A+ unsigned long objID = obj.getMuscleObjID();
6399N/A+ return (slot.getObjectClass(objID) == 'k')
6399N/A+ && (slot.getObjectIndex(objID) == keyNum);
6399N/A+ }
6399N/A+};
6399N/A+
6399N/A class ObjectCertCKAIDMatch {
6399N/A private:
6399N/A CKYByte cka_id;
6399N/A@@ -1307,6 +1671,29 @@
6399N/A return handle;
6399N/A }
6399N/A
6399N/A+/* Create a short lived Secret Key for ECC key derive. */
6399N/A+PKCS11Object *
6399N/A+Slot::createSecretKeyObject(CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
6399N/A+{
6399N/A+
6399N/A+ if (secretKeyBuffer == NULL ) {
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A+ "Can't create secret key object for ECC.");
6399N/A+ }
6399N/A+
6399N/A+ unsigned long muscleID = 0xfff;
6399N/A+ PKCS11Object *secret = new SecretKey(muscleID, handle, secretKeyBuffer, pTemplate, ulAttributeCount);
6399N/A+
6399N/A+ if (secret == NULL) {
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A+ "Can't create secret key object for ECC.");
6399N/A+ }
6399N/A+
6399N/A+ tokenObjects.push_back(*secret);
6399N/A+
6399N/A+ return secret;
6399N/A+}
6399N/A+
6399N/A void
6399N/A Slot::addKeyObject(list<PKCS11Object>& objectList, const ListObjectInfo& info,
6399N/A CK_OBJECT_HANDLE handle, bool isCombined)
6399N/A@@ -1316,24 +1703,31 @@
6399N/A CK_OBJECT_CLASS objClass = keyObj.getClass();
6399N/A const CKYBuffer *id;
6399N/A
6399N/A-
6399N/A if (isCombined &&
6399N/A- ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
6399N/A- id = keyObj.getAttribute(CKA_ID);
6399N/A- if ((!id) || (CKYBuffer_Size(id) != 1)) {
6399N/A- throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A- "Missing or invalid CKA_ID value");
6399N/A- }
6399N/A- iter = find_if(objectList.begin(), objectList.end(),
6399N/A- ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
6399N/A- if ( iter == objectList.end() ) {
6399N/A+ ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
6399N/A+ id = keyObj.getAttribute(CKA_ID);
6399N/A+ if ((!id) || (CKYBuffer_Size(id) != 1)) {
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A+ "Missing or invalid CKA_ID value");
6399N/A+ }
6399N/A+ iter = find_if(objectList.begin(), objectList.end(),
6399N/A+ ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
6399N/A+ if ( iter == objectList.end() ) {
6399N/A // We failed to find a cert with a matching CKA_ID. This
6399N/A // can happen if the cert is not present on the token, or
6399N/A // the der encoded cert stored on the token was corrupted.
6399N/A- throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A- "Failed to find cert with matching CKA_ID value");
6399N/A- }
6399N/A- keyObj.completeKey(*iter);
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A+ "Failed to find cert with matching CKA_ID value");
6399N/A+ }
6399N/A+ keyObj.completeKey(*iter);
6399N/A+
6399N/A+ /* use key object to determine what algorithms we support */
6399N/A+ if ( keyObj.getKeyType() == PKCS11Object::ecc) {
6399N/A+ algs = (SlotAlgs) (algs | ALG_ECC);
6399N/A+ } else {
6399N/A+ algs = (SlotAlgs) (algs | ALG_RSA);
6399N/A+ }
6399N/A+
6399N/A }
6399N/A objectList.push_back(keyObj);
6399N/A
6399N/A@@ -1363,6 +1757,7 @@
6399N/A void
6399N/A Slot::unloadObjects()
6399N/A {
6399N/A+ algs = ALG_NONE;
6399N/A tokenObjects.clear();
6399N/A free(personName);
6399N/A personName = NULL;
6399N/A@@ -1421,23 +1816,35 @@
6399N/A // Shared memory segments are fixed size (equal to the object memory size of
6399N/A // the token).
6399N/A //
6399N/A+//
6399N/A+//
6399N/A+
6399N/A+struct SlotDataPair {
6399N/A+ unsigned long dataOffset;
6399N/A+ unsigned long dataSize;
6399N/A+};
6399N/A
6399N/A struct SlotSegmentHeader {
6399N/A unsigned short version;
6399N/A unsigned short headerSize;
6399N/A unsigned char valid;
6399N/A- unsigned char reserved;
6399N/A+ unsigned char firstCacCert;
6399N/A unsigned char cuid[10];
6399N/A- unsigned short reserved2;
6399N/A+
6399N/A+ unsigned short reserved;
6399N/A unsigned short dataVersion;
6399N/A unsigned short dataHeaderOffset;
6399N/A unsigned short dataOffset;
6399N/A unsigned long dataHeaderSize;
6399N/A unsigned long dataSize;
6399N/A- unsigned long cert2Offset;
6399N/A- unsigned long cert2Size;
6399N/A+ unsigned long nextDataOffset;
6399N/A+ SlotDataPair cacCerts[MAX_CERT_SLOTS];
6399N/A };
6399N/A
6399N/A+const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */
6399N/A+const unsigned short CAC_DATA_VERSION=2;
6399N/A+
6399N/A+
6399N/A #define MAX_OBJECT_STORE_SIZE 15000
6399N/A //
6399N/A // previous development versions used a segment prefix of
6399N/A@@ -1458,7 +1865,7 @@
6399N/A }
6399N/A sprintf(segName,SEGMENT_PREFIX"%s",readerName);
6399N/A segment = SHMem::initSegment(segName, MAX_OBJECT_STORE_SIZE, needInit);
6399N/A- delete segName;
6399N/A+ delete [] segName;
6399N/A if (!segment) {
6399N/A // just run without shared memory
6399N/A return;
6399N/A@@ -1472,9 +1879,8 @@
6399N/A return;
6399N/A }
6399N/A
6399N/A- SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
6399N/A if (needInit) {
6399N/A- segmentHeader->valid = 0;
6399N/A+ clearValid(0);
6399N/A }
6399N/A segmentSize = segment->getSHMemSize();
6399N/A }
6399N/A@@ -1548,6 +1954,18 @@
6399N/A return segmentHeader->dataVersion;
6399N/A }
6399N/A
6399N/A+unsigned char
6399N/A+SlotMemSegment::getFirstCacCert() const
6399N/A+{
6399N/A+ if (!segment) {
6399N/A+ return NOT_A_CAC;
6399N/A+ }
6399N/A+
6399N/A+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
6399N/A+
6399N/A+ return segmentHeader->firstCacCert;
6399N/A+}
6399N/A+
6399N/A void
6399N/A SlotMemSegment::setVersion(unsigned short version)
6399N/A {
6399N/A@@ -1571,6 +1989,18 @@
6399N/A segmentHeader->dataVersion = version;
6399N/A }
6399N/A
6399N/A+void
6399N/A+SlotMemSegment::setFirstCacCert(unsigned char firstCacCert)
6399N/A+{
6399N/A+ if (!segment) {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
6399N/A+
6399N/A+ segmentHeader->firstCacCert = firstCacCert;
6399N/A+}
6399N/A+
6399N/A bool
6399N/A SlotMemSegment::isValid() const
6399N/A {
6399N/A@@ -1645,23 +2075,13 @@
6399N/A int size;
6399N/A CKYByte *data;
6399N/A
6399N/A- switch (instance) {
6399N/A- case 0:
6399N/A- data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
6399N/A- size = segmentHeader->dataHeaderSize;
6399N/A- break;
6399N/A- case 1:
6399N/A- data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
6399N/A- size = segmentHeader->dataSize;
6399N/A- break;
6399N/A- case 2:
6399N/A- data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
6399N/A- size = segmentHeader->cert2Size;
6399N/A- break;
6399N/A- default:
6399N/A+ if (instance >= MAX_CERT_SLOTS) {
6399N/A CKYBuffer_Resize(objData, 0);
6399N/A return;
6399N/A }
6399N/A+ data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance]
6399N/A+ .dataOffset];
6399N/A+ size = segmentHeader->cacCerts[instance].dataSize;
6399N/A CKYBuffer_Replace(objData, 0, data, size);
6399N/A }
6399N/A
6399N/A@@ -1675,30 +2095,20 @@
6399N/A SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
6399N/A int size = CKYBuffer_Size(data);
6399N/A CKYByte *shmData;
6399N/A- switch (instance) {
6399N/A- case 0:
6399N/A- segmentHeader->headerSize = sizeof *segmentHeader;
6399N/A- segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
6399N/A- segmentHeader->dataHeaderSize = size;
6399N/A- segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size;
6399N/A- segmentHeader->dataSize = 0;
6399N/A- segmentHeader->cert2Offset = segmentHeader->dataOffset;
6399N/A- segmentHeader->cert2Size = 0;
6399N/A- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
6399N/A- break;
6399N/A- case 1:
6399N/A- segmentHeader->dataSize = size;
6399N/A- segmentHeader->cert2Offset = segmentHeader->dataOffset + size;
6399N/A- segmentHeader->cert2Size = 0;
6399N/A- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
6399N/A- break;
6399N/A- case 2:
6399N/A- segmentHeader->cert2Size = size;
6399N/A- shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
6399N/A- break;
6399N/A- default:
6399N/A+
6399N/A+ if (instance >= MAX_CERT_SLOTS) {
6399N/A return;
6399N/A }
6399N/A+
6399N/A+ if (segmentHeader->firstCacCert == NOT_A_CAC) {
6399N/A+ segmentHeader->firstCacCert = instance;
6399N/A+ }
6399N/A+ unsigned long dataOffset = segmentHeader->nextDataOffset;
6399N/A+ segmentHeader->cacCerts[instance].dataOffset = dataOffset;
6399N/A+ segmentHeader->nextDataOffset += size;
6399N/A+ segmentHeader->cacCerts[instance].dataSize = size;
6399N/A+ shmData = (CKYByte *) &segmentAddr[dataOffset];
6399N/A+
6399N/A memcpy(shmData, CKYBuffer_Data(data), size);
6399N/A }
6399N/A
6399N/A@@ -1710,15 +2120,18 @@
6399N/A return;
6399N/A }
6399N/A SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
6399N/A- switch (instance) {
6399N/A- case 0:
6399N/A- segmentHeader->headerSize = 0;
6399N/A- segmentHeader->dataHeaderSize = 0;
6399N/A- /* fall through */
6399N/A- case 1:
6399N/A- segmentHeader->dataSize = 0;
6399N/A+
6399N/A+ segmentHeader->headerSize = sizeof *segmentHeader;
6399N/A+ segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
6399N/A+ segmentHeader->dataHeaderSize = 0;
6399N/A+ segmentHeader->dataSize = 0;
6399N/A+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
6399N/A+ segmentHeader->cacCerts[i].dataSize = 0;
6399N/A }
6399N/A+ segmentHeader->dataOffset = sizeof *segmentHeader;
6399N/A+ segmentHeader->nextDataOffset = sizeof *segmentHeader;
6399N/A segmentHeader->valid = 0;
6399N/A+ segmentHeader->firstCacCert = NOT_A_CAC;
6399N/A }
6399N/A
6399N/A void
6399N/A@@ -1756,7 +2169,7 @@
6399N/A // shared memory is protected by our transaction call on the card
6399N/A //
6399N/A CKYStatus status;
6399N/A- if (state & CAC_CARD) {
6399N/A+ if (state & GOV_CARD) {
6399N/A status = CACApplet_SelectCardManager(conn, NULL);
6399N/A } else {
6399N/A status = CKYApplet_SelectCardManager(conn, NULL);
6399N/A@@ -1989,108 +2402,401 @@
6399N/A return objInfoList;
6399N/A }
6399N/A
6399N/A-void
6399N/A-Slot::loadCACCert(CKYByte instance)
6399N/A-{
6399N/A- CKYISOStatus apduRC;
6399N/A- CKYStatus status = CKYSUCCESS;
6399N/A- CKYBuffer cert;
6399N/A- CKYBuffer rawCert;
6399N/A- CKYBuffer shmCert;
6399N/A- CKYSize nextSize;
6399N/A+typedef enum {
6399N/A+ BER_UNWRAP,
6399N/A+ BER_NEXT
6399N/A+} BERop;
6399N/A
6399N/A- OSTime time = OSTimeNow();
6399N/A+static CKYStatus
6399N/A+berProcess(CKYBuffer *buf, int matchTag, CKYBuffer *target, BERop type)
6399N/A+{
6399N/A+ unsigned char tag;
6399N/A+ unsigned int used_length= 0;
6399N/A+ unsigned int data_length;
6399N/A
6399N/A- CKYBuffer_InitEmpty(&cert);
6399N/A- CKYBuffer_InitEmpty(&rawCert);
6399N/A- CKYBuffer_InitEmpty(&shmCert);
6399N/A+ tag = CKYBuffer_GetChar(buf,used_length++);
6399N/A
6399N/A- //
6399N/A- // not all CAC cards have all the PKI instances
6399N/A- // catch the applet selection errors if they don't
6399N/A- //
6399N/A- try {
6399N/A- selectCACApplet(instance);
6399N/A- } catch(PKCS11Exception& e) {
6399N/A- // all CAC's must have instance '0', throw the error it
6399N/A- // they don't.
6399N/A- if (instance == 0) throw e;
6399N/A- // If the CAC doesn't have instance '2', and we were updating
6399N/A- // the shared memory, set it to valid now.
6399N/A- if ((instance == 2) && !shmem.isValid()) {
6399N/A- shmem.setValid();
6399N/A- }
6399N/A- return;
6399N/A+ /* blow out when we come to the end */
6399N/A+ if (matchTag && tag != matchTag) {
6399N/A+ return CKYLIBFAIL;
6399N/A }
6399N/A
6399N/A- log->log("CAC Cert %d: select CAC applet: %d ms\n",
6399N/A- instance, OSTimeNow() - time);
6399N/A+ data_length = CKYBuffer_GetChar(buf,used_length++);
6399N/A
6399N/A- if (instance == 0) {
6399N/A- /* get the first 100 bytes of the cert */
6399N/A- status = CACApplet_GetCertificateFirst(conn, &rawCert,
6399N/A- &nextSize, &apduRC);
6399N/A- if (status != CKYSUCCESS) {
6399N/A- handleConnectionError();
6399N/A- }
6399N/A- log->log("CAC Cert %d: fetch CAC Cert: %d ms\n",
6399N/A- instance, OSTimeNow() - time);
6399N/A- }
6399N/A+ if (data_length & 0x80) {
6399N/A+ int len_count = data_length & 0x7f;
6399N/A
6399N/A- unsigned short dataVersion = 1;
6399N/A- CKYBool needRead = 1;
6399N/A+ data_length = 0;
6399N/A
6399N/A- /* see if it matches the shared memory */
6399N/A- if (shmem.isValid() && shmem.getDataVersion() == dataVersion) {
6399N/A- shmem.readCACCert(&shmCert, instance);
6399N/A- CKYSize certSize = CKYBuffer_Size(&rawCert);
6399N/A- CKYSize shmCertSize = CKYBuffer_Size(&shmCert);
6399N/A- const CKYByte *shmData = CKYBuffer_Data(&shmCert);
6399N/A+ while (len_count-- > 0) {
6399N/A+ data_length = (data_length << 8) |
6399N/A+ CKYBuffer_GetChar(buf,used_length++);
6399N/A+ }
6399N/A+ }
6399N/A
6399N/A- if (instance != 0) {
6399N/A- needRead = 0;
6399N/A- }
6399N/A+ if (data_length > (CKYBuffer_Size(buf)-used_length) ) {
6399N/A+ return CKYLIBFAIL;
6399N/A+ }
6399N/A
6399N/A- if (shmCertSize >= certSize) {
6399N/A- if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) {
6399N/A- /* yes it does, no need to read the rest of the cert, use
6399N/A- * the cache */
6399N/A- CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize);
6399N/A- needRead = 0;
6399N/A- }
6399N/A+ if (type == BER_UNWRAP) {
6399N/A+ return CKYBuffer_AppendBuffer(target, buf, used_length, data_length);
6399N/A+ }
6399N/A+ return CKYBuffer_AppendBuffer(target, buf, used_length+data_length,
6399N/A+ CKYBuffer_Size(buf)-(used_length+data_length));
6399N/A+}
6399N/A+
6399N/A+
6399N/A+CKYStatus
6399N/A+Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize)
6399N/A+{
6399N/A+ CKYStatus status;
6399N/A+ CKYISOStatus apduRC;
6399N/A+ *nextSize = 0;
6399N/A+
6399N/A+ if (state & PIV_CARD) {
6399N/A+ CKYBuffer pivData;
6399N/A+ CKYBuffer certInfo;
6399N/A+
6399N/A+ CKYBuffer_InitEmpty(&pivData);
6399N/A+ CKYBuffer_InitEmpty(&certInfo);
6399N/A+ CKYBuffer_Resize(cert, 0);
6399N/A+ status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC);
6399N/A+ /* actually, on success, we need to parse the certificate and find the
6399N/A+ * propper tag */
6399N/A+ if (status == CKYSUCCESS) {
6399N/A+ status = berProcess(cert, 0x53, &pivData, BER_UNWRAP);
6399N/A+ CKYBuffer_Resize(cert, 0);
6399N/A+ CKYBuffer_AppendChar(cert,0);
6399N/A+ do {
6399N/A+ CKYByte tag = CKYBuffer_GetChar(&pivData,0);
6399N/A+ if (tag == CAC_TAG_CERTIFICATE) {
6399N/A+ status = berProcess(&pivData, CAC_TAG_CERTIFICATE,
6399N/A+ cert, BER_UNWRAP);
6399N/A+ }
6399N/A+ if (tag == CAC_TAG_CERTINFO) {
6399N/A+ CKYBuffer_Resize(&certInfo, 0);
6399N/A+ status = berProcess(&pivData, CAC_TAG_CERTINFO,
6399N/A+ &certInfo, BER_UNWRAP);
6399N/A+ if (CKYBuffer_Size(&certInfo) == 1) {
6399N/A+ CKYBuffer_SetChar(cert,0,
6399N/A+ CKYBuffer_GetChar(&certInfo,0));
6399N/A+ }
6399N/A+ }
6399N/A+ if (status == CKYSUCCESS) {
6399N/A+ CKYBuffer_Resize(&certInfo, 0);
6399N/A+ status = berProcess(&pivData, 0, &certInfo, BER_NEXT);
6399N/A+ if (status == CKYSUCCESS) {
6399N/A+ CKYBuffer_Resize(&pivData,0);
6399N/A+ status = CKYBuffer_AppendCopy(&pivData,&certInfo);
6399N/A+ }
6399N/A+ }
6399N/A+ } while ((status == CKYSUCCESS) && (CKYBuffer_Size(&pivData) != 0));
6399N/A+ CKYBuffer_FreeData(&pivData);
6399N/A+ CKYBuffer_FreeData(&certInfo);
6399N/A }
6399N/A- if (!needRead && (shmCertSize == 0)) {
6399N/A+
6399N/A+ return status;
6399N/A+ }
6399N/A+
6399N/A+ if (mOldCAC) {
6399N/A+ /* get the first 100 bytes of the cert */
6399N/A+ status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC);
6399N/A+ return status;
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer tBuf;
6399N/A+ CKYBuffer vBuf;
6399N/A+ CKYSize tlen, vlen;
6399N/A+ CKYOffset toffset, voffset;
6399N/A+ int length = 0;
6399N/A+
6399N/A+ CKYBuffer_InitEmpty(&tBuf);
6399N/A+ CKYBuffer_InitEmpty(&vBuf);
6399N/A+ CKYBuffer_Resize(cert, 0);
6399N/A+ CKYBuffer_AppendChar(cert,0);
6399N/A+
6399N/A+ /* handle the new CAC card read */
6399N/A+ /* read the TLV */
6399N/A+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ goto done;
6399N/A+ }
6399N/A+ tlen = CKYBuffer_Size(&tBuf);
6399N/A+ vlen = CKYBuffer_Size(&vBuf);
6399N/A+
6399N/A+ /* look for the Cert out of the TLV */
6399N/A+ for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ;
6399N/A+ voffset += length) {
6399N/A+
6399N/A+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
6399N/A+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
6399N/A+ toffset += 2;
6399N/A+ if (length == 0xff) {
6399N/A+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
6399N/A+ toffset +=2;
6399N/A+ }
6399N/A+ if (tag == CAC_TAG_CERTIFICATE) {
6399N/A+ CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
6399N/A+ }
6399N/A+ if (tag == CAC_TAG_CERTINFO) {
6399N/A+ CKYBuffer_SetChar(cert,0,CKYBuffer_GetChar(&vBuf,voffset));
6399N/A+ }
6399N/A+ }
6399N/A+ status = CKYSUCCESS;
6399N/A+
6399N/A+done:
6399N/A+ CKYBuffer_FreeData(&tBuf);
6399N/A+ CKYBuffer_FreeData(&vBuf);
6399N/A+ return status;
6399N/A+}
6399N/A+
6399N/A+
6399N/A+const static unsigned long crc_table[] = {
6399N/A+0x00000000,0x77073096,0xee0e612c,0x990951ba,
6399N/A+0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
6399N/A+0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,
6399N/A+0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
6399N/A+0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,
6399N/A+0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
6399N/A+0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,
6399N/A+0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
6399N/A+0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
6399N/A+0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
6399N/A+0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,
6399N/A+0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
6399N/A+0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,
6399N/A+0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
6399N/A+0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,
6399N/A+0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
6399N/A+0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,
6399N/A+0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
6399N/A+0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,
6399N/A+0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
6399N/A+0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
6399N/A+0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
6399N/A+0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,
6399N/A+0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
6399N/A+0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,
6399N/A+0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
6399N/A+0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
6399N/A+0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
6399N/A+0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,
6399N/A+0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
6399N/A+0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,
6399N/A+0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
6399N/A+0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,
6399N/A+0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
6399N/A+0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,
6399N/A+0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
6399N/A+0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,
6399N/A+0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
6399N/A+0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,
6399N/A+0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
6399N/A+0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,
6399N/A+0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
6399N/A+0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,
6399N/A+0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
6399N/A+0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
6399N/A+0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
6399N/A+0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,
6399N/A+0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
6399N/A+0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,
6399N/A+0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
6399N/A+0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,
6399N/A+0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
6399N/A+0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,
6399N/A+0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
6399N/A+0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,
6399N/A+0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
6399N/A+0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,
6399N/A+0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
6399N/A+0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,
6399N/A+0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
6399N/A+0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,
6399N/A+0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
6399N/A+0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
6399N/A+0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
6399N/A+};
6399N/A+
6399N/A+static unsigned long
6399N/A+calc_crc32(const unsigned char *buf, int len)
6399N/A+{
6399N/A+ unsigned long crc = 0xffffffff;
6399N/A+ int i;
6399N/A+
6399N/A+ for (i=0; i < len; i++) {
6399N/A+ unsigned char crc_low = crc & 0xff;
6399N/A+ unsigned long crc_high = crc >> 8;
6399N/A+ crc = crc_table[crc_low ^ buf[i]] ^ crc_high;
6399N/A+ }
6399N/A+ return crc ^ 0xffffffff;
6399N/A+}
6399N/A+
6399N/A+/*
6399N/A+ * decompress, handles both gzip and zlib trailers
6399N/A+ * it also automatically allocates the output buffer and expands it as
6399N/A+ * necessary.
6399N/A+ */
6399N/A+static int
6399N/A+decompress(CKYBuffer *out,
6399N/A+ CKYBuffer *in, CKYOffset offset, CKYSize len)
6399N/A+{
6399N/A+ int zret;
6399N/A+ CKYStatus status;
6399N/A+ z_stream stream;
6399N/A+ int chunk = len *2;
6399N/A+ int outlen = 0;
6399N/A+
6399N/A+
6399N/A+ /* allocate inflate state */
6399N/A+ stream.zalloc = Z_NULL;
6399N/A+ stream.zfree = Z_NULL;
6399N/A+ stream.opaque = Z_NULL;
6399N/A+ stream.avail_in = 0;
6399N/A+ stream.next_in = Z_NULL;
6399N/A+ zret = inflateInit(&stream);
6399N/A+ if (zret != Z_OK)
6399N/A+ return zret;
6399N/A+
6399N/A+ status = CKYBuffer_Reserve(out, outlen);
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ return Z_MEM_ERROR;
6399N/A+ }
6399N/A+
6399N/A+ stream.avail_in = len;
6399N/A+ stream.next_in = (Bytef *)(CKYBuffer_Data(in) + offset);
6399N/A+
6399N/A+ do {
6399N/A+ CKYBuffer_Resize(out, outlen + chunk);
6399N/A+ stream.avail_out = chunk;
6399N/A+
6399N/A+ stream.next_out = (Bytef *)CKYBuffer_Data(out)+ outlen;
6399N/A+
6399N/A+ zret= inflate(&stream, Z_NO_FLUSH);
6399N/A+
6399N/A+ /* we need the length early so it can be used in error processing */
6399N/A+ outlen += chunk - stream.avail_out;
6399N/A+
6399N/A+ /* proccess the error codes */
6399N/A+ switch (zret) {
6399N/A+ case Z_DATA_ERROR:
6399N/A+ /* a DATA error can occur on either corrupted data, or on gzip.
6399N/A+ * data. This is because gzip uses CRC32 and zlib used ADLER32
6399N/A+ * checksums. We need to check to see if this failure is do to
6399N/A+ * a gzip header. */
6399N/A+ /* 1) a gzip header includes 4 extra bytes containing the length
6399N/A+ * of the gziped data. This means there must be 4 more bytes
6399N/A+ * in our input buffer that have not been processed */
6399N/A+ if (stream.avail_in != 4) {
6399N/A+ break; /* not a gzip header */
6399N/A+ }
6399N/A+ /* The last 4 bytes of a gzip header include the uncompressed length
6399N/A+ * modulo 2^32. Make sure the actual uncompressed length matches
6399N/A+ * the header. */
6399N/A+ if ((outlen & 0xffffffffL)
6399N/A+ != CKYBuffer_GetLongLE(in, offset+len-4)) {
6399N/A+ break; /* didn't decode the full length */
6399N/A+ }
6399N/A+ /* At this point it''s pretty likely we have a gzip trailer. Verify
6399N/A+ * the crc32 values to make sure there hasn't been any corruption.
6399N/A+ */
6399N/A+ if (calc_crc32(CKYBuffer_Data(out), outlen) !=
6399N/A+ CKYBuffer_GetLongLE(in,offset+len-8)) {
6399N/A+ break; /* CRC didn't match */
6399N/A+ }
6399N/A+ /* This was valid gzip data, and we've successfully uncompressed
6399N/A+ * it. We're now done. */
6399N/A+ zret=Z_STREAM_END;
6399N/A+ break;
6399N/A+ case Z_NEED_DICT:
6399N/A+ /* if we need the dict, it wasn't in the data,
6399N/A+ * so it's a data error */
6399N/A+ zret = Z_DATA_ERROR;
6399N/A+ break;
6399N/A+ case Z_OK:
6399N/A+ /* Z_OK means we need more data, expand the buffer and go again.
6399N/A+ * if we don't need more buffer space, then the input must have
6399N/A+ * been truncated, that's a data error */
6399N/A+ if (stream.avail_out != 0) {
6399N/A+ zret = Z_DATA_ERROR;
6399N/A+ }
6399N/A+ break;
6399N/A+ }
6399N/A+ } while (zret == Z_OK);
6399N/A+
6399N/A+ /* cleanup */
6399N/A+ if (zret == Z_STREAM_END) {
6399N/A+ zret = Z_OK;
6399N/A+ CKYBuffer_Resize(out, outlen);
6399N/A+ } else {
6399N/A+ CKYBuffer_Resize(out, 0);
6399N/A+ }
6399N/A+ (void)inflateEnd(&stream);
6399N/A+ return zret;
6399N/A+}
6399N/A+
6399N/A+/*
6399N/A+ * only necessary for old CAC cards. New CAC cards have to read the
6399N/A+ * whole cert in anyway above....
6399N/A+ */
6399N/A+CKYStatus
6399N/A+Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize)
6399N/A+{
6399N/A+ CKYISOStatus apduRC;
6399N/A+ assert(mOldCAC);
6399N/A+ return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC);
6399N/A+}
6399N/A+
6399N/A+void
6399N/A+Slot::loadCACCert(CKYByte instance)
6399N/A+{
6399N/A+ CKYStatus status = CKYSUCCESS;
6399N/A+ CKYBuffer cert;
6399N/A+ CKYBuffer rawCert;
6399N/A+ CKYBuffer shmCert;
6399N/A+ CKYSize nextSize;
6399N/A+ CKYISOStatus apduRC;
6399N/A+
6399N/A+ OSTime time = OSTimeNow();
6399N/A+
6399N/A+ CKYBuffer_InitEmpty(&cert);
6399N/A+ CKYBuffer_InitEmpty(&rawCert);
6399N/A+ CKYBuffer_InitEmpty(&shmCert);
6399N/A+
6399N/A+ //
6399N/A+ // not all CAC cards have all the PKI instances
6399N/A+ // catch the applet selection errors if they don't
6399N/A+ //
6399N/A+ try {
6399N/A+ selectCACApplet(instance, false);
6399N/A+ } catch(PKCS11Exception& e) {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ log->log("CAC Cert %d: select CAC applet: %d ms\n",
6399N/A+ instance, OSTimeNow() - time);
6399N/A+
6399N/A+
6399N/A+ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION) {
6399N/A+ shmem.readCACCert(&rawCert, instance);
6399N/A+ if (CKYBuffer_Size(&rawCert) == 0) {
6399N/A /* no cert of this type, just return */
6399N/A return;
6399N/A }
6399N/A- }
6399N/A- CKYBuffer_FreeData(&shmCert);
6399N/A+ } else {
6399N/A+ status = readCACCertificateFirst(&rawCert, &nextSize);
6399N/A
6399N/A- if (needRead) {
6399N/A- /* it doesn't, read the new cert and update the cache */
6399N/A- if (instance == 0) {
6399N/A- shmem.clearValid(0);
6399N/A- shmem.setVersion(SHMEM_VERSION);
6399N/A- shmem.setDataVersion(dataVersion);
6399N/A- } else {
6399N/A- status = CACApplet_GetCertificateFirst(conn, &rawCert,
6399N/A- &nextSize, &apduRC);
6399N/A-
6399N/A- if (status != CKYSUCCESS) {
6399N/A- /* CAC only requires the Certificate in pki '0' */
6399N/A- /* if pki '1' or '2' are empty, treat it as a non-fatal error*/
6399N/A- if (instance == 2) {
6399N/A- /* we've attempted to read all the certs, shared memory
6399N/A- * is now valid */
6399N/A- shmem.setValid();
6399N/A- }
6399N/A- return;
6399N/A- }
6399N/A+ if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) {
6399N/A+ /* this cert doesn't exists, go to the next one */
6399N/A+ return;
6399N/A }
6399N/A
6399N/A if (nextSize) {
6399N/A- status = CACApplet_GetCertificateAppend(conn, &rawCert,
6399N/A- nextSize, &apduRC);
6399N/A+ status = readCACCertificateAppend(&rawCert, nextSize);
6399N/A }
6399N/A log->log("CAC Cert %d: Fetch rest : %d ms\n",
6399N/A instance, OSTimeNow() - time);
6399N/A@@ -2098,37 +2804,66 @@
6399N/A handleConnectionError();
6399N/A }
6399N/A shmem.writeCACCert(&rawCert, instance);
6399N/A- if (instance == 2) {
6399N/A- shmem.setValid();
6399N/A- }
6399N/A }
6399N/A
6399N/A
6399N/A log->log("CAC Cert %d: Cert has been read: %d ms\n",
6399N/A instance, OSTimeNow() - time);
6399N/A- if (CKYBuffer_GetChar(&rawCert,0) == 1) {
6399N/A- CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
6399N/A- CKYSize certSize = 0;
6399N/A+ /* new CACs, and old CACs with the high one bit are compressed,
6399N/A+ * uncompress them */
6399N/A+ if ((CKYBuffer_GetChar(&rawCert,0) & 0x3) == 1) {
6399N/A+ CKYOffset offset = 1;
6399N/A int zret = Z_MEM_ERROR;
6399N/A
6399N/A- do {
6399N/A- guessFinalSize *= 2;
6399N/A- status = CKYBuffer_Resize(&cert, guessFinalSize);
6399N/A- if (status != CKYSUCCESS) {
6399N/A- break;
6399N/A+ /* process the GZIP header if present */
6399N/A+ /* header_id = 0x1f, 0x8b. CM=8. If we ever support something other
6399N/A+ * than CM=8, we need to change the zlib header below. Currently both
6399N/A+ * gzip and zlib only support CM=8 (DEFLATE) compression */
6399N/A+ if ((CKYBuffer_GetChar(&rawCert,1) == 0x1f) &&
6399N/A+ (CKYBuffer_GetChar(&rawCert,2) == 0x8b) &&
6399N/A+ (CKYBuffer_GetChar(&rawCert,3) == 8)) {
6399N/A+ CKYByte flags = CKYBuffer_GetChar(&rawCert,4);
6399N/A+ /* this has a gzip header, not raw data. */
6399N/A+ offset += 10; /* base size of the gzip header */
6399N/A+ if (flags & 4) { /* FEXTRA */
6399N/A+ CKYSize len = CKYBuffer_GetShortLE(&rawCert,offset);
6399N/A+ offset += len;
6399N/A+ }
6399N/A+ if (flags & 8) { /* FNAME */
6399N/A+ while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
6399N/A+ offset++;
6399N/A+ }
6399N/A+ offset++;
6399N/A+ }
6399N/A+ if (flags & 0x10) { /* FComment */
6399N/A+ while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
6399N/A+ offset++;
6399N/A+ }
6399N/A+ offset++;
6399N/A+ }
6399N/A+ if (flags & 2) { /* FHCRC */
6399N/A+ offset += 2;
6399N/A }
6399N/A- certSize = guessFinalSize;
6399N/A- zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
6399N/A- CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1);
6399N/A- } while (zret == Z_BUF_ERROR);
6399N/A+ offset -= 2;
6399N/A+
6399N/A+ /* add zlib header, so libz will be happy */
6399N/A+ /* CINFO=7, CM=8, LEVEL=2, DICTFLAG=0, FCHECK= 1c */
6399N/A+ /* NOTE: the zlib will fail when procssing the trailer. this is
6399N/A+ * ok because decompress automatically notices the failure and
6399N/A+ * and checks the gzip trailer. */
6399N/A+ CKYBuffer_SetChar(&rawCert, offset, 0x78);
6399N/A+ CKYBuffer_SetChar(&rawCert, offset+1, 0x9c);
6399N/A+ }
6399N/A+ /* uncompress. This expands cert as necessary. */
6399N/A+ zret = decompress(&cert, &rawCert, offset,
6399N/A+ CKYBuffer_Size(&rawCert)-offset);
6399N/A
6399N/A if (zret != Z_OK) {
6399N/A CKYBuffer_FreeData(&rawCert);
6399N/A CKYBuffer_FreeData(&cert);
6399N/A throw PKCS11Exception(CKR_DEVICE_ERROR,
6399N/A- "Corrupted compressed CAC Cert");
6399N/A+ "Corrupted compressed CAC/PIV Cert");
6399N/A }
6399N/A- CKYBuffer_Resize(&cert,certSize);
6399N/A } else {
6399N/A CKYBuffer_InitFromBuffer(&cert,&rawCert,1,CKYBuffer_Size(&rawCert)-1);
6399N/A }
6399N/A@@ -2136,12 +2871,18 @@
6399N/A log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n",
6399N/A instance, OSTimeNow() - time);
6399N/A
6399N/A- CACCert certObj(instance, &cert);
6399N/A- CACPrivKey privKey(instance, certObj);
6399N/A- CACPubKey pubKey(instance, certObj);
6399N/A+ bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD);
6399N/A+ CACCert certObj(instance, &cert, isPIV);
6399N/A+ CACPrivKey privKey(instance, certObj, isPIV);
6399N/A+ CACPubKey pubKey(instance, certObj, isPIV);
6399N/A tokenObjects.push_back(privKey);
6399N/A tokenObjects.push_back(pubKey);
6399N/A tokenObjects.push_back(certObj);
6399N/A+ if ( pubKey.getKeyType() == PKCS11Object::ecc) {
6399N/A+ algs = (SlotAlgs) (algs | ALG_ECC);
6399N/A+ } else {
6399N/A+ algs = (SlotAlgs) (algs | ALG_RSA);
6399N/A+ }
6399N/A
6399N/A if (personName == NULL) {
6399N/A const char *name = certObj.getName();
6399N/A@@ -2153,6 +2894,94 @@
6399N/A }
6399N/A
6399N/A void
6399N/A+Slot::initCACShMem(void)
6399N/A+{
6399N/A+ bool failed = false;
6399N/A+
6399N/A+ unsigned char firstCert = shmem.getFirstCacCert();
6399N/A+
6399N/A+ log->log("init CACShMem: \n");
6399N/A+ /* check to make sure the shared memory is initialized with a CAC card */
6399N/A+ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION
6399N/A+ && firstCert != NOT_A_CAC) {
6399N/A+ CKYBuffer rawCert;
6399N/A+ CKYBuffer shmCert;
6399N/A+ CKYSize nextSize;
6399N/A+
6399N/A+ log->log("init CACShMem: valid CAC cache found firstCert = %d\n",
6399N/A+ firstCert);
6399N/A+ CKYBuffer_InitEmpty(&rawCert);
6399N/A+ CKYBuffer_InitEmpty(&shmCert);
6399N/A+
6399N/A+
6399N/A+ /* yes, see if it's this cac card by comparing the first cert
6399N/A+ * in the chain */
6399N/A+
6399N/A+ /* see if the first cert is in the expected slot */
6399N/A+ try {
6399N/A+ selectCACApplet(firstCert, false);
6399N/A+ } catch(PKCS11Exception& e) {
6399N/A+ failed = true;
6399N/A+ log->log("init CACShMem: applet select failed firstCert = %d\n",
6399N/A+ firstCert);
6399N/A+ }
6399N/A+ if (!failed) {
6399N/A+ CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize);
6399N/A+ if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) {
6399N/A+ failed = true;
6399N/A+ log->log("init CACShMem: read Cert failed firstCert = %d\n",
6399N/A+ firstCert);
6399N/A+ }
6399N/A+ }
6399N/A+ if (!failed) {
6399N/A+ shmem.readCACCert(&shmCert, firstCert);
6399N/A+ CKYSize certSize = CKYBuffer_Size(&rawCert);
6399N/A+ CKYSize shmCertSize = CKYBuffer_Size(&shmCert);
6399N/A+ const CKYByte *shmData = CKYBuffer_Data(&shmCert);
6399N/A+
6399N/A+ if (shmCertSize >= certSize) {
6399N/A+ if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) {
6399N/A+ /* this card is cached, go on and use the cache */
6399N/A+ log->log("init CACShMem: entries match, using cache\n");
6399N/A+ CKYBuffer_FreeData(&rawCert);
6399N/A+ CKYBuffer_FreeData(&shmCert);
6399N/A+ return;
6399N/A+ }
6399N/A+ }
6399N/A+ log->log("init CACShMem: no entry match certSize=%d"
6399N/A+ " shmCertSize=%d\n",certSize, shmCertSize);
6399N/A+ }
6399N/A+ CKYBuffer_FreeData(&rawCert);
6399N/A+ CKYBuffer_FreeData(&shmCert);
6399N/A+ }
6399N/A+
6399N/A+ log->log("init CACShMem: starting new cache valid=%d version=%d "
6399N/A+ " firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(),
6399N/A+ firstCert);
6399N/A+ /* cache is either invalid or for another card, start initializing it */
6399N/A+ shmem.clearValid(0);
6399N/A+ shmem.setVersion(SHMEM_VERSION);
6399N/A+ shmem.setDataVersion(CAC_DATA_VERSION);
6399N/A+}
6399N/A+
6399N/A+void
6399N/A+Slot::verifyCACShMem(void)
6399N/A+{
6399N/A+ /* if the memory is valid, then nothing to do */
6399N/A+ if (shmem.isValid()) {
6399N/A+ return;
6399N/A+ }
6399N/A+ /* if we didn't find any cert fail */
6399N/A+ if (shmem.getFirstCacCert() == NOT_A_CAC) {
6399N/A+ shmem.clearValid(0);
6399N/A+ disconnect();
6399N/A+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
6399N/A+ }
6399N/A+ /* we're all set, let others see our results */
6399N/A+ shmem.setValid();
6399N/A+}
6399N/A+
6399N/A+void
6399N/A Slot::loadObjects()
6399N/A {
6399N/A // throw away all token objects!
6399N/A@@ -2170,10 +2999,12 @@
6399N/A list<ListObjectInfo> objInfoList;
6399N/A std::list<ListObjectInfo>::iterator iter;
6399N/A
6399N/A- if (state & CAC_CARD) {
6399N/A- loadCACCert(0);
6399N/A- loadCACCert(1);
6399N/A- loadCACCert(2);
6399N/A+ if (state & GOV_CARD) {
6399N/A+ initCACShMem();
6399N/A+ for (int i=0; i < maxCacCerts; i++) {
6399N/A+ loadCACCert(i);
6399N/A+ }
6399N/A+ verifyCACShMem();
6399N/A status = trans.end();
6399N/A loadReaderObject();
6399N/A return;
6399N/A@@ -2399,6 +3230,9 @@
6399N/A }
6399N/A return nonceValid;
6399N/A }
6399N/A+ if (!needLogin) {
6399N/A+ return true;
6399N/A+ }
6399N/A return loggedIn;
6399N/A }
6399N/A
6399N/A@@ -2415,6 +3249,7 @@
6399N/A }
6399N/A
6399N/A if (!isVersion1Key) {
6399N/A+ pinCache.invalidate();
6399N/A pinCache.set((const char *)pPin, ulPinLen);
6399N/A } else if (nonceValid) {
6399N/A throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN);
6399N/A@@ -2424,15 +3259,15 @@
6399N/A CKYStatus status = trans.begin(conn);
6399N/A if(status != CKYSUCCESS ) handleConnectionError();
6399N/A
6399N/A- if (state & CAC_CARD) {
6399N/A- selectCACApplet(0);
6399N/A+ if (state & GOV_CARD) {
6399N/A+ selectCACApplet(0, true);
6399N/A } else {
6399N/A selectApplet();
6399N/A }
6399N/A
6399N/A if (isVersion1Key) {
6399N/A attemptLogin((const char *)pPin);
6399N/A- } else if (state & CAC_CARD) {
6399N/A+ } else if (state & GOV_CARD) {
6399N/A attemptCACLogin();
6399N/A } else {
6399N/A oldAttemptLogin();
6399N/A@@ -2449,16 +3284,19 @@
6399N/A CKYISOStatus result;
6399N/A
6399N/A status = CACApplet_VerifyPIN(conn,
6399N/A- (const char *)CKYBuffer_Data(pinCache.get()), &result);
6399N/A+ (const char *)CKYBuffer_Data(pinCache.get()),
6399N/A+ mCACLocalLogin, &result);
6399N/A if( status == CKYSCARDERR ) {
6399N/A handleConnectionError();
6399N/A }
6399N/A switch( result ) {
6399N/A case CKYISO_SUCCESS:
6399N/A break;
6399N/A- case 6981:
6399N/A+ case 0x6981:
6399N/A+ pinCache.clearPin();
6399N/A throw PKCS11Exception(CKR_PIN_LOCKED);
6399N/A default:
6399N/A+ pinCache.clearPin();
6399N/A if ((result & 0xff00) == 0x6300) {
6399N/A throw PKCS11Exception(CKR_PIN_INCORRECT);
6399N/A }
6399N/A@@ -2487,10 +3325,13 @@
6399N/A case CKYISO_SUCCESS:
6399N/A break;
6399N/A case CKYISO_AUTH_FAILED:
6399N/A+ pinCache.clearPin();
6399N/A throw PKCS11Exception(CKR_PIN_INCORRECT);
6399N/A case CKYISO_IDENTITY_BLOCKED:
6399N/A+ pinCache.clearPin();
6399N/A throw PKCS11Exception(CKR_PIN_LOCKED);
6399N/A default:
6399N/A+ pinCache.clearPin();
6399N/A throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x",
6399N/A result);
6399N/A }
6399N/A@@ -2577,7 +3418,7 @@
6399N/A throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A }
6399N/A
6399N/A- if (state & CAC_CARD) {
6399N/A+ if (state & GOV_CARD) {
6399N/A CACLogout();
6399N/A return;
6399N/A }
6399N/A@@ -2704,7 +3545,7 @@
6399N/A ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
6399N/A ObjectHandleMatch(hObject));
6399N/A
6399N/A- if( iter == tokenObjects.end() ) {
6399N/A+ if ( iter == tokenObjects.end()) {
6399N/A throw PKCS11Exception(CKR_OBJECT_HANDLE_INVALID);
6399N/A }
6399N/A
6399N/A@@ -2788,6 +3629,21 @@
6399N/A }
6399N/A
6399N/A void
6399N/A+SlotList::derive(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
6399N/A+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
6399N/A+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
6399N/A+{
6399N/A+
6399N/A+ CK_SLOT_ID slotID;
6399N/A+ SessionHandleSuffix suffix;
6399N/A+
6399N/A+ decomposeSessionHandle(hSession, slotID, suffix);
6399N/A+
6399N/A+ slots[slotIDToIndex(slotID)]->derive(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey);
6399N/A+
6399N/A+}
6399N/A+
6399N/A+void
6399N/A Slot::ensureValidSession(SessionHandleSuffix suffix)
6399N/A {
6399N/A if( ! isValidSession(suffix) ) {
6399N/A@@ -2821,6 +3677,23 @@
6399N/A return keyNum & 0xFF;
6399N/A }
6399N/A
6399N/A+PKCS11Object::KeyType
6399N/A+Slot::getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey)
6399N/A+{
6399N/A+ ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
6399N/A+ ObjectHandleMatch(hKey));
6399N/A+
6399N/A+ if( iter == tokenObjects.end() ) {
6399N/A+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
6399N/A+ }
6399N/A+
6399N/A+ if( getObjectClass(iter->getMuscleObjID()) != 'k' ) {
6399N/A+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
6399N/A+ }
6399N/A+
6399N/A+ return iter->getKeyType();
6399N/A+}
6399N/A+
6399N/A void
6399N/A Slot::signInit(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
6399N/A CK_OBJECT_HANDLE hKey)
6399N/A@@ -2830,7 +3703,10 @@
6399N/A if( session == sessions.end() ) {
6399N/A throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A }
6399N/A- session->signatureState.initialize(objectHandleToKeyNum(hKey));
6399N/A+
6399N/A+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
6399N/A+
6399N/A+ session->signatureState.initialize(objectHandleToKeyNum(hKey), keyType);
6399N/A }
6399N/A
6399N/A void
6399N/A@@ -2842,7 +3718,10 @@
6399N/A if( session == sessions.end() ) {
6399N/A throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A }
6399N/A- session->decryptionState.initialize(objectHandleToKeyNum(hKey));
6399N/A+
6399N/A+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
6399N/A+
6399N/A+ session->decryptionState.initialize(objectHandleToKeyNum(hKey), keyType);
6399N/A }
6399N/A
6399N/A /**
6399N/A@@ -2951,6 +3830,93 @@
6399N/A }
6399N/A }
6399N/A
6399N/A+class ECCKeyAgreementParams : public CryptParams {
6399N/A+ public:
6399N/A+ ECCKeyAgreementParams(unsigned int keysize) : CryptParams(keysize) { }
6399N/A+
6399N/A+ CKYByte getDirection() const { return CKY_DIR_NONE;}
6399N/A+
6399N/A+ CryptOpState& getOpState(Session& session) const {
6399N/A+ return session.keyAgreementState;
6399N/A+ }
6399N/A+
6399N/A+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ void
6399N/A+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+};
6399N/A+
6399N/A+class SignatureParams : public CryptParams {
6399N/A+ public:
6399N/A+ SignatureParams(unsigned int keysize) : CryptParams(keysize) { }
6399N/A+
6399N/A+ CKYByte getDirection() const { return CKY_DIR_NONE; }
6399N/A+
6399N/A+ CryptOpState& getOpState(Session& session) const {
6399N/A+ return session.signatureState;
6399N/A+ }
6399N/A+
6399N/A+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ void
6399N/A+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+};
6399N/A+
6399N/A+
6399N/A+
6399N/A+class ECCSignatureParams : public CryptParams {
6399N/A+ public:
6399N/A+ ECCSignatureParams(unsigned int keysize) : CryptParams(keysize) { }
6399N/A+
6399N/A+ CKYByte getDirection() const { return CKY_DIR_NONE; }
6399N/A+
6399N/A+ CryptOpState& getOpState(Session& session) const {
6399N/A+ return session.signatureState;
6399N/A+ }
6399N/A+
6399N/A+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
6399N/A+ return;
6399N/A+ }
6399N/A+
6399N/A+ void
6399N/A+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
6399N/A+ /* Here we will unpack the DER encoding of the signature */
6399N/A+
6399N/A+ if ( unpaddedOutput == NULL || paddedOutput == NULL) {
6399N/A+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer rawSignature;
6399N/A+ CKYBuffer_InitEmpty(&rawSignature);
6399N/A+
6399N/A+ DEREncodedSignature sig(paddedOutput);
6399N/A+
6399N/A+ int rv = sig.getRawSignature(&rawSignature, getKeySize() );
6399N/A+
6399N/A+ if (rv == CKYSUCCESS) {
6399N/A+ CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(&rawSignature),
6399N/A+ CKYBuffer_Size(&rawSignature));
6399N/A+ } else {
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer_FreeData(&rawSignature);
6399N/A+
6399N/A+ }
6399N/A+
6399N/A+};
6399N/A+
6399N/A+
6399N/A class RSASignatureParams : public CryptParams {
6399N/A public:
6399N/A RSASignatureParams(unsigned int keysize) : CryptParams(keysize) { }
6399N/A@@ -3009,8 +3975,38 @@
6399N/A CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
6399N/A CK_ULONG_PTR pulSignatureLen)
6399N/A {
6399N/A- cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
6399N/A- RSASignatureParams(CryptParams::FIXED_KEY_SIZE));
6399N/A+
6399N/A+ refreshTokenState();
6399N/A+ SessionIter session = findSession(suffix);
6399N/A+ if( session == sessions.end() ) {
6399N/A+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A+ }
6399N/A+
6399N/A+ if (!isVersion1Key && ! isLoggedIn() ) {
6399N/A+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
6399N/A+ }
6399N/A+
6399N/A+ /* Create a default one just to get the sigState */
6399N/A+ SignatureParams dummyParams(CryptParams::DEFAULT_KEY_SIZE);
6399N/A+
6399N/A+ CryptOpState sigState = dummyParams.getOpState(*session);
6399N/A+
6399N/A+ PKCS11Object::KeyType keyType = sigState.keyType;
6399N/A+
6399N/A+ if ( keyType == PKCS11Object::unknown) {
6399N/A+ throw PKCS11Exception(CKR_DATA_INVALID);
6399N/A+ }
6399N/A+
6399N/A+ if( keyType == Key::ecc ) {
6399N/A+ ECCSignatureParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
6399N/A+ signECC(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
6399N/A+ params);
6399N/A+
6399N/A+ } else if (keyType == Key::rsa) {
6399N/A+ RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE);
6399N/A+ cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
6399N/A+ params);
6399N/A+ }
6399N/A }
6399N/A
6399N/A void
6399N/A@@ -3018,14 +4014,15 @@
6399N/A CK_ULONG ulDataLen, CK_BYTE_PTR pDecryptedData,
6399N/A CK_ULONG_PTR pulDecryptedDataLen)
6399N/A {
6399N/A+ RSADecryptParams params(CryptParams::DEFAULT_KEY_SIZE);
6399N/A cryptRSA(suffix, pData, ulDataLen, pDecryptedData, pulDecryptedDataLen,
6399N/A- RSADecryptParams(CryptParams::FIXED_KEY_SIZE));
6399N/A+ params);
6399N/A }
6399N/A
6399N/A void
6399N/A Slot::cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
6399N/A CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
6399N/A- CK_ULONG_PTR pulOutputLen, const CryptParams& params)
6399N/A+ CK_ULONG_PTR pulOutputLen, CryptParams& params)
6399N/A {
6399N/A refreshTokenState();
6399N/A SessionIter session = findSession(suffix);
6399N/A@@ -3043,6 +4040,11 @@
6399N/A CKYBuffer *result = &opState.result;
6399N/A CKYByte keyNum = opState.keyNum;
6399N/A
6399N/A+ unsigned int keySize = getRSAKeySize(keyNum);
6399N/A+
6399N/A+ if (keySize != CryptParams::DEFAULT_KEY_SIZE)
6399N/A+ params.setKeySize(keySize);
6399N/A+
6399N/A if( CKYBuffer_Size(result) == 0 ) {
6399N/A // we haven't already peformed the decryption, so do it now.
6399N/A if( pInput == NULL || ulInputLen == 0) {
6399N/A@@ -3062,7 +4064,8 @@
6399N/A }
6399N/A try {
6399N/A params.padInput(&inputPad, &input);
6399N/A- performRSAOp(&output, &inputPad, keyNum, params.getDirection());
6399N/A+ performRSAOp(&output, &inputPad, params.getKeySize(),
6399N/A+ keyNum, params.getDirection());
6399N/A params.unpadOutput(result, &output);
6399N/A CKYBuffer_FreeData(&input);
6399N/A CKYBuffer_FreeData(&inputPad);
6399N/A@@ -3099,10 +4102,159 @@
6399N/A return &nonce;
6399N/A }
6399N/A
6399N/A+void Slot::signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
6399N/A+ CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
6399N/A+ CK_ULONG_PTR pulOutputLen, CryptParams& params)
6399N/A+{
6399N/A+
6399N/A+ if( pulOutputLen == NULL ) {
6399N/A+ throw PKCS11Exception(CKR_DATA_INVALID,
6399N/A+ "output length is NULL");
6399N/A+ }
6399N/A+
6399N/A+ refreshTokenState();
6399N/A+ SessionIter session = findSession(suffix);
6399N/A+ if( session == sessions.end() ) {
6399N/A+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A+ }
6399N/A+ /* version 1 keys may not need login. We catch the error
6399N/A+ on the operation. The token will not allow us to sign with
6399N/A+ a protected key unless we are logged in.
6399N/A+ can be removed when version 0 support is depricated.
6399N/A+ */
6399N/A+
6399N/A+ if (!isVersion1Key && ! isLoggedIn() ) {
6399N/A+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
6399N/A+ }
6399N/A+ CryptOpState& opState = params.getOpState(*session);
6399N/A+ CKYBuffer *result = &opState.result;
6399N/A+ CKYByte keyNum = opState.keyNum;
6399N/A+
6399N/A+ unsigned int keySize = getECCKeySize(keyNum);
6399N/A+
6399N/A+ if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
6399N/A+ params.setKeySize(keySize);
6399N/A+
6399N/A+ if( CKYBuffer_Size(result) == 0 ) {
6399N/A+ unsigned int maxSize = params.getKeySize()/8;
6399N/A+
6399N/A+ if( pInput == NULL || ulInputLen == 0) {
6399N/A+ throw PKCS11Exception(CKR_DATA_LEN_RANGE);
6399N/A+ }
6399N/A+ if (ulInputLen > maxSize) {
6399N/A+ //pInput += ulInputLen - maxSize;
6399N/A+ ulInputLen = maxSize;
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer input;
6399N/A+ CKYBuffer output;
6399N/A+ CKYBuffer_InitEmpty(&output);
6399N/A+ CKYStatus status = CKYBuffer_InitFromData(&input, pInput, ulInputLen);
6399N/A+
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ CKYBuffer_FreeData(&output);
6399N/A+ throw PKCS11Exception(CKR_HOST_MEMORY);
6399N/A+ }
6399N/A+ try {
6399N/A+ performECCSignature(&output, &input, params.getKeySize(), keyNum);
6399N/A+ params.unpadOutput(result, &output);
6399N/A+ CKYBuffer_FreeData(&input);
6399N/A+ CKYBuffer_FreeData(&output);
6399N/A+ } catch(PKCS11Exception& e) {
6399N/A+ CKYBuffer_FreeData(&input);
6399N/A+ CKYBuffer_FreeData(&output);
6399N/A+ throw(e);
6399N/A+ }
6399N/A+ }
6399N/A+
6399N/A+ if( pOutput != NULL ) {
6399N/A+ if( *pulOutputLen < CKYBuffer_Size(result) ) {
6399N/A+ *pulOutputLen = CKYBuffer_Size(result);
6399N/A+ throw PKCS11Exception(CKR_BUFFER_TOO_SMALL);
6399N/A+ }
6399N/A+ memcpy(pOutput, CKYBuffer_Data(result), CKYBuffer_Size(result));
6399N/A+ }
6399N/A+ *pulOutputLen = CKYBuffer_Size(result);
6399N/A+}
6399N/A+
6399N/A+void
6399N/A+Slot::performECCSignature(CKYBuffer *output, const CKYBuffer *input,
6399N/A+ unsigned int keySize, CKYByte keyNum)
6399N/A+{
6399N/A+
6399N/A+ /* establish a transaction */
6399N/A+ Transaction trans;
6399N/A+ CKYStatus status = trans.begin(conn);
6399N/A+ if( status != CKYSUCCESS ) handleConnectionError();
6399N/A+
6399N/A+ if (state & GOV_CARD) {
6399N/A+ selectCACApplet(keyNum, true);
6399N/A+ } else {
6399N/A+ selectApplet();
6399N/A+ }
6399N/A+
6399N/A+ CKYISOStatus result;
6399N/A+ int loginAttempted = 0;
6399N/A+
6399N/A+retry:
6399N/A+ if (state & PIV_CARD) {
6399N/A+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
6399N/A+ } else if (state & CAC_CARD) {
6399N/A+ status = CACApplet_SignDecrypt(conn, input, output, &result);
6399N/A+ } else {
6399N/A+ status = CKYApplet_ComputeECCSignature(conn, keyNum, input, NULL, output, getNonce(), &result);
6399N/A+ }
6399N/A+ /* map the ISO not logged in code to the coolkey one */
6399N/A+ if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
6399N/A+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
6399N/A+ result = (CKYStatus) CKYISO_UNAUTHORIZED;
6399N/A+ }
6399N/A+
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ if ( status == CKYSCARDERR ) {
6399N/A+ handleConnectionError();
6399N/A+ }
6399N/A+
6399N/A+ if (result == CKYISO_DATA_INVALID) {
6399N/A+ throw PKCS11Exception(CKR_DATA_INVALID);
6399N/A+ }
6399N/A+ /* version0 keys could be logged out in the middle by someone else,
6399N/A+ reauthenticate... This code can go away when we depricate.
6399N/A+ version0 applets.
6399N/A+ */
6399N/A+ if (!isVersion1Key && !loginAttempted &&
6399N/A+ (result == CKYISO_UNAUTHORIZED)) {
6399N/A+ /* try to reauthenticate */
6399N/A+ try {
6399N/A+ if (state & GOV_CARD) {
6399N/A+ attemptCACLogin();
6399N/A+ } else {
6399N/A+ oldAttemptLogin();
6399N/A+ }
6399N/A+ } catch(PKCS11Exception& ) {
6399N/A+ /* attemptLogin can throw things like CKR_PIN_INCORRECT
6399N/A+ that don't make sense from a crypto operation. This is
6399N/A+ a result of pin caching. We will reformat any login
6399N/A+ exception to a CKR_DEVICE_ERROR.
6399N/A+ */
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A+ }
6399N/A+ loginAttempted = true;
6399N/A+ goto retry; /* easier to understand than a while loop in this case. */
6399N/A+ }
6399N/A+ throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
6399N/A+ CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
6399N/A+
6399N/A+ }
6399N/A+
6399N/A+}
6399N/A+
6399N/A+
6399N/A void
6399N/A-Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input,
6399N/A+Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, unsigned int keySize,
6399N/A CKYByte keyNum, CKYByte direction)
6399N/A {
6399N/A+
6399N/A //
6399N/A // establish a transaction
6399N/A //
6399N/A@@ -3113,8 +4265,8 @@
6399N/A //
6399N/A // select the applet
6399N/A //
6399N/A- if (state & CAC_CARD) {
6399N/A- selectCACApplet(keyNum);
6399N/A+ if (state & GOV_CARD) {
6399N/A+ selectCACApplet(keyNum, true);
6399N/A } else {
6399N/A selectApplet();
6399N/A }
6399N/A@@ -3122,12 +4274,21 @@
6399N/A CKYISOStatus result;
6399N/A int loginAttempted = 0;
6399N/A retry:
6399N/A- if (state & CAC_CARD) {
6399N/A+ if (state & PIV_CARD) {
6399N/A+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
6399N/A+ } else if (state & CAC_CARD) {
6399N/A status = CACApplet_SignDecrypt(conn, input, output, &result);
6399N/A } else {
6399N/A status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
6399N/A input, NULL, output, getNonce(), &result);
6399N/A }
6399N/A+
6399N/A+ /* map the ISO not logged in code to the coolkey one */
6399N/A+ if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
6399N/A+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
6399N/A+ result = CKYISO_UNAUTHORIZED;
6399N/A+ }
6399N/A+
6399N/A if (status != CKYSUCCESS) {
6399N/A if ( status == CKYSCARDERR ) {
6399N/A handleConnectionError();
6399N/A@@ -3138,11 +4299,15 @@
6399N/A // version0 keys could be logged out in the middle by someone else,
6399N/A // reauthenticate... This code can go away when we depricate.
6399N/A // version0 applets.
6399N/A- if (!isVersion1Key && !loginAttempted &&
6399N/A+ if (!isVersion1Key && !loginAttempted && pinCache.isValid() &&
6399N/A (result == CKYISO_UNAUTHORIZED)) {
6399N/A // try to reauthenticate
6399N/A try {
6399N/A- oldAttemptLogin();
6399N/A+ if (state & GOV_CARD) {
6399N/A+ attemptCACLogin();
6399N/A+ } else {
6399N/A+ oldAttemptLogin();
6399N/A+ }
6399N/A } catch(PKCS11Exception& ) {
6399N/A // attemptLogin can throw things like CKR_PIN_INCORRECT
6399N/A // that don't make sense from a crypto operation. This is
6399N/A@@ -3162,7 +4327,7 @@
6399N/A Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
6399N/A CK_ULONG ulDataLen)
6399N/A {
6399N/A- if (state & CAC_CARD) {
6399N/A+ if (state & GOV_CARD) {
6399N/A /* should throw unsupported */
6399N/A throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A }
6399N/A@@ -3214,7 +4379,7 @@
6399N/A Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData,
6399N/A CK_ULONG ulDataLen)
6399N/A {
6399N/A- if (state & CAC_CARD) {
6399N/A+ if (state & GOV_CARD) {
6399N/A /* should throw unsupported */
6399N/A throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A }
6399N/A@@ -3245,3 +4410,268 @@
6399N/A throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A }
6399N/A }
6399N/A+
6399N/A+#define MAX_NUM_KEYS 8
6399N/A+unsigned int
6399N/A+Slot::getRSAKeySize(CKYByte keyNum)
6399N/A+{
6399N/A+ unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE;
6399N/A+ int modSize = 0;
6399N/A+
6399N/A+ if(keyNum >= MAX_NUM_KEYS) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ ObjectConstIter iter;
6399N/A+ iter = find_if(tokenObjects.begin(), tokenObjects.end(),
6399N/A+ KeyNumMatch(keyNum,*this));
6399N/A+
6399N/A+ if( iter == tokenObjects.end() ) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS);
6399N/A+
6399N/A+ if(modulus) {
6399N/A+ modSize = CKYBuffer_Size(modulus);
6399N/A+ if(CKYBuffer_GetChar(modulus,0) == 0x0) {
6399N/A+ modSize--;
6399N/A+ }
6399N/A+ if(modSize > 0)
6399N/A+ keySize = modSize * 8;
6399N/A+ }
6399N/A+
6399N/A+ return keySize;
6399N/A+}
6399N/A+
6399N/A+unsigned int
6399N/A+Slot::getECCKeySize(CKYByte keyNum)
6399N/A+{
6399N/A+ return calcECCKeySize(keyNum);
6399N/A+}
6399N/A+
6399N/A+unsigned int
6399N/A+Slot::calcECCKeySize(CKYByte keyNum)
6399N/A+{
6399N/A+ unsigned int keySize = CryptParams::ECC_DEFAULT_KEY_SIZE;
6399N/A+
6399N/A+ if(keyNum >= MAX_NUM_KEYS) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ ObjectConstIter iter;
6399N/A+ iter = find_if(tokenObjects.begin(), tokenObjects.end(),
6399N/A+ KeyNumMatch(keyNum,*this));
6399N/A+
6399N/A+ if( iter == tokenObjects.end() ) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer const *eccParams = iter->getAttribute(CKA_EC_PARAMS);
6399N/A+
6399N/A+ if (eccParams == NULL) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ /* Extract the oid from the params */
6399N/A+
6399N/A+ CKYByte ecParamsLen = CKYBuffer_GetChar(eccParams, 1);
6399N/A+
6399N/A+ if ( ecParamsLen == 0 ) {
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+/* Now compare against the limited known list of oid byte info */
6399N/A+
6399N/A+ unsigned int oidByteLen = 0;
6399N/A+
6399N/A+ CKYByte curByte = 0;
6399N/A+
6399N/A+ for (int i = 0 ; i < numECCurves ; i++ ) {
6399N/A+
6399N/A+ oidByteLen = curveBytesNamePair[i].bytes[0];
6399N/A+
6399N/A+ if ( oidByteLen != (unsigned int ) ecParamsLen ) {
6399N/A+ continue;
6399N/A+ }
6399N/A+
6399N/A+ int match = 1;
6399N/A+ for ( int j = 0 ; j < ecParamsLen ; j++ ) {
6399N/A+ curByte = CKYBuffer_GetChar(eccParams, 2 + j );
6399N/A+ if ( curveBytesNamePair[i].bytes[ j + 1 ] != curByte ) {
6399N/A+ match = 0;
6399N/A+ break;
6399N/A+ }
6399N/A+ }
6399N/A+
6399N/A+ if ( match == 1 ) {
6399N/A+ keySize = curveBytesNamePair[i].length;
6399N/A+ return keySize;
6399N/A+ }
6399N/A+
6399N/A+ }
6399N/A+
6399N/A+ return keySize;
6399N/A+}
6399N/A+
6399N/A+void
6399N/A+Slot::derive(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
6399N/A+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
6399N/A+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
6399N/A+{
6399N/A+
6399N/A+ log->log("Inside of Slot::Derive! \n");
6399N/A+
6399N/A+ ECCKeyAgreementParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
6399N/A+ SessionIter session = findSession(suffix);
6399N/A+
6399N/A+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hBaseKey);
6399N/A+
6399N/A+ session->keyAgreementState.initialize(objectHandleToKeyNum(hBaseKey), keyType);
6399N/A+ deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey, params);
6399N/A+
6399N/A+}
6399N/A+
6399N/A+void Slot::deriveECC(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
6399N/A+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params)
6399N/A+{
6399N/A+ if (pMechanism == NULL ) {
6399N/A+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
6399N/A+ }
6399N/A+
6399N/A+ CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
6399N/A+
6399N/A+ mechParams = (CK_ECDH1_DERIVE_PARAMS*) pMechanism->pParameter;
6399N/A+
6399N/A+ if (mechParams == NULL || mechParams->kdf != CKD_NULL ) {
6399N/A+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
6399N/A+ }
6399N/A+
6399N/A+ refreshTokenState();
6399N/A+ SessionIter session = findSession(suffix);
6399N/A+ if( session == sessions.end() ) {
6399N/A+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
6399N/A+ }
6399N/A+
6399N/A+ /* version 1 keys may not need login. We catch the error
6399N/A+ on the operation. The token will not allow us to sign with
6399N/A+ a protected key unless we are logged in.
6399N/A+ can be removed when version 0 support is depricated. */
6399N/A+
6399N/A+ if (!isVersion1Key && ! isLoggedIn() ) {
6399N/A+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
6399N/A+ }
6399N/A+
6399N/A+ CryptOpState& opState = params.getOpState(*session);
6399N/A+ CKYBuffer *result = &opState.result;
6399N/A+ CKYByte keyNum = opState.keyNum;
6399N/A+
6399N/A+ unsigned int keySize = getECCKeySize(keyNum);
6399N/A+
6399N/A+ if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
6399N/A+ params.setKeySize(keySize);
6399N/A+
6399N/A+ CK_MECHANISM_TYPE deriveMech = pMechanism->mechanism;
6399N/A+
6399N/A+ CK_ULONG otherPublicLen = mechParams->ulPublicDataLen;
6399N/A+ CK_BYTE_PTR otherPublicData = mechParams->pPublicData;
6399N/A+
6399N/A+ CKYBuffer secretKeyBuffer;
6399N/A+ CKYBuffer_InitEmpty(&secretKeyBuffer);
6399N/A+ CKYBuffer publicDataBuffer;
6399N/A+ CKYStatus status = CKYBuffer_InitFromData(&publicDataBuffer,otherPublicData, otherPublicLen);
6399N/A+
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ CKYBuffer_FreeData(&secretKeyBuffer);
6399N/A+ throw PKCS11Exception(CKR_HOST_MEMORY);
6399N/A+ }
6399N/A+
6399N/A+ PKCS11Object *secret = NULL;
6399N/A+ *phKey = 0;
6399N/A+
6399N/A+ if( CKYBuffer_Size(result) == 0 ) {
6399N/A+ try {
6399N/A+ performECCKeyAgreement(deriveMech, &publicDataBuffer, &secretKeyBuffer,
6399N/A+ keyNum, params.getKeySize());
6399N/A+ CK_OBJECT_HANDLE keyObjectHandle = generateUnusedObjectHandle();
6399N/A+ secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, pTemplate, ulAttributeCount);
6399N/A+ } catch(PKCS11Exception& e) {
6399N/A+ CKYBuffer_FreeData(&secretKeyBuffer);
6399N/A+ CKYBuffer_FreeData(&publicDataBuffer);
6399N/A+ throw(e);
6399N/A+ }
6399N/A+ }
6399N/A+
6399N/A+ CKYBuffer_FreeData(&secretKeyBuffer);
6399N/A+ CKYBuffer_FreeData(&publicDataBuffer);
6399N/A+
6399N/A+ if ( secret ) {
6399N/A+
6399N/A+ *phKey = secret->getHandle();
6399N/A+ delete secret;
6399N/A+ }
6399N/A+}
6399N/A+
6399N/A+void
6399N/A+Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, CKYBuffer *publicDataBuffer,
6399N/A+ CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize)
6399N/A+{
6399N/A+
6399N/A+ Transaction trans;
6399N/A+ CKYStatus status = trans.begin(conn);
6399N/A+ if( status != CKYSUCCESS ) handleConnectionError();
6399N/A+
6399N/A+ if (state & GOV_CARD) {
6399N/A+ selectCACApplet(keyNum, true);
6399N/A+ } else {
6399N/A+ selectApplet();
6399N/A+ }
6399N/A+
6399N/A+ CKYISOStatus result;
6399N/A+ int loginAttempted = 0;
6399N/A+
6399N/A+retry:
6399N/A+
6399N/A+ if (state & PIV_CARD) {
6399N/A+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, publicDataBuffer,
6399N/A+ secretKeyBuffer, &result);
6399N/A+ } else if (state & CAC_CARD) {
6399N/A+ status = CACApplet_SignDecrypt(conn, publicDataBuffer, secretKeyBuffer, &result);
6399N/A+ } else {
6399N/A+ status = CKYApplet_ComputeECCKeyAgreement(conn, keyNum,
6399N/A+ publicDataBuffer , NULL, secretKeyBuffer, getNonce(), &result);
6399N/A+ }
6399N/A+ /* map the ISO not logged in code to the coolkey one */
6399N/A+ if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
6399N/A+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
6399N/A+ result = (CKYStatus) CKYISO_UNAUTHORIZED;
6399N/A+ }
6399N/A+
6399N/A+ if (status != CKYSUCCESS) {
6399N/A+ if ( status == CKYSCARDERR ) {
6399N/A+ handleConnectionError();
6399N/A+ }
6399N/A+
6399N/A+ if (result == CKYISO_DATA_INVALID) {
6399N/A+ throw PKCS11Exception(CKR_DATA_INVALID);
6399N/A+ }
6399N/A+ if (!isVersion1Key && !loginAttempted &&
6399N/A+ (result == CKYISO_UNAUTHORIZED)) {
6399N/A+ try {
6399N/A+ if (state & GOV_CARD) {
6399N/A+ attemptCACLogin();
6399N/A+ } else {
6399N/A+ oldAttemptLogin();
6399N/A+ }
6399N/A+ } catch(PKCS11Exception& ) {
6399N/A+ throw PKCS11Exception(CKR_DEVICE_ERROR);
6399N/A+ }
6399N/A+ loginAttempted = true;
6399N/A+ goto retry;
6399N/A+ }
6399N/A+
6399N/A+ throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
6399N/A+ CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
6399N/A+
6399N/A+ }
6399N/A+}