859 lines
27 KiB
Diff
859 lines
27 KiB
Diff
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<PKCS11Object>& 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<PKCS11Object>&
|
|
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<ListObjectInfo>::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<ListObjectInfo> 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 {
|