diff -up ./src/coolkey/coolkey.cpp.alt-cac ./src/coolkey/coolkey.cpp --- ./src/coolkey/coolkey.cpp.alt-cac 2016-12-01 15:37:49.106167768 -0800 +++ ./src/coolkey/coolkey.cpp 2016-12-01 15:37:49.113167892 -0800 @@ -80,9 +80,16 @@ ecMechanismList[] = { {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } }; +static const MechInfo +allMechanismList[] = { + {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }, + {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, + {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } +}; unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo); unsigned int numECMechanisms = sizeof(ecMechanismList)/sizeof(MechInfo); +unsigned int numAllMechanisms = sizeof(allMechanismList)/sizeof(MechInfo); /* ------------------------------------------------------------ */ @@ -382,13 +389,22 @@ C_GetMechanismList(CK_SLOT_ID slotID, CK return CKR_TOKEN_NOT_PRESENT; } - if ( slot->getIsECC()) { + switch (slot->getAlgs()) { + case ALG_ECC|ALG_RSA: + mechanismList = allMechanismList; + numMechanisms = numAllMechanisms; + break; + case ALG_ECC: mechanismList = ecMechanismList; numMechanisms = numECMechanisms; - } else { + break; + case ALG_NONE: + case ALG_RSA: + default: mechanismList = rsaMechanismList; numMechanisms = numRSAMechanisms; - } + break; + } if( pMechanismList != NULL ) { if( *pulCount < numMechanisms ) { @@ -438,13 +454,22 @@ C_GetMechanismInfo(CK_SLOT_ID slotID, CK return CKR_TOKEN_NOT_PRESENT; } - if ( slot->getIsECC()) { + switch (slot->getAlgs()) { + case ALG_ECC|ALG_RSA: + mechanismList = allMechanismList; + numMechanisms = numAllMechanisms; + break; + case ALG_ECC: mechanismList = ecMechanismList; numMechanisms = numECMechanisms; - } else { + break; + case ALG_NONE: + case ALG_RSA: + default: mechanismList = rsaMechanismList; numMechanisms = numRSAMechanisms; - } + break; + } for(unsigned int i=0; i < numMechanisms; ++i ) { if( mechanismList[i].mech == type ) { diff -up ./src/coolkey/object.cpp.alt-cac ./src/coolkey/object.cpp --- ./src/coolkey/object.cpp.alt-cac 2016-12-01 15:37:49.097167608 -0800 +++ ./src/coolkey/object.cpp 2016-12-01 15:37:49.114167910 -0800 @@ -1232,7 +1232,7 @@ Reader::Reader(unsigned long muscleObjID } -CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : +CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16, instance | 0x400) { @@ -1242,7 +1242,9 @@ CACPrivKey::CACPrivKey(CKYByte instance, /* So we know what the key is supposed to be used for based on * the instance */ - if (instance == 2) { + /* instance 2 is usually a decryption cert. >2 are usually old decryption + * certs */ + if (instance == 2 || (instance > (isPIV ? 3 : 2))) { decrypt = TRUE; } @@ -1305,8 +1307,8 @@ CACPrivKey::CACPrivKey(CKYByte instance, CKYBuffer_FreeData(¶m2); } -CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : - PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16, +CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : + PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16, instance | 0x500) { CKYBuffer id; @@ -1315,7 +1317,7 @@ CACPubKey::CACPubKey(CKYByte instance, c /* So we know what the key is supposed to be used for based on * the instance */ - if (instance == 2) { + if (instance == 2 || (instance > (isPIV ? 3 : 2))) { encrypt = TRUE; } @@ -1359,6 +1361,9 @@ CACPubKey::CACPubKey(CKYByte instance, c setAttribute(CKA_EC_POINT, ¶m1); setAttribute(CKA_EC_PARAMS, ¶m2); setAttributeULong(CKA_KEY_TYPE, CKK_EC); + setAttributeBool(CKA_VERIFY_RECOVER, FALSE); + setAttributeBool(CKA_ENCRYPT, FALSE); + setAttributeBool(CKA_DERIVE, encrypt); break; default: break; @@ -1376,6 +1381,26 @@ static const char *CAC_Label[] = { "CAC ID Certificate", "CAC Email Signature Certificate", "CAC Email Encryption Certificate", + "CAC Cert 3", + "CAC Cert 4", + "CAC Cert 5", + "CAC Cert 6", + "CAC Cert 7", + "CAC Cert 8", + "CAC Cert 9", +}; + +static const char *PIV_Label[] = { + "PIV ID Certificate", + "PIV Email Signature Certificate", + "PIV Email Encryption Certificate", + "PIV Card Authentication Certificate", + "PIV Cert 4", + "PIV Cert 5", + "PIV Cert 6", + "PIV Cert 7", + "PIV Cert 8", + "PIV Cert 9", }; static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 }; @@ -1454,7 +1479,7 @@ GetUserName(const CKYBuffer *dn) return string; } -CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : +CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, instance | 0x600) { @@ -1471,7 +1496,7 @@ CACCert::CACCert(CKYByte instance, const setAttribute(CKA_ID, &id); CKYBuffer_FreeData(&id); setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509); - setAttribute(CKA_LABEL, CAC_Label[instance]); + setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]); CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial); CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject); diff -up ./src/coolkey/object.h.alt-cac ./src/coolkey/object.h --- ./src/coolkey/object.h.alt-cac 2016-12-01 15:37:49.087167430 -0800 +++ ./src/coolkey/object.h 2016-12-01 15:37:49.115167928 -0800 @@ -219,17 +219,17 @@ class Cert : public PKCS11Object { class CACPrivKey : public PKCS11Object { public: - CACPrivKey(CKYByte instance, const PKCS11Object &cert); + CACPrivKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); }; class CACPubKey : public PKCS11Object { public: - CACPubKey(CKYByte instance, const PKCS11Object &cert); + CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); }; class CACCert : public PKCS11Object { public: - CACCert(CKYByte instance, const CKYBuffer *derCert); + CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV); }; typedef enum { PK15StateInit, PK15StateNeedObject, diff -up ./src/coolkey/slot.cpp.alt-cac ./src/coolkey/slot.cpp --- ./src/coolkey/slot.cpp.alt-cac 2016-12-01 15:37:49.110167839 -0800 +++ ./src/coolkey/slot.cpp 2016-12-01 15:57:37.307994776 -0800 @@ -415,8 +415,9 @@ Slot::Slot(const char *readerName_, Log slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), isVersion1Key(false), needLogin(false), fullTokenName(false), mCoolkey(false), mOldCAC(false), mCACLocalLogin(false), - pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0), - p15tokenInfoAddr(0), p15Instance(0), + pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS), + algs(ALG_NONE), p15aid(0), p15odfAddr(0), p15tokenInfoAddr(0), + p15Instance(0), #ifdef USE_SHMEM shmem(readerName_), #endif @@ -776,6 +777,7 @@ Slot::connectToToken() state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; isVersion1Key = 0; needLogin = true; + maxCacCerts = MAX_CERT_SLOTS; mCoolkey = 0; mOldCAC = 0; mCACLocalLogin = getPIVLoginType(); @@ -927,8 +929,12 @@ Slot::getCACAid() } /* yes, fill in the old applets */ mOldCAC = true; + maxCacCerts = 1; for (i=1; i< MAX_CERT_SLOTS; i++) { - CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); + status = CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); + if (status == CKYSUCCESS) { + maxCacCerts = i+1; + } } return CKYSUCCESS; } @@ -986,6 +992,7 @@ Slot::getCACAid() if (certSlot == 0) { status = CKYAPDUFAIL; /* probably neeed a beter error code */ } + maxCacCerts = certSlot; done: CKYBuffer_FreeData(&tBuf); @@ -2168,12 +2175,11 @@ Slot::addKeyObject(list& o } keyObj.completeKey(*iter); - /* For now this is how we determine what type of key. - Also for now, allow only one or the other */ + /* use key object to determine what algorithms we support */ if ( keyObj.getKeyType() == PKCS11Object::ecc) { - mECC = true; + algs = (SlotAlgs) (algs | ALG_ECC); } else { - mECC = false; + algs = (SlotAlgs) (algs | ALG_RSA); } } @@ -2205,7 +2211,7 @@ Slot::addCertObject(list& void Slot::unloadObjects() { - mECC = false; + algs = ALG_NONE; tokenObjects.clear(); free(personName); personName = NULL; @@ -2269,29 +2275,42 @@ Slot::unloadObjects() // Shared memory segments are fixed size (equal to the object memory size of // the token). // +// +// + +struct SlotDataPair { + unsigned long dataOffset; + unsigned long dataSize; +}; struct SlotSegmentHeader { unsigned short version; unsigned short headerSize; unsigned char valid; - unsigned char reserved; + unsigned char firstCacCert; unsigned char cuid[10]; - unsigned short reserved2; + + unsigned short reserved; unsigned short dataVersion; unsigned short dataHeaderOffset; unsigned short dataOffset; unsigned long dataHeaderSize; unsigned long dataSize; - unsigned long cert2Offset; - unsigned long cert2Size; + unsigned long nextDataOffset; + SlotDataPair cacCerts[MAX_CERT_SLOTS]; }; +const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */ +const unsigned short CAC_DATA_VERSION=2; + + #define MAX_OBJECT_STORE_SIZE 15000 // // previous development versions used a segment prefix of // "coolkeypk11s" // -#define SEGMENT_PREFIX "coolkeypk11s" +#define SEGMENT_PREFIX "coolkeypk11t" // update segment since the old cache was + // incompatible #define CAC_FAKE_CUID "CAC Certs" SlotMemSegment::SlotMemSegment(const char *readerName): segmentAddr(NULL), segmentSize(0), segment(NULL) @@ -2320,9 +2339,8 @@ SlotMemSegment::SlotMemSegment(const cha return; } - SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; if (needInit) { - segmentHeader->valid = 0; + clearValid(0); } segmentSize = segment->getSHMemSize(); } @@ -2396,6 +2414,18 @@ SlotMemSegment::getDataVersion() const return segmentHeader->dataVersion; } +unsigned char +SlotMemSegment::getFirstCacCert() const +{ + if (!segment) { + return NOT_A_CAC; + } + + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + + return segmentHeader->firstCacCert; +} + void SlotMemSegment::setVersion(unsigned short version) { @@ -2419,6 +2449,18 @@ SlotMemSegment::setDataVersion(unsigned segmentHeader->dataVersion = version; } +void +SlotMemSegment::setFirstCacCert(unsigned char firstCacCert) +{ + if (!segment) { + return; + } + + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + + segmentHeader->firstCacCert = firstCacCert; +} + bool SlotMemSegment::isValid() const { @@ -2493,23 +2535,13 @@ SlotMemSegment::readCACCert(CKYBuffer *o int size; CKYByte *data; - switch (instance) { - case 0: - data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; - size = segmentHeader->dataHeaderSize; - break; - case 1: - data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; - size = segmentHeader->dataSize; - break; - case 2: - data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; - size = segmentHeader->cert2Size; - break; - default: + if (instance >= MAX_CERT_SLOTS) { CKYBuffer_Resize(objData, 0); return; } + data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance] + .dataOffset]; + size = segmentHeader->cacCerts[instance].dataSize; CKYBuffer_Replace(objData, 0, data, size); } @@ -2523,30 +2555,20 @@ SlotMemSegment::writeCACCert(const CKYBu SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; int size = CKYBuffer_Size(data); CKYByte *shmData; - switch (instance) { - case 0: - segmentHeader->headerSize = sizeof *segmentHeader; - segmentHeader->dataHeaderOffset = sizeof *segmentHeader; - segmentHeader->dataHeaderSize = size; - segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size; - segmentHeader->dataSize = 0; - segmentHeader->cert2Offset = segmentHeader->dataOffset; - segmentHeader->cert2Size = 0; - shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; - break; - case 1: - segmentHeader->dataSize = size; - segmentHeader->cert2Offset = segmentHeader->dataOffset + size; - segmentHeader->cert2Size = 0; - shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; - break; - case 2: - segmentHeader->cert2Size = size; - shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; - break; - default: + + if (instance >= MAX_CERT_SLOTS) { return; } + + if (segmentHeader->firstCacCert == NOT_A_CAC) { + segmentHeader->firstCacCert = instance; + } + unsigned long dataOffset = segmentHeader->nextDataOffset; + segmentHeader->cacCerts[instance].dataOffset = dataOffset; + segmentHeader->nextDataOffset += size; + segmentHeader->cacCerts[instance].dataSize = size; + shmData = (CKYByte *) &segmentAddr[dataOffset]; + memcpy(shmData, CKYBuffer_Data(data), size); } @@ -2558,15 +2580,18 @@ SlotMemSegment::clearValid(CKYByte insta return; } SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; - switch (instance) { - case 0: - segmentHeader->headerSize = 0; - segmentHeader->dataHeaderSize = 0; - /* fall through */ - case 1: - segmentHeader->dataSize = 0; + + segmentHeader->headerSize = sizeof *segmentHeader; + segmentHeader->dataHeaderOffset = sizeof *segmentHeader; + segmentHeader->dataHeaderSize = 0; + segmentHeader->dataSize = 0; + for (int i=0; i < MAX_CERT_SLOTS; i++) { + segmentHeader->cacCerts[i].dataSize = 0; } + segmentHeader->dataOffset = sizeof *segmentHeader; + segmentHeader->nextDataOffset = sizeof *segmentHeader; segmentHeader->valid = 0; + segmentHeader->firstCacCert = NOT_A_CAC; } void @@ -2882,8 +2907,7 @@ berProcess(CKYBuffer *buf, int matchTag, CKYStatus -Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, - bool throwException) +Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize) { CKYStatus status; CKYISOStatus apduRC; @@ -2897,9 +2921,6 @@ Slot::readCACCertificateFirst(CKYBuffer CKYBuffer_InitEmpty(&certInfo); CKYBuffer_Resize(cert, 0); status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC); - if (throwException && (status != CKYSUCCESS)) { - handleConnectionError(); - } /* actually, on success, we need to parse the certificate and find the * propper tag */ if (status == CKYSUCCESS) { @@ -2940,10 +2961,10 @@ Slot::readCACCertificateFirst(CKYBuffer if (mOldCAC) { /* get the first 100 bytes of the cert */ status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); - if (throwException && (status != CKYSUCCESS)) { - handleConnectionError(); + if (status == CKYSUCCESS) { + return status; } - return status; + /* try to use CACApplet_ReadFile before we give up */ } CKYBuffer tBuf; @@ -2959,11 +2980,11 @@ Slot::readCACCertificateFirst(CKYBuffer /* handle the new CAC card read */ /* read the TLV */ - status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); + status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, &apduRC); if (status != CKYSUCCESS) { goto done; } - status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); + status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, &apduRC); if (status != CKYSUCCESS) { goto done; } @@ -3199,14 +3220,12 @@ Slot::loadCACCert(CKYByte instance) CKYStatus status = CKYSUCCESS; CKYBuffer cert; CKYBuffer rawCert; - CKYBuffer shmCert; CKYSize nextSize; OSTime time = OSTimeNow(); CKYBuffer_InitEmpty(&cert); CKYBuffer_InitEmpty(&rawCert); - CKYBuffer_InitEmpty(&shmCert); // // not all CAC cards have all the PKI instances @@ -3215,78 +3234,24 @@ Slot::loadCACCert(CKYByte instance) try { selectCACApplet(instance, false); } catch(PKCS11Exception& e) { - // all CAC's must have instance '0', throw the error it - // they don't. - if (instance == 0) throw e; - // If the CAC doesn't have instance '2', and we were updating - // the shared memory, set it to valid now. - if ((instance == 2) && !shmem.isValid()) { - shmem.setValid(); - } return; } log->log("CAC Cert %d: select CAC applet: %d ms\n", instance, OSTimeNow() - time); - if (instance == 0) { - readCACCertificateFirst(&rawCert, &nextSize, true); - - if(CKYBuffer_Size(&rawCert) <= 1) { - handleConnectionError(); - } - log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", - instance, OSTimeNow() - time); - } - - unsigned short dataVersion = 1; - CKYBool needRead = 1; - /* see if it matches the shared memory */ - if (shmem.isValid() && shmem.getDataVersion() == dataVersion) { - shmem.readCACCert(&shmCert, instance); - CKYSize certSize = CKYBuffer_Size(&rawCert); - CKYSize shmCertSize = CKYBuffer_Size(&shmCert); - const CKYByte *shmData = CKYBuffer_Data(&shmCert); - - if (instance != 0) { - needRead = 0; - } - - if (shmCertSize >= certSize) { - if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { - /* yes it does, no need to read the rest of the cert, use - * the cache */ - CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize); - needRead = 0; - } - } - if (!needRead && (shmCertSize == 0)) { + if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION) { + shmem.readCACCert(&rawCert, instance); + if (CKYBuffer_Size(&rawCert) == 0) { /* no cert of this type, just return */ return; } - } - CKYBuffer_FreeData(&shmCert); - - if (needRead) { - /* it doesn't, read the new cert and update the cache */ - if (instance == 0) { - shmem.clearValid(0); - shmem.setVersion(SHMEM_VERSION); - shmem.setDataVersion(dataVersion); - } else { - status = readCACCertificateFirst(&rawCert, &nextSize, false); - - if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { - /* CAC only requires the Certificate in pki '0' */ - /* if pki '1' or '2' are empty, treat it as a non-fatal error*/ - if (instance == 2) { - /* we've attempted to read all the certs, shared memory - * is now valid */ - shmem.setValid(); - } - return; - } + } else { + status = readCACCertificateFirst(&rawCert, &nextSize); + if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { + /*this cert doesn't exist, go to the next one */ + return; } if (nextSize) { @@ -3298,9 +3263,6 @@ Slot::loadCACCert(CKYByte instance) handleConnectionError(); } shmem.writeCACCert(&rawCert, instance); - if (instance == 2) { - shmem.setValid(); - } } @@ -3368,14 +3330,17 @@ Slot::loadCACCert(CKYByte instance) log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n", instance, OSTimeNow() - time); - CACCert certObj(instance, &cert); - CACPrivKey privKey(instance, certObj); - CACPubKey pubKey(instance, certObj); + bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD); + CACCert certObj(instance, &cert, isPIV); + CACPrivKey privKey(instance, certObj, isPIV); + CACPubKey pubKey(instance, certObj, isPIV); tokenObjects.push_back(privKey); tokenObjects.push_back(pubKey); tokenObjects.push_back(certObj); if ( pubKey.getKeyType() == PKCS11Object::ecc) { - mECC = 1; + algs = (SlotAlgs) (algs | ALG_ECC); + } else { + algs = (SlotAlgs) (algs | ALG_RSA); } if (personName == NULL) { @@ -3388,6 +3353,94 @@ Slot::loadCACCert(CKYByte instance) } void +Slot::initCACShMem(void) +{ + bool failed = false; + + unsigned char firstCert = shmem.getFirstCacCert(); + + log->log("init CACShMem: \n"); + /* check to make sure the shared memory is initialized with a CAC card */ + if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION + && firstCert != NOT_A_CAC) { + CKYBuffer rawCert; + CKYBuffer shmCert; + CKYSize nextSize; + + log->log("init CACShMem: valid CAC cache found firstCert = %d\n", + firstCert); + CKYBuffer_InitEmpty(&rawCert); + CKYBuffer_InitEmpty(&shmCert); + + + /* yes, see if it's this cac card by comparing the first cert + * in the chain */ + + /* see if the first cert is in the expected slot */ + try { + selectCACApplet(firstCert, false); + } catch(PKCS11Exception& e) { + failed = true; + log->log("init CACShMem: applet select failed firstCert = %d\n", + firstCert); + } + if (!failed) { + CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize); + if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) { + failed = true; + log->log("init CACShMem: read Cert failed firstCert = %d\n", + firstCert); + } + } + if (!failed) { + shmem.readCACCert(&shmCert, firstCert); + CKYSize certSize = CKYBuffer_Size(&rawCert); + CKYSize shmCertSize = CKYBuffer_Size(&shmCert); + const CKYByte *shmData = CKYBuffer_Data(&shmCert); + + if (shmCertSize >= certSize) { + if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { + /* this card is cached, go on and use the cache */ + log->log("init CACShMem: entries match, using cache\n"); + CKYBuffer_FreeData(&rawCert); + CKYBuffer_FreeData(&shmCert); + return; + } + } + log->log("init CACShMem: no entry match certSize=%d" + " shmCertSize=%d\n",certSize, shmCertSize); + } + CKYBuffer_FreeData(&rawCert); + CKYBuffer_FreeData(&shmCert); + } + + log->log("init CACShMem: starting new cache valid=%d version=%d " + " firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(), + firstCert); + /* cache is either invalid or for another card, start initializing it */ + shmem.clearValid(0); + shmem.setVersion(SHMEM_VERSION); + shmem.setDataVersion(CAC_DATA_VERSION); +} + +void +Slot::verifyCACShMem(void) +{ + /* if the memory is valid, then nothing to do */ + if (shmem.isValid()) { + return; + } + /* if we didn't find any cert fail */ + if (shmem.getFirstCacCert() == NOT_A_CAC) { + shmem.clearValid(0); + disconnect(); + throw PKCS11Exception(CKR_DEVICE_REMOVED); + } + /* we're all set, let others see our results */ + shmem.setValid(); +} + +void Slot::loadObjects() { // throw away all token objects! @@ -3406,9 +3459,11 @@ Slot::loadObjects() std::list::iterator iter; if (state & GOV_CARD) { - loadCACCert(0); - loadCACCert(1); - loadCACCert(2); + initCACShMem(); + for (int i=0; i < maxCacCerts; i++) { + loadCACCert(i); + } + verifyCACShMem(); status = trans.end(); loadReaderObject(); return; @@ -4720,10 +4775,6 @@ Slot::performECCSignature(CKYBuffer *out CKYStatus status = trans.begin(conn); if( status != CKYSUCCESS ) handleConnectionError(); - if (!mECC) { - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); - } - CKYISOStatus result; bool loginAttempted = false; @@ -4790,9 +4841,6 @@ Slot::performRSAOp(CKYBuffer *output, co unsigned int keySize, const PKCS11Object *key, CKYByte direction) { - if ( mECC ) { - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); - } // // establish a transaction @@ -5145,10 +5193,6 @@ Slot::performECCKeyAgreement(CK_MECHANIS CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, const PKCS11Object *key, unsigned int keySize) { - if (!mECC) { - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); - } - Transaction trans; CKYStatus status = trans.begin(conn); if( status != CKYSUCCESS ) handleConnectionError(); diff -up ./src/coolkey/slot.h.alt-cac ./src/coolkey/slot.h --- ./src/coolkey/slot.h.alt-cac 2016-12-01 15:37:49.104167732 -0800 +++ ./src/coolkey/slot.h 2016-12-01 15:37:49.117167964 -0800 @@ -79,9 +79,11 @@ public: bool CUIDIsEqual(const CKYBuffer *cuid) const; unsigned short getVersion() const; unsigned short getDataVersion() const; + unsigned char getFirstCacCert() const; void setCUID(const CKYBuffer *cuid); void setVersion(unsigned short version); void setDataVersion(unsigned short version); + void setFirstCacCert(unsigned char firstCacCert); bool isValid() const; int size() const; const unsigned char *getCUID() const; @@ -90,6 +92,7 @@ public: void setSize(int size); void readData(CKYBuffer *data) const; void writeData(const CKYBuffer *data); + void initCACHeaders(void); void readCACCert(CKYBuffer *data, CKYByte instance) const; void writeCACCert(const CKYBuffer *data, CKYByte instance); void clearValid(CKYByte instance); @@ -294,7 +297,13 @@ class CryptParams { const CKYBuffer *paddedOutput) const = 0; }; -#define MAX_CERT_SLOTS 3 +#define MAX_CERT_SLOTS 10 +typedef enum { + ALG_NONE= 0x0, + ALG_ECC = 0x1, + ALG_RSA = 0x2 +} SlotAlgs; + #define MAX_AUTH_USERS 3 class Slot { @@ -349,7 +358,8 @@ class Slot { bool mCACLocalLogin; int pivContainer; int pivKey; - bool mECC; + int maxCacCerts; + SlotAlgs algs; unsigned short p15aid; unsigned short p15odfAddr; unsigned short p15tokenInfoAddr; @@ -424,8 +434,7 @@ class Slot { list fetchSeparateObjects(); CKYStatus getCACAid(); - CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, - bool throwException); + CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize); CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); CKYStatus getP15Params(); @@ -485,6 +494,8 @@ class Slot { void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu); CKYByte objectToKeyNum(const PKCS11Object *key); + void initCACShMem(void); + void verifyCACShMem(void); Slot(const Slot &cpy) #ifdef USE_SHMEM : shmem(readerName) @@ -580,7 +591,7 @@ class Slot { CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params); - bool getIsECC() { return mECC; } + SlotAlgs getAlgs() { return algs; } }; class SlotList {