Author: rrelyea
Update of /cvs/dirsec/coolkey/src/coolkey
In directory cvs01.phx2.fedoraproject.org:/tmp/cvs-serv6855/src/coolkey
Modified Files:
object.cpp slot.cpp slot.h
Log Message:
New CAC support
Index: object.cpp
===================================================================
RCS file: /cvs/dirsec/coolkey/src/coolkey/object.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- object.cpp 16 Sep 2009 23:56:40 -0000 1.4
+++ object.cpp 8 Sep 2010 20:14:40 -0000 1.5
@@ -505,6 +505,10 @@
unsigned char tag;
unsigned int used_length= 0;
+ if(!buf) {
+ return NULL;
+ }
+
tag = buf[used_length++];
/* blow out when we come to the end */
Index: slot.cpp
===================================================================
RCS file: /cvs/dirsec/coolkey/src/coolkey/slot.cpp,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- slot.cpp 9 Dec 2009 01:55:15 -0000 1.13
+++ slot.cpp 8 Sep 2010 20:14:41 -0000 1.14
@@ -372,7 +372,7 @@
: log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN),
isVersion1Key(false), needLogin(false), fullTokenName(false),
- mCoolkey(false),
+ mCoolkey(false), mOldCAC(false),
#ifdef USE_SHMEM
shmem(readerName_),
#endif
@@ -412,6 +412,9 @@
}
CKYBuffer_InitEmpty(&cardATR);
CKYBuffer_InitEmpty(&mCUID);
+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
+ CKYBuffer_InitEmpty(&cardAID[i]);
+ }
} catch(PKCS11Exception &) {
if (conn) {
CKYCardConnection_Destroy(conn);
@@ -479,6 +482,9 @@
CKYBuffer_FreeData(&nonce);
CKYBuffer_FreeData(&cardATR);
CKYBuffer_FreeData(&mCUID);
+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
+ CKYBuffer_FreeData(&cardAID[i]);
+ }
}
template <class C>
@@ -583,6 +589,7 @@
if( ! CKYCardConnection_IsConnected(conn) ) {
int i = 0;
//for cranky readers try again a few more times
+ status = CKYSCARDERR;
while( i++ < 5 && status != CKYSUCCESS )
{
status = CKYCardConnection_Connect(conn, readerName);
@@ -671,12 +678,12 @@
status = CKYApplet_SelectCoolKeyManager(conn, NULL);
if (status != CKYSUCCESS) {
log->log("CoolKey Select failed 0x%x\n", status);
- status = CACApplet_SelectPKI(conn, 0, NULL);
+ status = getCACAid();
if (status != CKYSUCCESS) {
- log->log("CAC Select failed 0x%x\n", status);
+ log->log("CAC Select failed 0x%x\n", status);
if (status == CKYSCARDERR) {
- log->log("CAC Card Failure 0x%x\n",
- CKYCardConnection_GetLastError(conn));
+ log->log("CAC Card Failure 0x%x\n",
+ CKYCardConnection_GetLastError(conn));
disconnect();
}
return;
@@ -689,6 +696,15 @@
isVersion1Key = 0;
needLogin = 1;
mCoolkey = 0;
+ return;
+loser:
+ log->log("CAC Select failed 0x%x\n", status);
+ if (status == CKYSCARDERR) {
+ log->log("CAC Card Failure 0x%x\n",
+ CKYCardConnection_GetLastError(conn));
+ disconnect();
+ }
+
return;
}
@@ -772,17 +788,111 @@
invalidateLogin(false);
}
+CKYStatus
+Slot::getCACAid()
+{
+ CKYBuffer tBuf;
+ CKYBuffer vBuf;
+ CKYSize tlen, vlen;
+ CKYOffset toffset, voffset;
+ int certSlot = 0;
+ int i,length = 0;
+ CKYStatus status;
+
+ CKYBuffer_InitEmpty(&tBuf);
+ CKYBuffer_InitEmpty(&vBuf);
+
+ /* clear out the card AID's */
+ for (i=0; i < MAX_CERT_SLOTS; i++) {
+ CKYBuffer_Resize(&cardAID[i],0);
+ }
+
+ status = CACApplet_SelectCCC(conn,NULL);
+ if (status != CKYSUCCESS) {
+ /* are we an old CAC */
+ status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL);
+ if (status != CKYSUCCESS) {
+ /* no, just fail */
+ return status;
+ }
+ /* yes, fill in the old applets */
+ mOldCAC = true;
+ for (i=1; i< MAX_CERT_SLOTS; i++) {
+ CACApplet_SelectPKI(conn, &cardAID[i], i, NULL);
+ }
+ return CKYSUCCESS;
+ }
+ /* definately not an old CAC */
+ mOldCAC = false;
+
+ /* read the TLV */
+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ tlen = CKYBuffer_Size(&tBuf);
+ vlen = CKYBuffer_Size(&vBuf);
+
+ for(toffset = 2, voffset=2;
+ certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ;
+ voffset += length) {
+
+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
+ toffset += 2;
+ if (length == 0xff) {
+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
+ toffset +=2;
+ }
+ if (tag != CAC_TAG_CARDURL) {
+ continue;
+ }
+ /* CARDURL tags must be at least 10 bytes long */
+ if (length < 10) {
+ continue;
+ }
+ /* check the app type, should be TLV_APP_PKI */
+ if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) {
+ continue;
+ }
+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf,
+ voffset+8, 2);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6);
+
+ certSlot++;
+ }
+ status = CKYSUCCESS;
+ if (certSlot == 0) {
+ status = CKYAPDUFAIL; /* probably neeed a beter error code */
+ }
+
+done:
+ CKYBuffer_FreeData(&tBuf);
+ CKYBuffer_FreeData(&vBuf);
+ return status;
+}
+
void
Slot::refreshTokenState()
{
if( cardStateMayHaveChanged() ) {
-log->log("card changed\n");
+ log->log("card changed\n");
invalidateLogin(true);
closeAllSessions();
unloadObjects();
connectToToken();
-
if( state & APPLET_PERSONALIZED ) {
try {
loadObjects();
@@ -1020,7 +1130,7 @@
struct _manList {
unsigned short type;
- char *string;
+ const char *string;
};
static const struct _manList manList[] = {
@@ -1281,13 +1391,30 @@
Slot::selectCACApplet(CKYByte instance)
{
CKYStatus status;
- status = CACApplet_SelectPKI(conn, instance, NULL);
+ CKYBuffer *aid = &cardAID[instance];
+
+ if (CKYBuffer_Size(aid) == 0) {
+ disconnect();
+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
+ return;
+ }
+
+ status = CKYApplet_SelectFile(conn, aid, NULL);
if ( status == CKYSCARDERR ) handleConnectionError();
if ( status != CKYSUCCESS) {
// could not select applet: this just means it's not there
disconnect();
throw PKCS11Exception(CKR_DEVICE_REMOVED);
}
+ if (mOldCAC) {
+ return;
+ }
+ status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
+ if ( status == CKYSCARDERR ) handleConnectionError();
+ if ( status != CKYSUCCESS) {
+ disconnect();
+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
+ }
}
// assume we are already in a transaction
void
@@ -2060,10 +2187,90 @@
return objInfoList;
}
+CKYStatus
+Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize,
+ bool throwException)
+{
+ CKYStatus status;
+ CKYISOStatus apduRC;
+ *nextSize = 0;
+
+ if (mOldCAC) {
+ /* get the first 100 bytes of the cert */
+ status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC);
+ if (throwException && (status != CKYSUCCESS)) {
+ handleConnectionError();
+ }
+
+ if(CKYBuffer_Size(cert) == 0) {
+ handleConnectionError();
+ }
+ return status;
+ }
+
+ CKYBuffer tBuf;
+ CKYBuffer vBuf;
+ CKYSize tlen, vlen;
+ CKYOffset toffset, voffset;
+ int length = 0;
+
+ CKYBuffer_InitEmpty(&tBuf);
+ CKYBuffer_InitEmpty(&vBuf);
+ CKYBuffer_Resize(cert, 0);
+
+ /* handle the new CAC card read */
+ /* read the TLV */
+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
+ if (status != CKYSUCCESS) {
+ goto done;
+ }
+ tlen = CKYBuffer_Size(&tBuf);
+ vlen = CKYBuffer_Size(&vBuf);
+
+ /* look for the Cert out of the TLV */
+ for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ;
+ voffset += length) {
+
+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
+ toffset += 2;
+ if (length == 0xff) {
+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
+ toffset +=2;
+ }
+ if (tag != CAC_TAG_CERTIFICATE) {
+ continue;
+ }
+ CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
+ break;
+ }
+ status = CKYSUCCESS;
+
+done:
+ CKYBuffer_FreeData(&tBuf);
+ CKYBuffer_FreeData(&vBuf);
+ return status;
+}
+
+/*
+ * only necessary for old CAC cards. New CAC cards have to read the
+ * whole cert in anyway above....
+ */
+CKYStatus
+Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize)
+{
+ CKYISOStatus apduRC;
+ assert(mOldCAC);
+ return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC);
+}
+
void
Slot::loadCACCert(CKYByte instance)
{
- CKYISOStatus apduRC;
CKYStatus status = CKYSUCCESS;
CKYBuffer cert;
CKYBuffer rawCert;
@@ -2098,12 +2305,10 @@
instance, OSTimeNow() - time);
if (instance == 0) {
- /* get the first 100 bytes of the cert */
- status = CACApplet_GetCertificateFirst(conn, &rawCert,
- &nextSize, &apduRC);
- if (status != CKYSUCCESS) {
- handleConnectionError();
- }
+ readCACCertificateFirst(&rawCert, &nextSize, true);
+ if(CKYBuffer_Size(&rawCert) == 0) {
+ handleConnectionError();
+ }
log->log("CAC Cert %d: fetch CAC Cert: %d ms\n",
instance, OSTimeNow() - time);
}
@@ -2144,8 +2349,7 @@
shmem.setVersion(SHMEM_VERSION);
shmem.setDataVersion(dataVersion);
} else {
- status = CACApplet_GetCertificateFirst(conn, &rawCert,
- &nextSize, &apduRC);
+ status = readCACCertificateFirst(&rawCert, &nextSize, false);
if (status != CKYSUCCESS) {
/* CAC only requires the Certificate in pki '0' */
@@ -2160,8 +2364,7 @@
}
if (nextSize) {
- status = CACApplet_GetCertificateAppend(conn, &rawCert,
- nextSize, &apduRC);
+ status = readCACCertificateAppend(&rawCert, nextSize);
}
log->log("CAC Cert %d: Fetch rest : %d ms\n",
instance, OSTimeNow() - time);
@@ -2177,9 +2380,10 @@
log->log("CAC Cert %d: Cert has been read: %d ms\n",
instance, OSTimeNow() - time);
- if (CKYBuffer_GetChar(&rawCert,0) == 1) {
+ if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) {
CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
CKYSize certSize = 0;
+ CKYOffset offset = mOldCAC ? 1 : 0;
int zret = Z_MEM_ERROR;
do {
@@ -2190,7 +2394,8 @@
}
certSize = guessFinalSize;
zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
- CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1);
+ CKYBuffer_Data(&rawCert)+offset,
+ CKYBuffer_Size(&rawCert)-offset);
} while (zret == Z_BUF_ERROR);
if (zret != Z_OK) {
@@ -2527,7 +2732,7 @@
switch( result ) {
case CKYISO_SUCCESS:
break;
- case 6981:
+ case 0x6981:
throw PKCS11Exception(CKR_PIN_LOCKED);
default:
if ((result & 0xff00) == 0x6300) {
@@ -3206,6 +3411,10 @@
status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
input, NULL, output, getNonce(), &result);
}
+ /* map the ISO not logged in code to the coolkey one */
+ if (status == CKYISO_CONDITION_NOT_SATISFIED) {
+ status = (CKYStatus) CKYISO_UNAUTHORIZED;
+ }
if (status != CKYSUCCESS) {
if ( status == CKYSCARDERR ) {
handleConnectionError();
Index: slot.h
===================================================================
RCS file: /cvs/dirsec/coolkey/src/coolkey/slot.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- slot.h 19 Feb 2009 02:04:13 -0000 1.3
+++ slot.h 8 Sep 2010 20:14:41 -0000 1.4
@@ -294,6 +294,7 @@
const CKYBuffer *paddedOutput) const = 0;
};
+#define MAX_CERT_SLOTS 3
class Slot {
public:
@@ -328,6 +329,8 @@
CKYBuffer nonce;
CKYBuffer cardATR;
CKYBuffer mCUID;
+ CKYBuffer cardAID[MAX_CERT_SLOTS];
+ unsigned short cardEF[MAX_CERT_SLOTS];
bool isVersion1Key;
bool needLogin;
long publicFree;
@@ -335,6 +338,7 @@
long privateFree;
bool fullTokenName;
bool mCoolkey;
+ bool mOldCAC;
//enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 };
@@ -398,6 +402,11 @@
list<ListObjectInfo> fetchCombinedObjects(const CKYBuffer *header);
list<ListObjectInfo> fetchSeparateObjects();
+ CKYStatus getCACAid();
+ CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize,
+ bool throwException);
+ CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize);
+
void selectApplet();
void selectCACApplet(CKYByte instance);
void unloadObjects();