diff --git a/SOURCES/coolkey-1.1.0-rhel7-alt-cac.patch b/SOURCES/coolkey-1.1.0-rhel7-alt-cac.patch new file mode 100644 index 0000000..f352f42 --- /dev/null +++ b/SOURCES/coolkey-1.1.0-rhel7-alt-cac.patch @@ -0,0 +1,858 @@ +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 { diff --git a/SPECS/coolkey.spec b/SPECS/coolkey.spec index ee4cc82..173d287 100644 --- a/SPECS/coolkey.spec +++ b/SPECS/coolkey.spec @@ -22,7 +22,7 @@ Name: coolkey Version: 1.1.0 -Release: 35%{?dist} +Release: 36%{?dist} Summary: CoolKey PKCS #11 module License: LGPLv2 URL: http://directory.fedora.redhat.com/wiki/CoolKey @@ -45,6 +45,8 @@ Patch23: coolkey-1.1.0-p15-coverity.patch Patch24: coolkey-1.1.0-more-keys.patch Patch25: coolkey-1.1.0-fail-on-bad-mechanisms.patch Patch26: coolkey-1.1.0-max-cpu-bug.patch +Patch27: coolkey-1.1.0-rhel7-alt-cac.patch + Group: System Environment/Libraries BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -92,6 +94,7 @@ Linux Driver support to access the CoolKey applet. %patch24 -b .more-keys %patch25 -b .fail-on-bad-mechanisms %patch26 -b .max-cpu-bug +%patch27 -b .alt-cac %build autoconf @@ -150,6 +153,9 @@ fi %changelog +* Thu Dec 1 2016 Robert Relyea - 1.1.0-36 +- recognize up to 10 cac and PIV certs rather than 3 + * Thu Jun 30 2016 Robert Relyea - 1.1.0-35 - include sleep on unknown reader errors.