4793 lines
151 KiB
Diff
4793 lines
151 KiB
Diff
|
diff -up ./src/coolkey/coolkey.cpp.piv-ecc ./src/coolkey/coolkey.cpp
|
||
|
--- ./src/coolkey/coolkey.cpp.piv-ecc 2013-09-08 15:50:33.085428102 -0700
|
||
|
+++ ./src/coolkey/coolkey.cpp 2013-09-08 15:50:33.119428673 -0700
|
||
|
@@ -34,7 +34,6 @@
|
||
|
#include "cky_base.h"
|
||
|
#include "params.h"
|
||
|
|
||
|
-#define NULL 0
|
||
|
|
||
|
/* static module data -------------------------------- */
|
||
|
|
||
|
@@ -70,11 +69,19 @@ typedef struct {
|
||
|
/**********************************************************************
|
||
|
************************** MECHANISM TABLE ***************************
|
||
|
**********************************************************************/
|
||
|
-static MechInfo
|
||
|
-mechanismList[] = {
|
||
|
+
|
||
|
+static const MechInfo
|
||
|
+rsaMechanismList[] = {
|
||
|
{CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }
|
||
|
};
|
||
|
-static unsigned int numMechanisms = sizeof(mechanismList)/sizeof(MechInfo);
|
||
|
+
|
||
|
+static const MechInfo
|
||
|
+ecMechanismList[] = {
|
||
|
+ {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}},{ CKM_ECDSA_SHA1, {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);
|
||
|
|
||
|
/* ------------------------------------------------------------ */
|
||
|
|
||
|
@@ -166,7 +173,6 @@ NOTSUPPORTED(C_GenerateKey, (CK_SESSION_
|
||
|
NOTSUPPORTED(C_GenerateKeyPair, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_ATTRIBUTE_PTR,CK_ULONG,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR,CK_OBJECT_HANDLE_PTR))
|
||
|
NOTSUPPORTED(C_WrapKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_OBJECT_HANDLE,CK_BYTE_PTR,CK_ULONG_PTR))
|
||
|
NOTSUPPORTED(C_UnwrapKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_BYTE_PTR,CK_ULONG,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR))
|
||
|
-NOTSUPPORTED(C_DeriveKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR))
|
||
|
NOTSUPPORTED(C_GetFunctionStatus, (CK_SESSION_HANDLE))
|
||
|
NOTSUPPORTED(C_CancelFunction, (CK_SESSION_HANDLE))
|
||
|
|
||
|
@@ -200,6 +206,10 @@ SUPPORTED(C_SeedRandom, seedRandom,
|
||
|
SUPPORTED(C_GenerateRandom, generateRandom,
|
||
|
(CK_SESSION_HANDLE hSession ,CK_BYTE_PTR data,CK_ULONG dataLen),
|
||
|
(hSession, data, dataLen))
|
||
|
+SUPPORTED(C_DeriveKey,derive,
|
||
|
+ (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey ),
|
||
|
+ (hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey))
|
||
|
|
||
|
/* non-specialized functions supported with the slot directly */
|
||
|
|
||
|
@@ -249,7 +259,7 @@ C_Initialize(CK_VOID_PTR pInitArgs)
|
||
|
log = new DummyLog();
|
||
|
}
|
||
|
log->log("Initialize called, hello %d\n", 5);
|
||
|
- CKY_SetName("coolkey");
|
||
|
+ CKY_SetName((char *) "coolkey");
|
||
|
slotList = new SlotList(log);
|
||
|
initialized = TRUE;
|
||
|
return CKR_OK;
|
||
|
@@ -347,6 +357,11 @@ CK_RV
|
||
|
C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
|
||
|
CK_ULONG_PTR pulCount)
|
||
|
{
|
||
|
+
|
||
|
+ const MechInfo *mechanismList = NULL;
|
||
|
+ unsigned int numMechanisms = 0;
|
||
|
+
|
||
|
+
|
||
|
if( ! initialized ) {
|
||
|
return CKR_CRYPTOKI_NOT_INITIALIZED;
|
||
|
}
|
||
|
@@ -359,11 +374,21 @@ C_GetMechanismList(CK_SLOT_ID slotID, CK
|
||
|
}
|
||
|
|
||
|
slotList->validateSlotID(slotID);
|
||
|
- if( ! slotList->getSlot(
|
||
|
- slotIDToIndex(slotID))->isTokenPresent() ) {
|
||
|
+
|
||
|
+ Slot *slot = slotList->getSlot(slotIDToIndex(slotID));
|
||
|
+
|
||
|
+ if( ! slot || ! slot->isTokenPresent() ) {
|
||
|
return CKR_TOKEN_NOT_PRESENT;
|
||
|
}
|
||
|
|
||
|
+ if ( slot->getIsECC()) {
|
||
|
+ mechanismList = ecMechanismList;
|
||
|
+ numMechanisms = numECMechanisms;
|
||
|
+ } else {
|
||
|
+ mechanismList = rsaMechanismList;
|
||
|
+ numMechanisms = numRSAMechanisms;
|
||
|
+ }
|
||
|
+
|
||
|
if( pMechanismList != NULL ) {
|
||
|
if( *pulCount < numMechanisms ) {
|
||
|
rv = CKR_BUFFER_TOO_SMALL;
|
||
|
@@ -390,19 +415,36 @@ CK_RV
|
||
|
C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
|
||
|
CK_MECHANISM_INFO_PTR pInfo)
|
||
|
{
|
||
|
+ const MechInfo *mechanismList = NULL;
|
||
|
+ unsigned int numMechanisms = 0;
|
||
|
+
|
||
|
if( ! initialized ) {
|
||
|
return CKR_CRYPTOKI_NOT_INITIALIZED;
|
||
|
}
|
||
|
+
|
||
|
+
|
||
|
try {
|
||
|
log->log("C_GetMechanismInfo called\n");
|
||
|
if( pInfo == NULL ) {
|
||
|
throw PKCS11Exception(CKR_ARGUMENTS_BAD);
|
||
|
}
|
||
|
slotList->validateSlotID(slotID);
|
||
|
- if( ! slotList->getSlot(slotIDToIndex(slotID))->isTokenPresent() ) {
|
||
|
+
|
||
|
+
|
||
|
+ Slot *slot = slotList->getSlot(slotIDToIndex(slotID));
|
||
|
+
|
||
|
+ if( ! slot || ! slot->isTokenPresent() ) {
|
||
|
return CKR_TOKEN_NOT_PRESENT;
|
||
|
}
|
||
|
|
||
|
+ if ( slot->getIsECC()) {
|
||
|
+ mechanismList = ecMechanismList;
|
||
|
+ numMechanisms = numECMechanisms;
|
||
|
+ } else {
|
||
|
+ mechanismList = rsaMechanismList;
|
||
|
+ numMechanisms = numRSAMechanisms;
|
||
|
+ }
|
||
|
+
|
||
|
for(unsigned int i=0; i < numMechanisms; ++i ) {
|
||
|
if( mechanismList[i].mech == type ) {
|
||
|
*pInfo = mechanismList[i].info;
|
||
|
diff -up ./src/coolkey/machdep.cpp.piv-ecc ./src/coolkey/machdep.cpp
|
||
|
--- ./src/coolkey/machdep.cpp.piv-ecc 2013-09-08 15:50:33.085428102 -0700
|
||
|
+++ ./src/coolkey/machdep.cpp 2013-09-08 15:50:33.119428673 -0700
|
||
|
@@ -368,6 +368,7 @@ SHMem::initSegment(const char *name, int
|
||
|
#ifdef FULL_CLEANUP
|
||
|
flock(shmemData->fd, LOCK_UN);
|
||
|
#endif
|
||
|
+ free(buf);
|
||
|
delete shmemData;
|
||
|
return NULL;
|
||
|
}
|
||
|
diff -up ./src/coolkey/object.cpp.piv-ecc ./src/coolkey/object.cpp
|
||
|
--- ./src/coolkey/object.cpp.piv-ecc 2013-09-08 15:50:33.104428421 -0700
|
||
|
+++ ./src/coolkey/object.cpp 2013-09-08 15:50:33.121428706 -0700
|
||
|
@@ -25,12 +25,44 @@
|
||
|
|
||
|
using std::find_if;
|
||
|
|
||
|
+const CKYByte rsaOID[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D, 0x01, 0x01,0x1};
|
||
|
+const CKYByte eccOID[] = {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01};
|
||
|
+
|
||
|
+#ifdef DEBUG
|
||
|
+void dump(CKYBuffer *buf)
|
||
|
+{
|
||
|
+ CKYSize i;
|
||
|
+ CKYSize size = CKYBuffer_Size(buf);
|
||
|
+#define ROW_LENGTH 60
|
||
|
+ char string[ROW_LENGTH+1];
|
||
|
+ char *bp = &string[0];
|
||
|
+ CKYByte c;
|
||
|
+
|
||
|
+ for (i=0; i < size; i++) {
|
||
|
+ if (i && ((i % (ROW_LENGTH-1)) == 0) ) {
|
||
|
+ *bp = 0;
|
||
|
+ printf(" %s\n",string);
|
||
|
+ bp = &string[0];
|
||
|
+ }
|
||
|
+ c = CKYBuffer_GetChar(buf, i);
|
||
|
+ printf("%02x ",c);
|
||
|
+ *bp++ = (c < ' ') ? '.' : ((c & 0x80) ? '*' : c);
|
||
|
+ }
|
||
|
+ *bp = 0;
|
||
|
+ for (i= (i % (ROW_LENGTH-1)); i && (i < ROW_LENGTH); i++) {
|
||
|
+ printf(" ");
|
||
|
+ }
|
||
|
+ printf(" %s\n",string);
|
||
|
+ fflush(stdout);
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
|
||
|
bool AttributeMatch::operator()(const PKCS11Attribute& cmp)
|
||
|
{
|
||
|
return (attr->type == cmp.getType()) &&
|
||
|
- CKYBuffer_DataIsEqual(cmp.getValue(),
|
||
|
- (const CKYByte *)attr->pValue, attr->ulValueLen);
|
||
|
+ CKYBuffer_DataIsEqual(cmp.getValue(),
|
||
|
+ (const CKYByte *)attr->pValue, attr->ulValueLen);
|
||
|
}
|
||
|
|
||
|
class AttributeTypeMatch
|
||
|
@@ -45,14 +77,14 @@ class AttributeTypeMatch
|
||
|
};
|
||
|
|
||
|
PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_)
|
||
|
- : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL)
|
||
|
+ : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL), keyType(unknown)
|
||
|
{
|
||
|
CKYBuffer_InitEmpty(&pubKey);
|
||
|
}
|
||
|
|
||
|
PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data,
|
||
|
CK_OBJECT_HANDLE handle_) : muscleObjID(muscleObjID_), handle(handle_),
|
||
|
- label(NULL), name(NULL)
|
||
|
+ label(NULL), name(NULL), keyType(unknown)
|
||
|
{
|
||
|
CKYBuffer_InitEmpty(&pubKey);
|
||
|
|
||
|
@@ -63,9 +95,98 @@ PKCS11Object::PKCS11Object(unsigned long
|
||
|
"PKCS #11 actual object id does not match stated id");
|
||
|
}
|
||
|
if (type == 0) {
|
||
|
- parseOldObject(data);
|
||
|
+ parseOldObject(data);
|
||
|
} else if (type == 1) {
|
||
|
- parseNewObject(data);
|
||
|
+ parseNewObject(data);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+SecretKey::SecretKey(unsigned long muscleObjID_, CK_OBJECT_HANDLE handle_, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
|
||
|
+ : PKCS11Object(muscleObjID_, handle_)
|
||
|
+{
|
||
|
+ static CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
|
||
|
+ static CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
||
|
+ static CK_BBOOL value = 0x1;
|
||
|
+
|
||
|
+ if ( secretKeyBuffer == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ /* Rifle through the input template */
|
||
|
+
|
||
|
+ CK_ATTRIBUTE_TYPE type;
|
||
|
+ CK_ATTRIBUTE attr;
|
||
|
+ CK_ULONG valueLength = 0;
|
||
|
+
|
||
|
+ for(int i = 0; i < (int) ulAttributeCount; i++) {
|
||
|
+ attr = pTemplate[i];
|
||
|
+ type = attr.type;
|
||
|
+
|
||
|
+ if ( type == CKA_VALUE_LEN) {
|
||
|
+ //CK_ULONG ulValueLen = attr.ulValueLen;
|
||
|
+ valueLength = *((CK_ULONG *)attr.pValue);
|
||
|
+ } else {
|
||
|
+
|
||
|
+ CKYBuffer val;
|
||
|
+ CKYBuffer_InitFromData(&val,(const CK_BYTE *) attr.pValue, attr.ulValueLen);
|
||
|
+ setAttribute( type, &val);
|
||
|
+ CKYBuffer_FreeData(&val);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ adjustToKeyValueLength( secretKeyBuffer, valueLength );
|
||
|
+
|
||
|
+ /* Fall backs. */
|
||
|
+
|
||
|
+ if(!attributeExists(CKA_CLASS))
|
||
|
+ setAttributeULong(CKA_CLASS, objClass);
|
||
|
+
|
||
|
+ if(!attributeExists(CKA_KEY_TYPE))
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, keyType);
|
||
|
+
|
||
|
+ if(!attributeExists(CKA_TOKEN))
|
||
|
+ setAttributeBool(CKA_TOKEN, value);
|
||
|
+
|
||
|
+ if(!attributeExists(CKA_DERIVE))
|
||
|
+ setAttributeBool(CKA_DERIVE, value);
|
||
|
+
|
||
|
+ /* Actual value */
|
||
|
+ setAttribute(CKA_VALUE, secretKeyBuffer);
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+void SecretKey::adjustToKeyValueLength(CKYBuffer * secretKeyBuffer,CK_ULONG valueLength)
|
||
|
+{
|
||
|
+ const CK_LONG MAX_DIFF = 200; /* Put some bounds on this value */
|
||
|
+
|
||
|
+ if ( !secretKeyBuffer ) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer scratch;
|
||
|
+ CK_ULONG actual_length = CKYBuffer_Size(secretKeyBuffer);
|
||
|
+
|
||
|
+ CK_LONG diff = 0;
|
||
|
+ diff = (CK_LONG) valueLength - actual_length;
|
||
|
+
|
||
|
+ if ( diff == 0 ) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( diff > 0 && diff < MAX_DIFF ) { /*check for silly values */
|
||
|
+ /* prepend with zeroes */
|
||
|
+ CKYBuffer_InitFromLen(&scratch, diff);
|
||
|
+ CKYBuffer_AppendCopy(&scratch, secretKeyBuffer);
|
||
|
+
|
||
|
+ CKYBuffer_FreeData(secretKeyBuffer);
|
||
|
+ CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
|
||
|
+ CKYBuffer_FreeData(&scratch);
|
||
|
+
|
||
|
+ } else if (diff < 0 ) {
|
||
|
+ /* truncate most significant bytes */
|
||
|
+ CKYBuffer_InitFromData(&scratch, CKYBuffer_Data(secretKeyBuffer)-diff, valueLength);
|
||
|
+ CKYBuffer_FreeData(secretKeyBuffer);
|
||
|
+ CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
|
||
|
+ CKYBuffer_FreeData(&scratch);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -95,29 +216,29 @@ PKCS11Object::parseOldObject(const CKYBu
|
||
|
attrib.setType(CKYBuffer_GetLong(data, idx));
|
||
|
idx += 4;
|
||
|
unsigned int attrLen = CKYBuffer_GetShort(data, idx);
|
||
|
- idx += 2;
|
||
|
+ idx += 2;
|
||
|
if( attrLen > CKYBuffer_Size(data)
|
||
|
- || (idx + attrLen > CKYBuffer_Size(data)) ) {
|
||
|
+ || (idx + attrLen > CKYBuffer_Size(data)) ) {
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
"Invalid attribute length %d\n", attrLen);
|
||
|
}
|
||
|
- /* these two types are ints, read them back from
|
||
|
- * the card in host order */
|
||
|
- if ((attrib.getType() == CKA_CLASS) ||
|
||
|
- (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
|
||
|
- (attrib.getType() == CKA_KEY_TYPE)) {
|
||
|
- /* ulongs are 4 bytes on the token, even if they are 8 or
|
||
|
- * more in the pkcs11 module */
|
||
|
- if (attrLen != 4) {
|
||
|
+ /* these two types are ints, read them back from
|
||
|
+ * the card in host order */
|
||
|
+ if ((attrib.getType() == CKA_CLASS) ||
|
||
|
+ (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
|
||
|
+ (attrib.getType() == CKA_KEY_TYPE)) {
|
||
|
+ /* ulongs are 4 bytes on the token, even if they are 8 or
|
||
|
+ * more in the pkcs11 module */
|
||
|
+ if (attrLen != 4) {
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
"Invalid attribute length %d\n", attrLen);
|
||
|
- }
|
||
|
- CK_ULONG value = makeLEUInt(data,idx);
|
||
|
+ }
|
||
|
+ CK_ULONG value = makeLEUInt(data,idx);
|
||
|
|
||
|
- attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
|
||
|
- } else {
|
||
|
- attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
|
||
|
- }
|
||
|
+ attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
|
||
|
+ } else {
|
||
|
+ attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
|
||
|
+ }
|
||
|
idx += attrLen;
|
||
|
attributes.push_back(attrib);
|
||
|
}
|
||
|
@@ -177,33 +298,33 @@ PKCS11Object::expandAttributes(unsigned
|
||
|
unsigned long i;
|
||
|
|
||
|
if (!attributeExists(CKA_ID)) {
|
||
|
- PKCS11Attribute attrib;
|
||
|
- attrib.setType(CKA_ID);
|
||
|
- attrib.setValue(&cka_id, 1);
|
||
|
+ PKCS11Attribute attrib;
|
||
|
+ attrib.setType(CKA_ID);
|
||
|
+ attrib.setValue(&cka_id, 1);
|
||
|
attributes.push_back(attrib);
|
||
|
}
|
||
|
/* unpack the class */
|
||
|
if (!attributeExists(CKA_CLASS)) {
|
||
|
- PKCS11Attribute attrib;
|
||
|
- attrib.setType(CKA_CLASS);
|
||
|
- attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
|
||
|
+ PKCS11Attribute attrib;
|
||
|
+ attrib.setType(CKA_CLASS);
|
||
|
+ attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
|
||
|
attributes.push_back(attrib);
|
||
|
}
|
||
|
|
||
|
/* unpack the boolean flags. Note, the default mask is based on
|
||
|
* the class specified in fixedAttrs, not on the real class */
|
||
|
for (i=1; i < sizeof(unsigned long)*8; i++) {
|
||
|
- unsigned long iMask = 1<< i;
|
||
|
- if ((mask & iMask) == 0) {
|
||
|
- continue;
|
||
|
- }
|
||
|
- if (attributeExists(boolType[i])) {
|
||
|
- continue;
|
||
|
- }
|
||
|
- PKCS11Attribute attrib;
|
||
|
- CKYByte bVal = (fixedAttrs & iMask) != 0;
|
||
|
- attrib.setType(boolType[i]);
|
||
|
- attrib.setValue(&bVal, 1);
|
||
|
+ unsigned long iMask = 1<< i;
|
||
|
+ if ((mask & iMask) == 0) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (attributeExists(boolType[i])) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ PKCS11Attribute attrib;
|
||
|
+ CKYByte bVal = (fixedAttrs & iMask) != 0;
|
||
|
+ attrib.setType(boolType[i]);
|
||
|
+ attrib.setValue(&bVal, 1);
|
||
|
attributes.push_back(attrib);
|
||
|
}
|
||
|
}
|
||
|
@@ -224,40 +345,40 @@ PKCS11Object::parseNewObject(const CKYBu
|
||
|
// load up the explicit attributes first
|
||
|
for (j=0, offset = 11; j < attributeCount && offset < size; j++) {
|
||
|
PKCS11Attribute attrib;
|
||
|
- CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
|
||
|
- unsigned int attrLen = 0;
|
||
|
+ CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
|
||
|
+ unsigned int attrLen = 0;
|
||
|
attrib.setType(CKYBuffer_GetLong(data, offset));
|
||
|
offset += 5;
|
||
|
|
||
|
- switch(attributeDataType) {
|
||
|
- case DATATYPE_STRING:
|
||
|
- attrLen = CKYBuffer_GetShort(data, offset);
|
||
|
- offset += 2;
|
||
|
+ switch(attributeDataType) {
|
||
|
+ case DATATYPE_STRING:
|
||
|
+ attrLen = CKYBuffer_GetShort(data, offset);
|
||
|
+ offset += 2;
|
||
|
if (attrLen > CKYBuffer_Size(data)
|
||
|
- || (offset + attrLen > CKYBuffer_Size(data)) ) {
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Invalid attribute length %d\n", attrLen);
|
||
|
+ || (offset + attrLen > CKYBuffer_Size(data)) ) {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Invalid attribute length %d\n", attrLen);
|
||
|
}
|
||
|
- attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
|
||
|
- break;
|
||
|
- case DATATYPE_BOOL_FALSE:
|
||
|
- case DATATYPE_BOOL_TRUE:
|
||
|
- {
|
||
|
- CKYByte bval = attributeDataType & 1;
|
||
|
- attrib.setValue(&bval, 1);
|
||
|
- }
|
||
|
- break;
|
||
|
- case DATATYPE_INTEGER:
|
||
|
- {
|
||
|
- CK_ULONG value = CKYBuffer_GetLong(data, offset);
|
||
|
- attrLen = 4;
|
||
|
- attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
|
||
|
- }
|
||
|
- break;
|
||
|
- default:
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Invalid attribute Data Type %d\n", attributeDataType);
|
||
|
- }
|
||
|
+ attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
|
||
|
+ break;
|
||
|
+ case DATATYPE_BOOL_FALSE:
|
||
|
+ case DATATYPE_BOOL_TRUE:
|
||
|
+ {
|
||
|
+ CKYByte bval = attributeDataType & 1;
|
||
|
+ attrib.setValue(&bval, 1);
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case DATATYPE_INTEGER:
|
||
|
+ {
|
||
|
+ CK_ULONG value = CKYBuffer_GetLong(data, offset);
|
||
|
+ attrLen = 4;
|
||
|
+ attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Invalid attribute Data Type %d\n", attributeDataType);
|
||
|
+ }
|
||
|
offset += attrLen;
|
||
|
attributes.push_back(attrib);
|
||
|
}
|
||
|
@@ -276,7 +397,7 @@ static const CK_ATTRIBUTE rdr_templat
|
||
|
|
||
|
bool
|
||
|
PKCS11Object::matchesTemplate(const CK_ATTRIBUTE_PTR pTemplate,
|
||
|
- CK_ULONG ulCount)
|
||
|
+ CK_ULONG ulCount)
|
||
|
const
|
||
|
{
|
||
|
unsigned int i;
|
||
|
@@ -285,10 +406,10 @@ PKCS11Object::matchesTemplate(const CK_A
|
||
|
|
||
|
#if defined( NSS_HIDE_NONSTANDARD_OBJECTS )
|
||
|
if (!ulCount) {
|
||
|
- // exclude MOZ reader objects from searches for all objects.
|
||
|
- // To find an MOZ reader object, one must search for it by
|
||
|
- // some matching attribute, such as class.
|
||
|
- iterator iter = find_if(attributes.begin(), attributes.end(),
|
||
|
+ // exclude MOZ reader objects from searches for all objects.
|
||
|
+ // To find an MOZ reader object, one must search for it by
|
||
|
+ // some matching attribute, such as class.
|
||
|
+ iterator iter = find_if(attributes.begin(), attributes.end(),
|
||
|
AttributeMatch(&rdr_template[0]));
|
||
|
return (iter == attributes.end()) ? true : false;
|
||
|
}
|
||
|
@@ -325,7 +446,7 @@ PKCS11Object::getAttribute(CK_ATTRIBUTE_
|
||
|
AttributeTypeMatch(type));
|
||
|
|
||
|
if( iter == attributes.end() ) {
|
||
|
- return NULL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
return iter->getValue();
|
||
|
}
|
||
|
@@ -349,8 +470,9 @@ PKCS11Object::getAttributeValue(CK_ATTRI
|
||
|
if( iter == attributes.end() ) {
|
||
|
// no attribute of this type
|
||
|
attrTypeInvalid = true;
|
||
|
- log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
|
||
|
- pTemplate[i].type, muscleObjID);
|
||
|
+ if ( log )
|
||
|
+ log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
|
||
|
+ pTemplate[i].type, muscleObjID);
|
||
|
pTemplate[i].ulValueLen = (CK_ULONG)-1;
|
||
|
continue;
|
||
|
}
|
||
|
@@ -371,7 +493,7 @@ PKCS11Object::getAttributeValue(CK_ATTRI
|
||
|
// the buffer is large enough. return the value and set the exact
|
||
|
// length.
|
||
|
memcpy(pTemplate[i].pValue, CKYBuffer_Data(iter->getValue()),
|
||
|
- CKYBuffer_Size(iter->getValue()));
|
||
|
+ CKYBuffer_Size(iter->getValue()));
|
||
|
pTemplate[i].ulValueLen = CKYBuffer_Size(iter->getValue());
|
||
|
}
|
||
|
|
||
|
@@ -406,14 +528,14 @@ PKCS11Object::getLabel()
|
||
|
|
||
|
// none found
|
||
|
if( iter == attributes.end() ) {
|
||
|
- return "";
|
||
|
+ return "";
|
||
|
}
|
||
|
|
||
|
int size = CKYBuffer_Size(iter->getValue());
|
||
|
|
||
|
label = new char [ size + 1 ];
|
||
|
if (!label) {
|
||
|
- return "";
|
||
|
+ return "";
|
||
|
}
|
||
|
memcpy(label, CKYBuffer_Data(iter->getValue()), size);
|
||
|
label[size] = 0;
|
||
|
@@ -431,13 +553,13 @@ PKCS11Object::getClass()
|
||
|
|
||
|
// none found */
|
||
|
if( iter == attributes.end() ) {
|
||
|
- return (CK_OBJECT_CLASS) -1;
|
||
|
+ return (CK_OBJECT_CLASS) -1;
|
||
|
}
|
||
|
|
||
|
int size = CKYBuffer_Size(iter->getValue());
|
||
|
|
||
|
if (size != sizeof(objClass)) {
|
||
|
- return (CK_OBJECT_CLASS) -1;
|
||
|
+ return (CK_OBJECT_CLASS) -1;
|
||
|
}
|
||
|
|
||
|
memcpy(&objClass, CKYBuffer_Data(iter->getValue()), size);
|
||
|
@@ -453,7 +575,7 @@ PKCS11Object::setAttribute(CK_ATTRIBUTE_
|
||
|
iter = find_if(attributes.begin(), attributes.end(),
|
||
|
AttributeTypeMatch(type));
|
||
|
if( iter != attributes.end() ) {
|
||
|
- iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
|
||
|
+ iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
|
||
|
} else {
|
||
|
attributes.push_back(PKCS11Attribute(type, value));
|
||
|
}
|
||
|
@@ -505,9 +627,15 @@ dataStart(const CKYByte *buf, unsigned i
|
||
|
unsigned char tag;
|
||
|
unsigned int used_length= 0;
|
||
|
|
||
|
+ *data_length = 0; /* make sure data_length is zero on failure */
|
||
|
+
|
||
|
if(!buf) {
|
||
|
return NULL;
|
||
|
}
|
||
|
+ /* there must be at least 2 bytes */
|
||
|
+ if (length < 2) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
tag = buf[used_length++];
|
||
|
|
||
|
@@ -521,15 +649,22 @@ dataStart(const CKYByte *buf, unsigned i
|
||
|
if (*data_length&0x80) {
|
||
|
int len_count = *data_length & 0x7f;
|
||
|
|
||
|
+ if (len_count+used_length > length) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
*data_length = 0;
|
||
|
|
||
|
while (len_count-- > 0) {
|
||
|
*data_length = (*data_length << 8) | buf[used_length++];
|
||
|
}
|
||
|
}
|
||
|
+ /* paranoia, can't happen */
|
||
|
+ if (length < used_length) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
if (*data_length > (length-used_length) ) {
|
||
|
- *data_length = length-used_length;
|
||
|
return NULL;
|
||
|
}
|
||
|
if (includeTag) *data_length += used_length;
|
||
|
@@ -542,16 +677,158 @@ unwrapBitString(const CKYByte *buf, unsi
|
||
|
{
|
||
|
/* for RSA, bit string always has byte number of bits */
|
||
|
if (buf[0] != 0) {
|
||
|
- return NULL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
if (len < 1) {
|
||
|
- return NULL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
*retLen = len -1;
|
||
|
return buf+1;
|
||
|
}
|
||
|
|
||
|
static SECStatus
|
||
|
+GetECKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
|
||
|
+ CCItem *point, CCItem *params)
|
||
|
+{
|
||
|
+ const CKYByte *buf = spki_data;
|
||
|
+ unsigned int buf_length = spki_length;
|
||
|
+ const CKYByte *algid;
|
||
|
+ unsigned int algidlen;
|
||
|
+ const CKYByte *dummy;
|
||
|
+ unsigned int dummylen;
|
||
|
+
|
||
|
+ if (!point || !params || !buf)
|
||
|
+ return SECFailure;
|
||
|
+
|
||
|
+ point->data = NULL;
|
||
|
+ point->len = 0;
|
||
|
+ params->data = NULL;
|
||
|
+ params->len = 0;
|
||
|
+
|
||
|
+ /* unwrap the algorithm id */
|
||
|
+ dummy = dataStart(buf,buf_length,&dummylen,false);
|
||
|
+ if (dummy == NULL) return SECFailure;
|
||
|
+ buf_length -= (dummy-buf) + dummylen;
|
||
|
+ buf = dummy + dummylen;
|
||
|
+ /* unwrpped value is in dummy */
|
||
|
+ algid = dummy;
|
||
|
+ algidlen = dummylen;
|
||
|
+ /* skip past algid oid */
|
||
|
+ dummy = dataStart(algid, algidlen, &dummylen, false);
|
||
|
+ if (dummy == NULL) return SECFailure;
|
||
|
+ algidlen -= (dummy-algid) + dummylen;
|
||
|
+ algid = dummy + dummylen;
|
||
|
+ params->data = algid;
|
||
|
+ params->len = algidlen;
|
||
|
+
|
||
|
+ /* unwrap the public key info */
|
||
|
+ buf = dataStart(buf,buf_length,&buf_length,false);
|
||
|
+ if (buf == NULL) return SECFailure;
|
||
|
+ buf = unwrapBitString(buf,buf_length,&buf_length);
|
||
|
+ if (buf == NULL) return SECFailure;
|
||
|
+
|
||
|
+ point->data = buf;
|
||
|
+ point->len = buf_length;
|
||
|
+
|
||
|
+ if(point->data == NULL) return SECFailure;
|
||
|
+
|
||
|
+ return SECSuccess;
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+GetKeyOIDMatches(const CKYByte *spki_data, unsigned int length, const CKYByte *oid_data)
|
||
|
+{
|
||
|
+ bool ret = TRUE;
|
||
|
+
|
||
|
+ if( spki_data == NULL || oid_data == NULL) {
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ for ( int i = 0 ; i < (int) length ; i++) {
|
||
|
+ if (spki_data[i] != oid_data[i]) {
|
||
|
+ ret = FALSE;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static SECStatus
|
||
|
+GetKeyAlgorithmId(const CKYByte *spki_data, unsigned int spki_length,
|
||
|
+ CCItem *algorithmId)
|
||
|
+{
|
||
|
+
|
||
|
+ const CKYByte *buf = spki_data;
|
||
|
+ unsigned int buf_length = spki_length;
|
||
|
+
|
||
|
+ if ( algorithmId == NULL) return SECFailure;
|
||
|
+
|
||
|
+ /* objtain the algorithm id */
|
||
|
+ algorithmId->data = dataStart(buf,buf_length,&algorithmId->len,false);
|
||
|
+ if (algorithmId->data == NULL) return SECFailure;
|
||
|
+
|
||
|
+ return SECSuccess;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static PKCS11Object::KeyType
|
||
|
+GetKeyTypeFromSPKI(const CKYBuffer *key)
|
||
|
+{
|
||
|
+ CCItem algIdItem;
|
||
|
+ SECStatus ret = GetKeyAlgorithmId(CKYBuffer_Data(key),
|
||
|
+ CKYBuffer_Size(key),&algIdItem);
|
||
|
+ PKCS11Object::KeyType foundType = PKCS11Object::unknown;
|
||
|
+
|
||
|
+ if ( ret != SECSuccess ) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode key algorithm ID.");
|
||
|
+ }
|
||
|
+
|
||
|
+ unsigned int length = 0;
|
||
|
+ const CKYByte *keyData = NULL;
|
||
|
+
|
||
|
+ /* Get actual oid buffer */
|
||
|
+
|
||
|
+ keyData = dataStart(algIdItem.data,algIdItem.len,&length, false);
|
||
|
+ if (keyData == NULL) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode key algorithm ID.");
|
||
|
+ }
|
||
|
+
|
||
|
+ bool match = FALSE;
|
||
|
+
|
||
|
+ /* Check for outrageous length */
|
||
|
+
|
||
|
+ if ( length <= 3 || length >= algIdItem.len) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode key algorithm ID.");
|
||
|
+ }
|
||
|
+ /* check for RSA */
|
||
|
+
|
||
|
+ match = GetKeyOIDMatches(keyData, length, rsaOID);
|
||
|
+
|
||
|
+ if ( match == TRUE ) {
|
||
|
+ foundType = PKCS11Object::rsa;
|
||
|
+ } else {
|
||
|
+ /* check for ECC */
|
||
|
+ match = GetKeyOIDMatches(keyData, length, eccOID);
|
||
|
+
|
||
|
+ if ( match == TRUE ) {
|
||
|
+ foundType = PKCS11Object::ecc;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( foundType == PKCS11Object::unknown) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode key algorithm ID.");
|
||
|
+ }
|
||
|
+ return foundType;
|
||
|
+}
|
||
|
+
|
||
|
+static SECStatus
|
||
|
GetKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
|
||
|
CCItem *modulus, CCItem *exponent)
|
||
|
{
|
||
|
@@ -596,7 +873,7 @@ GetKeyFields(const CKYBuffer *spki, CKYB
|
||
|
CCItem modulusItem, exponentItem;
|
||
|
|
||
|
rv = GetKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki),
|
||
|
- &modulusItem, &exponentItem);
|
||
|
+ &modulusItem, &exponentItem);
|
||
|
|
||
|
if( rv != SECSuccess ) {
|
||
|
throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
@@ -607,6 +884,29 @@ GetKeyFields(const CKYBuffer *spki, CKYB
|
||
|
CKYBuffer_Replace(exponent, 0, exponentItem.data, exponentItem.len);
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+GetECKeyFields(const CKYBuffer *spki, CKYBuffer *point, CKYBuffer *params)
|
||
|
+{
|
||
|
+ SECStatus rv;
|
||
|
+ CCItem pointItem, paramsItem;
|
||
|
+
|
||
|
+ if (spki == NULL || point == NULL || params == NULL) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode certificate Subject Public KeyInfo!");
|
||
|
+ }
|
||
|
+
|
||
|
+ rv = GetECKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki),
|
||
|
+ &pointItem, ¶msItem);
|
||
|
+
|
||
|
+ if( rv != SECSuccess ) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_FAILED,
|
||
|
+ "Failed to decode certificate Subject Public Key Info!");
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_Replace(point, 0, pointItem.data, pointItem.len);
|
||
|
+ CKYBuffer_Replace(params, 0, paramsItem.data, paramsItem.len);
|
||
|
+}
|
||
|
+
|
||
|
Key::Key(unsigned long muscleObjID, const CKYBuffer *data,
|
||
|
CK_OBJECT_HANDLE handle) : PKCS11Object(muscleObjID, data, handle)
|
||
|
{
|
||
|
@@ -616,22 +916,41 @@ Key::Key(unsigned long muscleObjID, cons
|
||
|
CKYBuffer_InitEmpty(&empty);
|
||
|
|
||
|
if ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY)) {
|
||
|
- /* only CKK_RSA is supported */
|
||
|
- setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
+ //we may know already what type of key this is.
|
||
|
+ if (attributeExists(CKA_KEY_TYPE)) {
|
||
|
+ CK_ULONG type = 0;
|
||
|
+ CK_ATTRIBUTE aTemplate = {CKA_KEY_TYPE, &type, sizeof(CK_ULONG)};
|
||
|
+
|
||
|
+ getAttributeValue(&aTemplate, 1, NULL);
|
||
|
+
|
||
|
+ if (type == 0x3) {
|
||
|
+ setKeyType(ecc);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_EC);
|
||
|
+ } else {
|
||
|
+ setKeyType(rsa);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* default to rsa */
|
||
|
+ setKeyType(rsa);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
+ }
|
||
|
+
|
||
|
+ // Could be RSA or ECC
|
||
|
} else if (objClass == CKO_SECRET_KEY) {
|
||
|
- if (!attributeExists(CKA_LABEL)) {
|
||
|
- setAttribute(CKA_LABEL, &empty);
|
||
|
- }
|
||
|
- if (!attributeExists(CKA_KEY_TYPE)) {
|
||
|
- /* default to DES3 */
|
||
|
- setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
|
||
|
- }
|
||
|
+ if (!attributeExists(CKA_LABEL)) {
|
||
|
+ setAttribute(CKA_LABEL, &empty);
|
||
|
+ }
|
||
|
+ if (!attributeExists(CKA_KEY_TYPE)) {
|
||
|
+ /* default to DES3 */
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
|
||
|
+ }
|
||
|
}
|
||
|
if (!attributeExists(CKA_START_DATE)) {
|
||
|
- setAttribute(CKA_START_DATE, &empty);
|
||
|
+ setAttribute(CKA_START_DATE, &empty);
|
||
|
}
|
||
|
if (!attributeExists(CKA_END_DATE)) {
|
||
|
- setAttribute(CKA_END_DATE, &empty);
|
||
|
+ setAttribute(CKA_END_DATE, &empty);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -640,32 +959,59 @@ Key::completeKey(const PKCS11Object &cer
|
||
|
{
|
||
|
// infer key attributes from cert
|
||
|
bool modulusExists, exponentExists;
|
||
|
- CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
|
||
|
- CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
|
||
|
+ bool pointExists, paramsExists;
|
||
|
+
|
||
|
+ PKCS11Object::KeyType keyType;
|
||
|
+ const CKYBuffer *key = cert.getPubKey();
|
||
|
|
||
|
if (!attributeExists(CKA_LABEL)) {
|
||
|
- setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
|
||
|
+ setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
|
||
|
}
|
||
|
+
|
||
|
+ CKYBuffer param1; CKYBuffer_InitEmpty(¶m1);
|
||
|
+ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
|
||
|
try {
|
||
|
- modulusExists = attributeExists(CKA_MODULUS);
|
||
|
- exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
|
||
|
- if (!modulusExists || !exponentExists) {
|
||
|
- const CKYBuffer *key = cert.getPubKey();
|
||
|
- GetKeyFields(key, &modulus, &exponent);
|
||
|
- if (!modulusExists) {
|
||
|
- setAttribute(CKA_MODULUS, &modulus);
|
||
|
- }
|
||
|
- if (!exponentExists) {
|
||
|
- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
|
||
|
- }
|
||
|
- }
|
||
|
+ keyType = GetKeyTypeFromSPKI(key);
|
||
|
+ setKeyType(keyType);
|
||
|
+
|
||
|
+ switch (keyType) {
|
||
|
+ case rsa:
|
||
|
+ modulusExists = attributeExists(CKA_MODULUS);
|
||
|
+ exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
|
||
|
+ if (!modulusExists || !exponentExists) {
|
||
|
+ GetKeyFields(key, ¶m1, ¶m2);
|
||
|
+ if (!modulusExists) {
|
||
|
+ setAttribute(CKA_MODULUS, ¶m1);
|
||
|
+ }
|
||
|
+ if (!exponentExists) {
|
||
|
+ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case ecc:
|
||
|
+ pointExists = attributeExists(CKA_EC_POINT);
|
||
|
+ paramsExists = attributeExists(CKA_EC_PARAMS);
|
||
|
+
|
||
|
+ if (!pointExists || !paramsExists) {
|
||
|
+ GetECKeyFields(key, ¶m1, ¶m2);
|
||
|
+ if (!pointExists) {
|
||
|
+ setAttribute(CKA_EC_POINT, ¶m1);
|
||
|
+ }
|
||
|
+ if (!paramsExists) {
|
||
|
+ setAttribute(CKA_EC_PARAMS, ¶m2);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
} catch (PKCS11Exception &e) {
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
- throw e;
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
+ throw e;
|
||
|
}
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
}
|
||
|
|
||
|
static SECStatus
|
||
|
@@ -737,14 +1083,14 @@ GetCertFieldItems(const CKYByte *dercert
|
||
|
|
||
|
static void
|
||
|
GetCertFields(const CKYBuffer *derCert, CKYBuffer *derSerial,
|
||
|
- CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
|
||
|
+ CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
|
||
|
{
|
||
|
SECStatus rv;
|
||
|
CCItem issuerItem, serialItem, derSerialItem, subjectItem,
|
||
|
validityItem, subjectKeyItem;
|
||
|
|
||
|
rv = GetCertFieldItems(CKYBuffer_Data(derCert), CKYBuffer_Size(derCert),
|
||
|
- &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
|
||
|
+ &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
|
||
|
&subjectKeyItem);
|
||
|
|
||
|
if( rv != SECSuccess ) {
|
||
|
@@ -769,50 +1115,50 @@ Cert::Cert(unsigned long muscleObjID, co
|
||
|
CK_ULONG certTypeValue = CKC_X_509;
|
||
|
|
||
|
CKYBuffer_InitFromData(&certType, (CKYByte *)&certTypeValue,
|
||
|
- sizeof(certTypeValue));
|
||
|
+ sizeof(certTypeValue));
|
||
|
CKYBuffer_Resize(&pubKey,0);
|
||
|
|
||
|
try {
|
||
|
- setAttribute(CKA_CERTIFICATE_TYPE, &certType);
|
||
|
+ setAttribute(CKA_CERTIFICATE_TYPE, &certType);
|
||
|
|
||
|
- if (!attributeExists(CKA_VALUE)) {
|
||
|
- if (derCert) {
|
||
|
- setAttribute(CKA_VALUE, derCert);
|
||
|
- } else {
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Missing certificate data from token");
|
||
|
- }
|
||
|
- }
|
||
|
+ if (!attributeExists(CKA_VALUE)) {
|
||
|
+ if (derCert) {
|
||
|
+ setAttribute(CKA_VALUE, derCert);
|
||
|
+ } else {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Missing certificate data from token");
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
- if (!derCert) {
|
||
|
- derCert = getAttribute(CKA_VALUE);
|
||
|
- if (!derCert) {
|
||
|
- // paranoia, should never happen since we verify the
|
||
|
- // attribute exists above
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Missing certificate data from token");
|
||
|
- }
|
||
|
- }
|
||
|
+ if (!derCert) {
|
||
|
+ derCert = getAttribute(CKA_VALUE);
|
||
|
+ if (!derCert) {
|
||
|
+ // paranoia, should never happen since we verify the
|
||
|
+ // attribute exists above
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Missing certificate data from token");
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
- // infer cert attributes
|
||
|
+ // infer cert attributes
|
||
|
|
||
|
- GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
|
||
|
+ GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
|
||
|
|
||
|
- if (!attributeExists(CKA_SERIAL_NUMBER)) {
|
||
|
- setAttribute(CKA_SERIAL_NUMBER, &derSerial);
|
||
|
- }
|
||
|
- if (!attributeExists(CKA_SUBJECT)) {
|
||
|
- setAttribute(CKA_SUBJECT, &derSubject);
|
||
|
- }
|
||
|
- if (!attributeExists(CKA_ISSUER)) {
|
||
|
- setAttribute(CKA_ISSUER, &derIssuer);
|
||
|
- }
|
||
|
+ if (!attributeExists(CKA_SERIAL_NUMBER)) {
|
||
|
+ setAttribute(CKA_SERIAL_NUMBER, &derSerial);
|
||
|
+ }
|
||
|
+ if (!attributeExists(CKA_SUBJECT)) {
|
||
|
+ setAttribute(CKA_SUBJECT, &derSubject);
|
||
|
+ }
|
||
|
+ if (!attributeExists(CKA_ISSUER)) {
|
||
|
+ setAttribute(CKA_ISSUER, &derIssuer);
|
||
|
+ }
|
||
|
} catch (PKCS11Exception &e) {
|
||
|
- CKYBuffer_FreeData(&certType);
|
||
|
- CKYBuffer_FreeData(&derSerial);
|
||
|
- CKYBuffer_FreeData(&derSubject);
|
||
|
- CKYBuffer_FreeData(&derIssuer);
|
||
|
- throw e;
|
||
|
+ CKYBuffer_FreeData(&certType);
|
||
|
+ CKYBuffer_FreeData(&derSerial);
|
||
|
+ CKYBuffer_FreeData(&derSubject);
|
||
|
+ CKYBuffer_FreeData(&derIssuer);
|
||
|
+ throw e;
|
||
|
}
|
||
|
CKYBuffer_FreeData(&certType);
|
||
|
CKYBuffer_FreeData(&derSerial);
|
||
|
@@ -822,7 +1168,7 @@ Cert::Cert(unsigned long muscleObjID, co
|
||
|
|
||
|
Reader::Reader(unsigned long muscleObjID, CK_OBJECT_HANDLE handle,
|
||
|
const char *reader, const CKYBuffer *cardATR, bool isCoolkey) :
|
||
|
- PKCS11Object(muscleObjID, handle)
|
||
|
+ PKCS11Object(muscleObjID, handle)
|
||
|
{
|
||
|
setAttributeULong(CKA_CLASS, CKO_MOZ_READER);
|
||
|
setAttribute(CKA_LABEL, reader);
|
||
|
@@ -833,9 +1179,10 @@ Reader::Reader(unsigned long muscleObjID
|
||
|
setAttribute(CKA_MOZ_ATR, cardATR);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) :
|
||
|
- PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
|
||
|
- instance | 0x400)
|
||
|
+ PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
|
||
|
+ instance | 0x400)
|
||
|
{
|
||
|
CKYBuffer id;
|
||
|
CKYBuffer empty;
|
||
|
@@ -844,7 +1191,7 @@ CACPrivKey::CACPrivKey(CKYByte instance,
|
||
|
/* So we know what the key is supposed to be used for based on
|
||
|
* the instance */
|
||
|
if (instance == 2) {
|
||
|
- decrypt = TRUE;
|
||
|
+ decrypt = TRUE;
|
||
|
}
|
||
|
|
||
|
CKYBuffer_InitEmpty(&empty);
|
||
|
@@ -863,33 +1210,52 @@ CACPrivKey::CACPrivKey(CKYByte instance,
|
||
|
setAttributeBool(CKA_LOCAL, TRUE);
|
||
|
setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
|
||
|
- setAttributeBool(CKA_DECRYPT, decrypt);
|
||
|
setAttributeBool(CKA_SIGN, !decrypt);
|
||
|
setAttributeBool(CKA_SIGN_RECOVER, !decrypt);
|
||
|
setAttributeBool(CKA_UNWRAP, FALSE);
|
||
|
setAttributeBool(CKA_SENSITIVE, TRUE);
|
||
|
setAttributeBool(CKA_EXTRACTABLE, FALSE);
|
||
|
|
||
|
- CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
|
||
|
- CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
|
||
|
+ CKYBuffer param1; CKYBuffer_InitEmpty(¶m1);
|
||
|
+ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
|
||
|
|
||
|
try {
|
||
|
- const CKYBuffer *key = cert.getPubKey();
|
||
|
- GetKeyFields(key, &modulus, &exponent);
|
||
|
- setAttribute(CKA_MODULUS, &modulus);
|
||
|
- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
|
||
|
- } catch (PKCS11Exception &e) {
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
- throw e;
|
||
|
- }
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
+ const CKYBuffer *key = cert.getPubKey();
|
||
|
+ keyType = GetKeyTypeFromSPKI(key);
|
||
|
+ setKeyType(keyType);
|
||
|
+
|
||
|
+ switch (keyType) {
|
||
|
+ case rsa:
|
||
|
+ GetKeyFields(key, ¶m1, ¶m2);
|
||
|
+ setAttribute(CKA_MODULUS, ¶m1);
|
||
|
+ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
+ setAttributeBool(CKA_DECRYPT, decrypt);
|
||
|
+ setAttributeBool(CKA_DERIVE, FALSE);
|
||
|
+ break;
|
||
|
+ case ecc:
|
||
|
+ GetECKeyFields(key, ¶m1, ¶m2);
|
||
|
+ setAttribute(CKA_EC_POINT, ¶m1);
|
||
|
+ setAttribute(CKA_EC_PARAMS, ¶m2);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_EC);
|
||
|
+ setAttributeBool(CKA_DECRYPT, FALSE);
|
||
|
+ setAttributeBool(CKA_DERIVE, decrypt);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ } catch (PKCS11Exception &e) {
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
+ throw e;
|
||
|
+ }
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
}
|
||
|
|
||
|
CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) :
|
||
|
- PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16,
|
||
|
- instance | 0x500)
|
||
|
+ PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16,
|
||
|
+ instance | 0x500)
|
||
|
{
|
||
|
CKYBuffer id;
|
||
|
CKYBuffer empty;
|
||
|
@@ -898,7 +1264,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) {
|
||
|
- encrypt = TRUE;
|
||
|
+ encrypt = TRUE;
|
||
|
}
|
||
|
|
||
|
CKYBuffer_InitEmpty(&empty);
|
||
|
@@ -915,34 +1281,49 @@ CACPubKey::CACPubKey(CKYByte instance, c
|
||
|
setAttribute(CKA_END_DATE, &empty);
|
||
|
setAttributeBool(CKA_DERIVE, FALSE);
|
||
|
setAttributeBool(CKA_LOCAL, TRUE);
|
||
|
- setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
|
||
|
setAttributeBool(CKA_ENCRYPT, encrypt);
|
||
|
setAttributeBool(CKA_VERIFY, !encrypt);
|
||
|
setAttributeBool(CKA_VERIFY_RECOVER, !encrypt);
|
||
|
setAttributeBool(CKA_WRAP, FALSE);
|
||
|
|
||
|
- CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
|
||
|
- CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
|
||
|
+ CKYBuffer param1; CKYBuffer_InitEmpty(¶m1);
|
||
|
+ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
|
||
|
|
||
|
try {
|
||
|
- const CKYBuffer *key = cert.getPubKey();
|
||
|
- GetKeyFields(key, &modulus, &exponent);
|
||
|
- setAttribute(CKA_MODULUS, &modulus);
|
||
|
- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
|
||
|
- } catch (PKCS11Exception &e) {
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
- throw e;
|
||
|
- }
|
||
|
- CKYBuffer_FreeData(&modulus);
|
||
|
- CKYBuffer_FreeData(&exponent);
|
||
|
+ const CKYBuffer *key = cert.getPubKey();
|
||
|
+ keyType = GetKeyTypeFromSPKI(key);
|
||
|
+ setKeyType(keyType);
|
||
|
+
|
||
|
+ switch (keyType) {
|
||
|
+ case rsa:
|
||
|
+ GetKeyFields(key, ¶m1, ¶m2);
|
||
|
+ setAttribute(CKA_MODULUS, ¶m1);
|
||
|
+ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
|
||
|
+ break;
|
||
|
+ case ecc:
|
||
|
+ GetECKeyFields(key, ¶m1, ¶m2);
|
||
|
+ setAttribute(CKA_EC_POINT, ¶m1);
|
||
|
+ setAttribute(CKA_EC_PARAMS, ¶m2);
|
||
|
+ setAttributeULong(CKA_KEY_TYPE, CKK_EC);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ } catch (PKCS11Exception &e) {
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
+ throw e;
|
||
|
+ }
|
||
|
+ CKYBuffer_FreeData(¶m1);
|
||
|
+ CKYBuffer_FreeData(¶m2);
|
||
|
}
|
||
|
|
||
|
static const char *CAC_Label[] = {
|
||
|
- "CAC ID Certificate",
|
||
|
- "CAC Email Signature Certificate",
|
||
|
- "CAC Email Encryption Certificate",
|
||
|
+ "CAC ID Certificate",
|
||
|
+ "CAC Email Signature Certificate",
|
||
|
+ "CAC Email Encryption Certificate",
|
||
|
};
|
||
|
|
||
|
static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 };
|
||
|
@@ -959,39 +1340,43 @@ GetCN(const CKYByte *dn, unsigned int dn
|
||
|
if (buf == NULL) return SECFailure;
|
||
|
|
||
|
while (buf_length) {
|
||
|
- const CKYByte *name;
|
||
|
- unsigned int name_length;
|
||
|
- const CKYByte *oid;
|
||
|
- unsigned int oid_length;
|
||
|
-
|
||
|
- /* unwrap the set */
|
||
|
- name = dataStart(buf, buf_length, &name_length, false);
|
||
|
+ const CKYByte *name;
|
||
|
+ unsigned int name_length;
|
||
|
+ const CKYByte *oid;
|
||
|
+ unsigned int oid_length;
|
||
|
+
|
||
|
+ /* unwrap the set */
|
||
|
+ name = dataStart(buf, buf_length, &name_length, false);
|
||
|
+ if (name == NULL) return SECFailure;
|
||
|
|
||
|
/* advance to next set */
|
||
|
- buf_length -= (name-buf) + name_length;
|
||
|
- buf = name + name_length;
|
||
|
+ buf_length -= (name-buf) + name_length;
|
||
|
+ buf = name + name_length;
|
||
|
|
||
|
- /* unwrap the Sequence */
|
||
|
- name = dataStart(name, name_length, &name_length, false);
|
||
|
+ /* unwrap the Sequence */
|
||
|
+ name = dataStart(name, name_length, &name_length, false);
|
||
|
+ if (name == NULL) return SECFailure;
|
||
|
|
||
|
/* unwrap the oid */
|
||
|
- oid = dataStart(name, name_length, &oid_length, false);
|
||
|
+ oid = dataStart(name, name_length, &oid_length, false);
|
||
|
+ if (oid == NULL) return SECFailure;
|
||
|
|
||
|
- /* test the oid */
|
||
|
- if (oid_length != CN_LENGTH) {
|
||
|
- continue;
|
||
|
- }
|
||
|
- if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
|
||
|
- continue;
|
||
|
- }
|
||
|
+ /* test the oid */
|
||
|
+ if (oid_length != CN_LENGTH) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
|
||
|
- /* advance to CN */
|
||
|
- name_length -= (oid-name) + oid_length;
|
||
|
- name = oid + oid_length;
|
||
|
-
|
||
|
- /* unwrap the CN */
|
||
|
- cn->data = dataStart(name, name_length, &cn->len, false);
|
||
|
- return SECSuccess;
|
||
|
+ /* advance to CN */
|
||
|
+ name_length -= (oid-name) + oid_length;
|
||
|
+ name = oid + oid_length;
|
||
|
+
|
||
|
+ /* unwrap the CN */
|
||
|
+ cn->data = dataStart(name, name_length, &cn->len, false);
|
||
|
+ if (cn->data == NULL) return SECFailure;
|
||
|
+ return SECSuccess;
|
||
|
}
|
||
|
return SECFailure;
|
||
|
}
|
||
|
@@ -1006,11 +1391,11 @@ GetUserName(const CKYBuffer *dn)
|
||
|
rv = GetCN(CKYBuffer_Data(dn), CKYBuffer_Size(dn) , &cn);
|
||
|
|
||
|
if( rv != SECSuccess ) {
|
||
|
- return NULL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
string = new char [ cn.len + 1 ];
|
||
|
if (string == NULL) {
|
||
|
- return NULL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
memcpy(string, cn.data, cn.len);
|
||
|
string[cn.len] = 0;
|
||
|
@@ -1018,8 +1403,8 @@ GetUserName(const CKYBuffer *dn)
|
||
|
}
|
||
|
|
||
|
CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) :
|
||
|
- PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16,
|
||
|
- instance | 0x600)
|
||
|
+ PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16,
|
||
|
+ instance | 0x600)
|
||
|
{
|
||
|
CKYBuffer id;
|
||
|
CKYBuffer empty;
|
||
|
@@ -1028,7 +1413,7 @@ CACCert::CACCert(CKYByte instance, const
|
||
|
/* So we know what the key is supposed to be used for based on
|
||
|
* the instance */
|
||
|
if (instance == 2) {
|
||
|
- decrypt = TRUE;
|
||
|
+ decrypt = TRUE;
|
||
|
}
|
||
|
|
||
|
CKYBuffer_InitEmpty(&empty);
|
||
|
@@ -1050,19 +1435,19 @@ CACCert::CACCert(CKYByte instance, const
|
||
|
CKYBuffer_Resize(&pubKey,0);
|
||
|
|
||
|
try {
|
||
|
- setAttribute(CKA_VALUE, derCert);
|
||
|
- // infer cert attributes
|
||
|
+ setAttribute(CKA_VALUE, derCert);
|
||
|
+ // infer cert attributes
|
||
|
|
||
|
- GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
|
||
|
+ GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
|
||
|
|
||
|
- setAttribute(CKA_SERIAL_NUMBER, &derSerial);
|
||
|
- setAttribute(CKA_SUBJECT, &derSubject);
|
||
|
- setAttribute(CKA_ISSUER, &derIssuer);
|
||
|
+ setAttribute(CKA_SERIAL_NUMBER, &derSerial);
|
||
|
+ setAttribute(CKA_SUBJECT, &derSubject);
|
||
|
+ setAttribute(CKA_ISSUER, &derIssuer);
|
||
|
} catch (PKCS11Exception &e) {
|
||
|
- CKYBuffer_FreeData(&derSerial);
|
||
|
- CKYBuffer_FreeData(&derSubject);
|
||
|
- CKYBuffer_FreeData(&derIssuer);
|
||
|
- throw e;
|
||
|
+ CKYBuffer_FreeData(&derSerial);
|
||
|
+ CKYBuffer_FreeData(&derSubject);
|
||
|
+ CKYBuffer_FreeData(&derIssuer);
|
||
|
+ throw e;
|
||
|
}
|
||
|
|
||
|
name = GetUserName(&derSubject); /* adopt */
|
||
|
@@ -1070,3 +1455,100 @@ CACCert::CACCert(CKYByte instance, const
|
||
|
CKYBuffer_FreeData(&derSubject);
|
||
|
CKYBuffer_FreeData(&derIssuer);
|
||
|
}
|
||
|
+
|
||
|
+DEREncodedSignature::DEREncodedSignature(const CKYBuffer *derSig)
|
||
|
+{
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&derEncodedSignature);
|
||
|
+ CKYBuffer_InitFromCopy(&derEncodedSignature, derSig);
|
||
|
+}
|
||
|
+
|
||
|
+DEREncodedSignature::~DEREncodedSignature()
|
||
|
+{
|
||
|
+ CKYBuffer_FreeData(&derEncodedSignature);
|
||
|
+}
|
||
|
+
|
||
|
+int DEREncodedSignature::getRawSignature(CKYBuffer *rawSig,
|
||
|
+ unsigned int keySize)
|
||
|
+{
|
||
|
+ const CKYByte *buf = NULL;
|
||
|
+
|
||
|
+ if (rawSig == NULL) {
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (CKYBuffer_Size(&derEncodedSignature) == 0) {
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_Zero(rawSig);
|
||
|
+
|
||
|
+ unsigned int seq_length = 0;
|
||
|
+ unsigned int expected_sig_len = ( (keySize + 7) / 8 ) * 2 ;
|
||
|
+ unsigned int expected_piece_size = expected_sig_len / 2 ;
|
||
|
+
|
||
|
+ /* unwrap the sequence */
|
||
|
+ buf = dataStart(CKYBuffer_Data(&derEncodedSignature), CKYBuffer_Size(&derEncodedSignature),&seq_length, false);
|
||
|
+
|
||
|
+ if (buf == NULL) return -1;
|
||
|
+
|
||
|
+ // unwrap first multi byte integer
|
||
|
+
|
||
|
+ unsigned int int_length = 0;
|
||
|
+ const CKYByte *int1Buf = NULL;
|
||
|
+ const CKYByte *int2Buf = NULL;
|
||
|
+
|
||
|
+ int1Buf = dataStart(buf, seq_length, &int_length, false );
|
||
|
+
|
||
|
+ if (int1Buf == NULL) return -1;
|
||
|
+ //advance to next entry
|
||
|
+
|
||
|
+ if (int_length > expected_piece_size) {
|
||
|
+
|
||
|
+ unsigned int diff = int_length - expected_piece_size ;
|
||
|
+
|
||
|
+ /* Make sure we are chopping off zeroes
|
||
|
+ Otherwise give up. */
|
||
|
+
|
||
|
+ for (int i = 0 ; i < (int) diff ; i++) {
|
||
|
+ if ( int1Buf[i] != 0)
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ int_length -= diff;
|
||
|
+ int1Buf += diff;
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ seq_length -= (int1Buf -buf) + int_length;
|
||
|
+ buf = int1Buf + int_length;
|
||
|
+
|
||
|
+ // unwrap second multi byte integer
|
||
|
+
|
||
|
+ unsigned int second_int_length = 0;
|
||
|
+
|
||
|
+ int2Buf = dataStart(buf, seq_length, &second_int_length, false);
|
||
|
+
|
||
|
+ if (int2Buf == NULL) return -1;
|
||
|
+
|
||
|
+
|
||
|
+ if (second_int_length > expected_piece_size) {
|
||
|
+ unsigned int diff = second_int_length - expected_piece_size ;
|
||
|
+
|
||
|
+ /* Make sure we are chopping off zeroes
|
||
|
+ Otherwise give up. */
|
||
|
+
|
||
|
+ for (int i = 0 ; i < (int) diff ; i++) {
|
||
|
+ if ( int2Buf[i] != 0)
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ second_int_length -= diff;
|
||
|
+ int2Buf += diff;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_AppendData(rawSig, int1Buf, int_length);
|
||
|
+ CKYBuffer_AppendData(rawSig, int2Buf, second_int_length);
|
||
|
+
|
||
|
+ return CKYSUCCESS;
|
||
|
+}
|
||
|
diff -up ./src/coolkey/object.h.piv-ecc ./src/coolkey/object.h
|
||
|
--- ./src/coolkey/object.h.piv-ecc 2013-09-08 15:50:33.081428035 -0700
|
||
|
+++ ./src/coolkey/object.h 2013-09-08 15:50:33.121428706 -0700
|
||
|
@@ -49,7 +49,7 @@ class PKCS11Attribute {
|
||
|
CKYBuffer_Size(&cpy.value));
|
||
|
return *this;
|
||
|
}
|
||
|
- PKCS11Attribute() { CKYBuffer_InitEmpty(&value); }
|
||
|
+ PKCS11Attribute() : type(0){ CKYBuffer_InitEmpty(&value); }
|
||
|
PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYBuffer *value_)
|
||
|
: type(type_) { CKYBuffer_InitFromCopy(&value, value_); }
|
||
|
~PKCS11Attribute() { CKYBuffer_FreeData(&value); }
|
||
|
@@ -57,6 +57,11 @@ class PKCS11Attribute {
|
||
|
|
||
|
class PKCS11Object {
|
||
|
public:
|
||
|
+ enum KeyType {
|
||
|
+ rsa,
|
||
|
+ ecc,
|
||
|
+ unknown
|
||
|
+ };
|
||
|
|
||
|
typedef list<PKCS11Attribute> AttributeList;
|
||
|
typedef AttributeList::iterator AttributeIter;
|
||
|
@@ -75,18 +80,20 @@ class PKCS11Object {
|
||
|
PKCS11Object &operator=(PKCS11Object &cpy) { return *this; } //Disallow
|
||
|
|
||
|
protected :
|
||
|
- CKYBuffer pubKey;
|
||
|
char *name;
|
||
|
+ KeyType keyType;
|
||
|
+ CKYBuffer pubKey;
|
||
|
|
||
|
public:
|
||
|
PKCS11Object(unsigned long muscleObjID, CK_OBJECT_HANDLE handle);
|
||
|
PKCS11Object(unsigned long muscleObjID, const CKYBuffer *data,
|
||
|
CK_OBJECT_HANDLE handle);
|
||
|
- ~PKCS11Object() { delete [] label; delete [] name; CKYBuffer_FreeData(&pubKey); }
|
||
|
+ ~PKCS11Object() { delete label; delete name; CKYBuffer_FreeData(&pubKey);
|
||
|
+ attributes.clear(); }
|
||
|
|
||
|
PKCS11Object(const PKCS11Object& cpy) :
|
||
|
attributes(cpy.attributes), muscleObjID(cpy.muscleObjID),
|
||
|
- handle(cpy.handle), label(NULL), name(NULL) {
|
||
|
+ handle(cpy.handle), label(NULL), name(NULL), keyType(cpy.keyType) {
|
||
|
CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey); }
|
||
|
|
||
|
|
||
|
@@ -116,14 +123,15 @@ class PKCS11Object {
|
||
|
const CKYBuffer *getPubKey(void) const {
|
||
|
return &pubKey;
|
||
|
}
|
||
|
+
|
||
|
+ KeyType getKeyType() const { return keyType;}
|
||
|
+ void setKeyType(KeyType theType) { keyType = theType; }
|
||
|
};
|
||
|
|
||
|
class Key : public PKCS11Object {
|
||
|
-
|
||
|
public:
|
||
|
Key(unsigned long muscleObjID, const CKYBuffer *data, CK_OBJECT_HANDLE handle);
|
||
|
void completeKey(const PKCS11Object &cert);
|
||
|
-
|
||
|
};
|
||
|
|
||
|
class Cert : public PKCS11Object {
|
||
|
@@ -153,6 +161,25 @@ class Reader : public PKCS11Object {
|
||
|
const char *reader, const CKYBuffer *cardATR, bool isCoolkey);
|
||
|
};
|
||
|
|
||
|
+class SecretKey : public PKCS11Object {
|
||
|
+ public:
|
||
|
+ SecretKey(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount);
|
||
|
+ private:
|
||
|
+ void adjustToKeyValueLength(CKYBuffer * secretKeyBuffer,CK_ULONG valueLength);
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+class DEREncodedSignature {
|
||
|
+
|
||
|
+ protected :
|
||
|
+ CKYBuffer derEncodedSignature;
|
||
|
+ public:
|
||
|
+ DEREncodedSignature(const CKYBuffer *derSig);
|
||
|
+ ~DEREncodedSignature();
|
||
|
+ int getRawSignature(CKYBuffer *rawSig, unsigned int keySize);
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
class AttributeMatch {
|
||
|
|
||
|
private:
|
||
|
diff -up ./src/coolkey/pkcs11t.h.piv-ecc ./src/coolkey/pkcs11t.h
|
||
|
--- ./src/coolkey/pkcs11t.h.piv-ecc 2006-06-09 11:39:11.000000000 -0700
|
||
|
+++ ./src/coolkey/pkcs11t.h 2013-09-08 15:50:33.122428723 -0700
|
||
|
@@ -1351,4 +1351,41 @@ typedef struct CK_PKCS5_PBKD2_PARAMS {
|
||
|
|
||
|
typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
|
||
|
|
||
|
+/* The following EC Key Derivation Functions are defined */
|
||
|
+
|
||
|
+#define CKD_NULL 0x00000001
|
||
|
+
|
||
|
+#define CKD_SHA1_KDF 0x00000002
|
||
|
+
|
||
|
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11. */
|
||
|
+
|
||
|
+ typedef CK_ULONG CK_EC_KDF_TYPE;
|
||
|
+
|
||
|
+/*
|
||
|
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
|
||
|
+ *
|
||
|
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
|
||
|
+ *
|
||
|
+ * where each party contributes one key pair.
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+typedef struct CK_ECDH1_DERIVE_PARAMS {
|
||
|
+
|
||
|
+ CK_EC_KDF_TYPE kdf;
|
||
|
+
|
||
|
+ CK_ULONG ulSharedDataLen;
|
||
|
+
|
||
|
+ CK_BYTE_PTR pSharedData;
|
||
|
+
|
||
|
+ CK_ULONG ulPublicDataLen;
|
||
|
+
|
||
|
+ CK_BYTE_PTR pPublicData;
|
||
|
+
|
||
|
+} CK_ECDH1_DERIVE_PARAMS;
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
|
||
|
+
|
||
|
#endif
|
||
|
diff -up ./src/coolkey/slot.cpp.piv-ecc ./src/coolkey/slot.cpp
|
||
|
--- ./src/coolkey/slot.cpp.piv-ecc 2013-09-08 15:50:33.112428555 -0700
|
||
|
+++ ./src/coolkey/slot.cpp 2013-09-08 15:50:33.124428757 -0700
|
||
|
@@ -54,6 +54,34 @@ const CKYByte ATR2[] =
|
||
|
{ 0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72,
|
||
|
0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 };
|
||
|
|
||
|
+
|
||
|
+/* ECC curve information
|
||
|
+ * Provide information for the limited set of curves supported by our smart card(s).
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+typedef struct curveBytes2Name {
|
||
|
+ const CKYByte * bytes;
|
||
|
+ const char *curveName;
|
||
|
+ unsigned int length;
|
||
|
+
|
||
|
+} CurveBytes2Name;
|
||
|
+
|
||
|
+/* First byte is length of oid byte array. */
|
||
|
+
|
||
|
+const CKYByte nistp256[] = { 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
|
||
|
+const CKYByte nistp384[] = { 0x5, 0x2b, 0x81, 0x04, 0x00, 0x22 };
|
||
|
+const CKYByte nistp521[] = { 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23 };
|
||
|
+
|
||
|
+const int numECCurves = 3;
|
||
|
+
|
||
|
+static CurveBytes2Name curveBytesNamePair[] =
|
||
|
+{
|
||
|
+ { nistp256, "nistp256", 256 },
|
||
|
+ { nistp384, "nistp384", 384 },
|
||
|
+ { nistp521, "nistp521", 521 }
|
||
|
+};
|
||
|
+
|
||
|
SlotList::SlotList(Log *log_) : log(log_)
|
||
|
{
|
||
|
// initialize things to NULL so we can recover from an exception
|
||
|
@@ -136,7 +164,11 @@ SlotList::updateSlotList()
|
||
|
throw PKCS11Exception(CKR_HOST_MEMORY);
|
||
|
memset(newSlots, 0, numReaders*sizeof(Slot*));
|
||
|
|
||
|
- memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
|
||
|
+ /* keep coverity happy, even though slot == NULL implies that
|
||
|
+ * numSlots == 0 */
|
||
|
+ if (slots) {
|
||
|
+ memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
|
||
|
+ }
|
||
|
|
||
|
for (unsigned int i=numSlots; i < numReaders; i++) {
|
||
|
newSlots[i] = new
|
||
|
@@ -237,32 +269,19 @@ SlotList::updateReaderList()
|
||
|
|
||
|
CKYStatus status = CKYCardContext_ListReaders(context, &readerNames);
|
||
|
if ( status != CKYSUCCESS ) {
|
||
|
- throw PKCS11Exception(CKR_GENERAL_ERROR,
|
||
|
+ /* if the service is stopped, treat it as if we have no readers */
|
||
|
+ if ((CKYCardContext_GetLastError(context) != SCARD_E_NO_SERVICE) &&
|
||
|
+ (CKYCardContext_GetLastError(context) != SCARD_E_SERVICE_STOPPED)) {
|
||
|
+ throw PKCS11Exception(CKR_GENERAL_ERROR,
|
||
|
"Failed to list readers: 0x%x\n",
|
||
|
CKYCardContext_GetLastError(context));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
- if (!readerStates) {
|
||
|
+ if (readerStates == NULL && readerNames != NULL) {
|
||
|
/* fresh Reader State list, just create it */
|
||
|
readerStates = CKYReader_CreateArray(readerNames, (CKYSize *)&numReaders);
|
||
|
|
||
|
- /* if we have no readers, make sure we have at least one to keep things
|
||
|
- * happy */
|
||
|
- if (readerStates == NULL &&
|
||
|
- CKYReaderNameList_GetCount(readerNames) == 0) {
|
||
|
- readerStates = (SCARD_READERSTATE *)
|
||
|
- malloc(sizeof(SCARD_READERSTATE));
|
||
|
- if (readerStates) {
|
||
|
- CKYReader_Init(readerStates);
|
||
|
- status = CKYReader_SetReaderName(readerStates, "E-Gate 0 0");
|
||
|
- if (status != CKYSUCCESS) {
|
||
|
- CKYReader_DestroyArray(readerStates, 1);
|
||
|
- readerStates = NULL;
|
||
|
- } else {
|
||
|
- numReaders = 1;
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
CKYReaderNameList_Destroy(readerNames);
|
||
|
|
||
|
if (readerStates == NULL) {
|
||
|
@@ -272,6 +291,16 @@ SlotList::updateReaderList()
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ if (readerStates == NULL) {
|
||
|
+ /* if we didn't have any readers before and we did get new names,
|
||
|
+ * that is handled above. If we didn't have any readers before, and
|
||
|
+ * we didn't get any names, there is nothing to update. blow out now.
|
||
|
+ * This more efficient and makes coverity happy (since coverity doesn't
|
||
|
+ * know numReaders and readerStates are linked). */
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
/* it would be tempting at this point just to see if we have more readers
|
||
|
* then specified previously. The problem with this is it is possible that
|
||
|
* some readers have been deleted, so the only way to tell if we have
|
||
|
@@ -286,18 +315,26 @@ SlotList::updateReaderList()
|
||
|
|
||
|
const char *curReaderName = NULL;
|
||
|
unsigned long knownState = 0;
|
||
|
- for(int ri = 0 ; ri < numReaders; ri ++) {
|
||
|
+ for(unsigned int ri = 0 ; ri < numReaders; ri ++) {
|
||
|
knownState = CKYReader_GetKnownState(&readerStates[ri]);
|
||
|
-
|
||
|
+
|
||
|
curReaderName = CKYReader_GetReaderName(&readerStates[ri]);
|
||
|
- if(readerNameExistsInList(curReaderName,&readerNames)) {
|
||
|
- CKYReader_SetKnownState(&readerStates[ri], knownState & ~SCARD_STATE_IGNORE);
|
||
|
+ if(readerNames && readerNameExistsInList(curReaderName,&readerNames)) {
|
||
|
+ CKYReader_SetKnownState(&readerStates[ri],
|
||
|
+ knownState & ~SCARD_STATE_IGNORE);
|
||
|
} else {
|
||
|
- if (!(knownState & SCARD_STATE_UNAVAILABLE))
|
||
|
- CKYReader_SetKnownState(&readerStates[ri], knownState | SCARD_STATE_UNAVAILABLE | SCARD_STATE_CHANGED);
|
||
|
- }
|
||
|
+ if (!(knownState & SCARD_STATE_UNAVAILABLE))
|
||
|
+ CKYReader_SetKnownState(&readerStates[ri],
|
||
|
+ knownState | SCARD_STATE_UNAVAILABLE | SCARD_STATE_CHANGED);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
+ if (readerNames == NULL) {
|
||
|
+ /* OK we've marked everything unavailable, we clearly
|
||
|
+ * aren't adding any readers, so we can blow out here */
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
const char *newReadersData[MAX_READER_DELTA];
|
||
|
const char **newReaders = &newReadersData[0];
|
||
|
unsigned int newReaderCount = 0;
|
||
|
@@ -370,7 +407,8 @@ Slot::Slot(const char *readerName_, Log
|
||
|
: log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
|
||
|
slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN),
|
||
|
isVersion1Key(false), needLogin(false), fullTokenName(false),
|
||
|
- mCoolkey(false), mOldCAC(false),
|
||
|
+ mCoolkey(false), mOldCAC(false),mCACLocalLogin(false),
|
||
|
+ pivContainer(-1), pivKey(-1), mECC(false),
|
||
|
#ifdef USE_SHMEM
|
||
|
shmem(readerName_),
|
||
|
#endif
|
||
|
@@ -573,6 +611,35 @@ SlotList::getSlotList(CK_BBOOL tokenPres
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
+bool
|
||
|
+Slot::getPIVLoginType(void)
|
||
|
+{
|
||
|
+ CKYStatus status;
|
||
|
+ CKYISOStatus apduRC;
|
||
|
+ CKYBuffer buffer;
|
||
|
+ bool local = true;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&buffer);
|
||
|
+
|
||
|
+ /* get the discovery object */
|
||
|
+ status = PIVApplet_GetCertificate(conn, &buffer, 0x7e, &apduRC);
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ /* Discovery object optional, PIV defaults to local */
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ /* techically we probably should parse out the TLVs, but the PIV
|
||
|
+ * specifies exactly what they should be, so we know exactly which
|
||
|
+ * byte to look at */
|
||
|
+ if ((CKYBuffer_Size(&buffer) >= 20) &&
|
||
|
+ (CKYBuffer_GetChar(&buffer,17) == 0x60)) {
|
||
|
+ /* This tells us we should use global login for this piv card */
|
||
|
+ local = false;
|
||
|
+ }
|
||
|
+done:
|
||
|
+ CKYBuffer_FreeData(&buffer);
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
Slot::connectToToken()
|
||
|
{
|
||
|
@@ -587,6 +654,7 @@ Slot::connectToToken()
|
||
|
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);
|
||
|
@@ -672,12 +740,36 @@ Slot::connectToToken()
|
||
|
// see if the applet is selectable
|
||
|
|
||
|
log->log("time connnect: Begin transaction %d ms\n", OSTimeNow() - time);
|
||
|
+ status = PIVApplet_Select(conn, NULL);
|
||
|
+ if (status == CKYSUCCESS) {
|
||
|
+ /* CARD is a PIV card */
|
||
|
+ state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
|
||
|
+ isVersion1Key = 0;
|
||
|
+ needLogin = 1;
|
||
|
+ mCoolkey = 0;
|
||
|
+ mOldCAC = 0;
|
||
|
+ mCACLocalLogin = getPIVLoginType();
|
||
|
+ return;
|
||
|
+ }
|
||
|
status = CKYApplet_SelectCoolKeyManager(conn, NULL);
|
||
|
if (status != CKYSUCCESS) {
|
||
|
log->log("CoolKey Select failed 0x%x\n", status);
|
||
|
status = getCACAid();
|
||
|
if (status != CKYSUCCESS) {
|
||
|
- goto loser;
|
||
|
+ log->log("CAC Select failed 0x%x\n", status);
|
||
|
+ if (status == CKYSCARDERR) {
|
||
|
+ log->log("Card Failure 0x%x\n",
|
||
|
+ CKYCardConnection_GetLastError(conn));
|
||
|
+ disconnect();
|
||
|
+ }
|
||
|
+ /* CARD is a PIV card */
|
||
|
+ state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
|
||
|
+ isVersion1Key = 0;
|
||
|
+ needLogin = 1;
|
||
|
+ mCoolkey = 0;
|
||
|
+ mOldCAC = 0;
|
||
|
+ mCACLocalLogin = getPIVLoginType();
|
||
|
+ return;
|
||
|
}
|
||
|
state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
|
||
|
/* skip the read of the cuid. We really don't need it and,
|
||
|
@@ -687,15 +779,7 @@ Slot::connectToToken()
|
||
|
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();
|
||
|
- }
|
||
|
+ mCACLocalLogin = false;
|
||
|
return;
|
||
|
}
|
||
|
mCoolkey = 1;
|
||
|
@@ -762,8 +846,8 @@ Slot::invalidateLogin(bool hard)
|
||
|
}
|
||
|
} else {
|
||
|
loggedIn = false;
|
||
|
+ pinCache.invalidate();
|
||
|
if (hard) {
|
||
|
- pinCache.invalidate();
|
||
|
pinCache.clearPin();
|
||
|
}
|
||
|
}
|
||
|
@@ -1202,6 +1286,7 @@ Slot::getTokenInfo(CK_TOKEN_INFO_PTR pTo
|
||
|
|
||
|
|
||
|
return CKR_OK;
|
||
|
+
|
||
|
}
|
||
|
|
||
|
void
|
||
|
@@ -1222,7 +1307,16 @@ SlotList::waitForSlotEvent(CK_FLAGS flag
|
||
|
bool found = FALSE;
|
||
|
CKYStatus status;
|
||
|
SCARD_READERSTATE *myReaderStates = NULL;
|
||
|
+ static SCARD_READERSTATE pnp = { 0 };
|
||
|
unsigned int myNumReaders = 0;
|
||
|
+
|
||
|
+ readerListLock.getLock();
|
||
|
+ if (pnp.szReader == 0) {
|
||
|
+ CKYReader_Init(&pnp);
|
||
|
+ pnp.szReader = "\\\\?PnP?\\Notification";
|
||
|
+ }
|
||
|
+ readerListLock.releaseLock();
|
||
|
+
|
||
|
#ifndef notdef
|
||
|
do {
|
||
|
readerListLock.getLock();
|
||
|
@@ -1241,11 +1335,13 @@ SlotList::waitForSlotEvent(CK_FLAGS flag
|
||
|
* from that set to return
|
||
|
*/
|
||
|
for (i=0; i < numReaders; i++) {
|
||
|
- unsigned long knownState = CKYReader_GetKnownState(&readerStates[i]);
|
||
|
+ unsigned long knownState =
|
||
|
+ CKYReader_GetKnownState(&readerStates[i]);
|
||
|
|
||
|
if ((knownState & SCARD_STATE_UNAVAILABLE) &&
|
||
|
(knownState & SCARD_STATE_CHANGED)) {
|
||
|
- CKYReader_SetKnownState(&readerStates[i], knownState & ~SCARD_STATE_CHANGED);
|
||
|
+ CKYReader_SetKnownState(&readerStates[i],
|
||
|
+ knownState & ~SCARD_STATE_CHANGED);
|
||
|
readerListLock.releaseLock();
|
||
|
*slotp = slotIndexToID(i);
|
||
|
found = TRUE;
|
||
|
@@ -1262,31 +1358,48 @@ SlotList::waitForSlotEvent(CK_FLAGS flag
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- if (myNumReaders != numReaders) {
|
||
|
+ if (myNumReaders != numReaders + 1) {
|
||
|
if (myReaderStates) {
|
||
|
delete [] myReaderStates;
|
||
|
}
|
||
|
- myReaderStates = new SCARD_READERSTATE [numReaders];
|
||
|
+ myReaderStates = new SCARD_READERSTATE [numReaders + 1];
|
||
|
+ myNumReaders = numReaders + 1;
|
||
|
}
|
||
|
- memcpy(myReaderStates, readerStates,
|
||
|
- sizeof(SCARD_READERSTATE)*numReaders);
|
||
|
- myNumReaders = numReaders;
|
||
|
+
|
||
|
+ memcpy(myReaderStates, readerStates,
|
||
|
+ sizeof(SCARD_READERSTATE) * numReaders);
|
||
|
+ memcpy(&myReaderStates[numReaders], &pnp, sizeof(pnp));
|
||
|
readerListLock.releaseLock();
|
||
|
status = CKYCardContext_WaitForStatusChange(context,
|
||
|
- myReaderStates, myNumReaders, timeout);
|
||
|
+ myReaderStates, myNumReaders, timeout);
|
||
|
if (status == CKYSUCCESS) {
|
||
|
- for (i=0; i < myNumReaders; i++) {
|
||
|
- SCARD_READERSTATE *rsp = &myReaderStates[i];
|
||
|
- unsigned long eventState = CKYReader_GetEventState(rsp);
|
||
|
+ unsigned long eventState;
|
||
|
+ for (i=0; i < myNumReaders - 1; i++) {
|
||
|
+ eventState = CKYReader_GetEventState(&myReaderStates[i]);
|
||
|
if (eventState & SCARD_STATE_CHANGED) {
|
||
|
readerListLock.getLock();
|
||
|
- CKYReader_SetKnownState(&readerStates[i], eventState & ~SCARD_STATE_CHANGED);
|
||
|
+ CKYReader_SetKnownState(&readerStates[i],
|
||
|
+ eventState & ~SCARD_STATE_CHANGED);
|
||
|
readerListLock.releaseLock();
|
||
|
*slotp = slotIndexToID(i);
|
||
|
found = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
+ /* No real need to check for an additional card, we already update
|
||
|
+ * the list when we iterate. */
|
||
|
+ if (!found) {
|
||
|
+ eventState = CKYReader_GetEventState(
|
||
|
+ &myReaderStates[myNumReaders-1]);
|
||
|
+ if (eventState & SCARD_STATE_CHANGED) {
|
||
|
+ readerListLock.getLock();
|
||
|
+ CKYReader_SetKnownState(&pnp,
|
||
|
+ eventState & ~SCARD_STATE_CHANGED);
|
||
|
+ readerListLock.releaseLock();
|
||
|
+ log->log("Reader insertion/removal detected\n");
|
||
|
+ continue; /* get the update */
|
||
|
+ }
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (found || (flag == CKF_DONT_BLOCK) || shuttingDown) {
|
||
|
@@ -1294,21 +1407,20 @@ SlotList::waitForSlotEvent(CK_FLAGS flag
|
||
|
}
|
||
|
|
||
|
#ifndef WIN32
|
||
|
- if (status != CKYSUCCESS) {
|
||
|
-
|
||
|
- if ( (CKYCardContext_GetLastError(context) ==
|
||
|
- SCARD_E_READER_UNAVAILABLE) ||
|
||
|
- (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT))
|
||
|
- {
|
||
|
- OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
|
||
|
- }
|
||
|
-
|
||
|
-
|
||
|
- }
|
||
|
+ /* pcsc-lite needs to make progress or something */
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ if ((CKYCardContext_GetLastError(context) ==
|
||
|
+ SCARD_E_READER_UNAVAILABLE) ||
|
||
|
+ (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT)) {
|
||
|
+ OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
|
||
|
+ }
|
||
|
+ }
|
||
|
#endif
|
||
|
} while ((status == CKYSUCCESS) ||
|
||
|
(CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) ||
|
||
|
- ( CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE));
|
||
|
+ (CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE) ||
|
||
|
+ (CKYCardContext_GetLastError(context) == SCARD_E_NO_SERVICE) ||
|
||
|
+ (CKYCardContext_GetLastError(context) == SCARD_E_SERVICE_STOPPED) );
|
||
|
#else
|
||
|
do {
|
||
|
OSSleep(100);
|
||
|
@@ -1345,6 +1457,7 @@ Slot::handleConnectionError()
|
||
|
case SCARD_W_REMOVED_CARD:
|
||
|
ckrv = CKR_DEVICE_REMOVED;
|
||
|
break;
|
||
|
+
|
||
|
default:
|
||
|
ckrv = CKR_DEVICE_ERROR;
|
||
|
break;
|
||
|
@@ -1404,13 +1517,46 @@ Slot::selectApplet()
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-Slot::selectCACApplet(CKYByte instance)
|
||
|
+Slot::selectCACApplet(CKYByte instance, bool doDisconnect)
|
||
|
{
|
||
|
CKYStatus status;
|
||
|
+ /* PIV containers and keys by instance */
|
||
|
+ static const int container[] = {
|
||
|
+ 0x5fc105, 0x5fc10a, 0x5fc10b, 0x5fc101,
|
||
|
+ 0x5fc10d, 0x5fc10e, 0x5fc10f, 0x5fc110,
|
||
|
+ 0x5fc111, 0x5fc112, 0x5fc113, 0x5fc114,
|
||
|
+ 0x5fc115, 0x5fc116, 0x5fc117, 0x5fc118,
|
||
|
+ 0x5fc119, 0x5fc11a, 0x5fc11b, 0x5fc11c,
|
||
|
+ 0x5fc11d, 0x5fc11e, 0x5fc11f, 0x5fc120
|
||
|
+ };
|
||
|
+ static const int keyRef[] = {
|
||
|
+ 0x9a, 0x9c, 0x9d, 0x9e,
|
||
|
+ 0x82, 0x83, 0x84, 0x85,
|
||
|
+ 0x86, 0x87, 0x88, 0x89,
|
||
|
+ 0x8a, 0x8b, 0x8c, 0x8d,
|
||
|
+ 0x8e, 0x8f, 0x90, 0x91,
|
||
|
+ 0x92, 0x93, 0x94, 0x95
|
||
|
+ };
|
||
|
+
|
||
|
+ if (state & PIV_CARD) {
|
||
|
+ status = PIVApplet_Select(conn, NULL);
|
||
|
+ if (status == CKYSCARDERR) handleConnectionError();
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ if (doDisconnect) {
|
||
|
+ disconnect();
|
||
|
+ }
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
|
||
|
+ }
|
||
|
+ pivContainer = container[instance];
|
||
|
+ pivKey = keyRef[instance];
|
||
|
+ return;
|
||
|
+ }
|
||
|
CKYBuffer *aid = &cardAID[instance];
|
||
|
|
||
|
if (CKYBuffer_Size(aid) == 0) {
|
||
|
- disconnect();
|
||
|
+ if (doDisconnect) {
|
||
|
+ disconnect();
|
||
|
+ }
|
||
|
throw PKCS11Exception(CKR_DEVICE_REMOVED);
|
||
|
return;
|
||
|
}
|
||
|
@@ -1419,7 +1565,9 @@ Slot::selectCACApplet(CKYByte instance)
|
||
|
if ( status == CKYSCARDERR ) handleConnectionError();
|
||
|
if ( status != CKYSUCCESS) {
|
||
|
// could not select applet: this just means it's not there
|
||
|
- disconnect();
|
||
|
+ if (doDisconnect) {
|
||
|
+ disconnect();
|
||
|
+ }
|
||
|
throw PKCS11Exception(CKR_DEVICE_REMOVED);
|
||
|
}
|
||
|
if (mOldCAC) {
|
||
|
@@ -1428,7 +1576,9 @@ Slot::selectCACApplet(CKYByte instance)
|
||
|
status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
|
||
|
if ( status == CKYSCARDERR ) handleConnectionError();
|
||
|
if ( status != CKYSUCCESS) {
|
||
|
- disconnect();
|
||
|
+ if (doDisconnect) {
|
||
|
+ disconnect();
|
||
|
+ }
|
||
|
throw PKCS11Exception(CKR_DEVICE_REMOVED);
|
||
|
}
|
||
|
}
|
||
|
@@ -1521,6 +1671,29 @@ Slot::generateUnusedObjectHandle()
|
||
|
return handle;
|
||
|
}
|
||
|
|
||
|
+/* Create a short lived Secret Key for ECC key derive. */
|
||
|
+PKCS11Object *
|
||
|
+Slot::createSecretKeyObject(CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
|
||
|
+{
|
||
|
+
|
||
|
+ if (secretKeyBuffer == NULL ) {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Can't create secret key object for ECC.");
|
||
|
+ }
|
||
|
+
|
||
|
+ unsigned long muscleID = 0xfff;
|
||
|
+ PKCS11Object *secret = new SecretKey(muscleID, handle, secretKeyBuffer, pTemplate, ulAttributeCount);
|
||
|
+
|
||
|
+ if (secret == NULL) {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Can't create secret key object for ECC.");
|
||
|
+ }
|
||
|
+
|
||
|
+ tokenObjects.push_back(*secret);
|
||
|
+
|
||
|
+ return secret;
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
Slot::addKeyObject(list<PKCS11Object>& objectList, const ListObjectInfo& info,
|
||
|
CK_OBJECT_HANDLE handle, bool isCombined)
|
||
|
@@ -1530,24 +1703,32 @@ Slot::addKeyObject(list<PKCS11Object>& o
|
||
|
CK_OBJECT_CLASS objClass = keyObj.getClass();
|
||
|
const CKYBuffer *id;
|
||
|
|
||
|
-
|
||
|
if (isCombined &&
|
||
|
- ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
|
||
|
- id = keyObj.getAttribute(CKA_ID);
|
||
|
- if ((!id) || (CKYBuffer_Size(id) != 1)) {
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Missing or invalid CKA_ID value");
|
||
|
- }
|
||
|
- iter = find_if(objectList.begin(), objectList.end(),
|
||
|
- ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
|
||
|
- if ( iter == objectList.end() ) {
|
||
|
+ ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
|
||
|
+ id = keyObj.getAttribute(CKA_ID);
|
||
|
+ if ((!id) || (CKYBuffer_Size(id) != 1)) {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Missing or invalid CKA_ID value");
|
||
|
+ }
|
||
|
+ iter = find_if(objectList.begin(), objectList.end(),
|
||
|
+ ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
|
||
|
+ if ( iter == objectList.end() ) {
|
||
|
// We failed to find a cert with a matching CKA_ID. This
|
||
|
// can happen if the cert is not present on the token, or
|
||
|
// the der encoded cert stored on the token was corrupted.
|
||
|
- throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Failed to find cert with matching CKA_ID value");
|
||
|
- }
|
||
|
- keyObj.completeKey(*iter);
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
+ "Failed to find cert with matching CKA_ID value");
|
||
|
+ }
|
||
|
+ keyObj.completeKey(*iter);
|
||
|
+
|
||
|
+ /* For now this is how we determine what type of key.
|
||
|
+ Also for now, allow only one or the other */
|
||
|
+ if ( keyObj.getKeyType() == PKCS11Object::ecc) {
|
||
|
+ mECC = true;
|
||
|
+ } else {
|
||
|
+ mECC = false;
|
||
|
+ }
|
||
|
+
|
||
|
}
|
||
|
objectList.push_back(keyObj);
|
||
|
|
||
|
@@ -1577,6 +1758,7 @@ Slot::addCertObject(list<PKCS11Object>&
|
||
|
void
|
||
|
Slot::unloadObjects()
|
||
|
{
|
||
|
+ mECC = false;
|
||
|
tokenObjects.clear();
|
||
|
free(personName);
|
||
|
personName = NULL;
|
||
|
@@ -1970,7 +2152,7 @@ Slot::readCUID(void)
|
||
|
// shared memory is protected by our transaction call on the card
|
||
|
//
|
||
|
CKYStatus status;
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
status = CACApplet_SelectCardManager(conn, NULL);
|
||
|
} else {
|
||
|
status = CKYApplet_SelectCardManager(conn, NULL);
|
||
|
@@ -2203,6 +2385,50 @@ Slot::fetchCombinedObjects(const CKYBuff
|
||
|
return objInfoList;
|
||
|
}
|
||
|
|
||
|
+typedef enum {
|
||
|
+ BER_UNWRAP,
|
||
|
+ BER_NEXT
|
||
|
+} BERop;
|
||
|
+
|
||
|
+static CKYStatus
|
||
|
+berProcess(CKYBuffer *buf, int matchTag, CKYBuffer *target, BERop type)
|
||
|
+{
|
||
|
+ unsigned char tag;
|
||
|
+ unsigned int used_length= 0;
|
||
|
+ unsigned int data_length;
|
||
|
+
|
||
|
+ tag = CKYBuffer_GetChar(buf,used_length++);
|
||
|
+
|
||
|
+ /* blow out when we come to the end */
|
||
|
+ if (matchTag && tag != matchTag) {
|
||
|
+ return CKYLIBFAIL;
|
||
|
+ }
|
||
|
+
|
||
|
+ data_length = CKYBuffer_GetChar(buf,used_length++);
|
||
|
+
|
||
|
+ if (data_length & 0x80) {
|
||
|
+ int len_count = data_length & 0x7f;
|
||
|
+
|
||
|
+ data_length = 0;
|
||
|
+
|
||
|
+ while (len_count-- > 0) {
|
||
|
+ data_length = (data_length << 8) |
|
||
|
+ CKYBuffer_GetChar(buf,used_length++);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (data_length > (CKYBuffer_Size(buf)-used_length) ) {
|
||
|
+ return CKYLIBFAIL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (type == BER_UNWRAP) {
|
||
|
+ return CKYBuffer_AppendBuffer(target, buf, used_length, data_length);
|
||
|
+ }
|
||
|
+ return CKYBuffer_AppendBuffer(target, buf, used_length+data_length,
|
||
|
+ CKYBuffer_Size(buf)-(used_length+data_length));
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
CKYStatus
|
||
|
Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize,
|
||
|
bool throwException)
|
||
|
@@ -2211,16 +2437,60 @@ Slot::readCACCertificateFirst(CKYBuffer
|
||
|
CKYISOStatus apduRC;
|
||
|
*nextSize = 0;
|
||
|
|
||
|
+ if (state & PIV_CARD) {
|
||
|
+ CKYBuffer pivData;
|
||
|
+ CKYBuffer certInfo;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&pivData);
|
||
|
+ 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) {
|
||
|
+ status = berProcess(cert, 0x53, &pivData, BER_UNWRAP);
|
||
|
+ CKYBuffer_Resize(cert, 0);
|
||
|
+ CKYBuffer_AppendChar(cert,0);
|
||
|
+ do {
|
||
|
+ CKYByte tag = CKYBuffer_GetChar(&pivData,0);
|
||
|
+ if (tag == CAC_TAG_CERTIFICATE) {
|
||
|
+ status = berProcess(&pivData, CAC_TAG_CERTIFICATE,
|
||
|
+ cert, BER_UNWRAP);
|
||
|
+ }
|
||
|
+ if (tag == CAC_TAG_CERTINFO) {
|
||
|
+ CKYBuffer_Resize(&certInfo, 0);
|
||
|
+ status = berProcess(&pivData, CAC_TAG_CERTINFO,
|
||
|
+ &certInfo, BER_UNWRAP);
|
||
|
+ if (CKYBuffer_Size(&certInfo) == 1) {
|
||
|
+ CKYBuffer_SetChar(cert,0,
|
||
|
+ CKYBuffer_GetChar(&certInfo,0));
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (status == CKYSUCCESS) {
|
||
|
+ CKYBuffer_Resize(&certInfo, 0);
|
||
|
+ status = berProcess(&pivData, 0, &certInfo, BER_NEXT);
|
||
|
+ if (status == CKYSUCCESS) {
|
||
|
+ CKYBuffer_Resize(&pivData,0);
|
||
|
+ status = CKYBuffer_AppendCopy(&pivData,&certInfo);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ } while ((status == CKYSUCCESS) && (CKYBuffer_Size(&pivData) != 0));
|
||
|
+ CKYBuffer_FreeData(&pivData);
|
||
|
+ CKYBuffer_FreeData(&certInfo);
|
||
|
+ }
|
||
|
+
|
||
|
+ return status;
|
||
|
+ }
|
||
|
+
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
@@ -2233,6 +2503,7 @@ Slot::readCACCertificateFirst(CKYBuffer
|
||
|
CKYBuffer_InitEmpty(&tBuf);
|
||
|
CKYBuffer_InitEmpty(&vBuf);
|
||
|
CKYBuffer_Resize(cert, 0);
|
||
|
+ CKYBuffer_AppendChar(cert,0);
|
||
|
|
||
|
/* handle the new CAC card read */
|
||
|
/* read the TLV */
|
||
|
@@ -2258,11 +2529,12 @@ Slot::readCACCertificateFirst(CKYBuffer
|
||
|
length = CKYBuffer_GetShortLE(&tBuf, toffset);
|
||
|
toffset +=2;
|
||
|
}
|
||
|
- if (tag != CAC_TAG_CERTIFICATE) {
|
||
|
- continue;
|
||
|
+ if (tag == CAC_TAG_CERTIFICATE) {
|
||
|
+ CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
|
||
|
+ }
|
||
|
+ if (tag == CAC_TAG_CERTINFO) {
|
||
|
+ CKYBuffer_SetChar(cert,0,CKYBuffer_GetChar(&vBuf,voffset));
|
||
|
}
|
||
|
- CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
|
||
|
- break;
|
||
|
}
|
||
|
status = CKYSUCCESS;
|
||
|
|
||
|
@@ -2272,6 +2544,191 @@ done:
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+const static unsigned long crc_table[] = {
|
||
|
+0x00000000,0x77073096,0xee0e612c,0x990951ba,
|
||
|
+0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
|
||
|
+0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,
|
||
|
+0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
|
||
|
+0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,
|
||
|
+0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
|
||
|
+0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,
|
||
|
+0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
|
||
|
+0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
|
||
|
+0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
|
||
|
+0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,
|
||
|
+0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
|
||
|
+0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,
|
||
|
+0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
|
||
|
+0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,
|
||
|
+0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
|
||
|
+0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,
|
||
|
+0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
|
||
|
+0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,
|
||
|
+0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
|
||
|
+0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
|
||
|
+0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
|
||
|
+0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,
|
||
|
+0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
|
||
|
+0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,
|
||
|
+0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
|
||
|
+0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
|
||
|
+0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
|
||
|
+0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,
|
||
|
+0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
|
||
|
+0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,
|
||
|
+0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
|
||
|
+0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,
|
||
|
+0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
|
||
|
+0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,
|
||
|
+0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
|
||
|
+0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,
|
||
|
+0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
|
||
|
+0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,
|
||
|
+0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
|
||
|
+0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,
|
||
|
+0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
|
||
|
+0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,
|
||
|
+0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
|
||
|
+0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
|
||
|
+0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
|
||
|
+0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,
|
||
|
+0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
|
||
|
+0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,
|
||
|
+0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
|
||
|
+0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,
|
||
|
+0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
|
||
|
+0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,
|
||
|
+0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
|
||
|
+0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,
|
||
|
+0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
|
||
|
+0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,
|
||
|
+0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
|
||
|
+0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,
|
||
|
+0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
|
||
|
+0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,
|
||
|
+0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
|
||
|
+0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
|
||
|
+0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
|
||
|
+};
|
||
|
+
|
||
|
+static unsigned long
|
||
|
+calc_crc32(const unsigned char *buf, int len)
|
||
|
+{
|
||
|
+ unsigned long crc = 0xffffffff;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i=0; i < len; i++) {
|
||
|
+ unsigned char crc_low = crc & 0xff;
|
||
|
+ unsigned long crc_high = crc >> 8;
|
||
|
+ crc = crc_table[crc_low ^ buf[i]] ^ crc_high;
|
||
|
+ }
|
||
|
+ return crc ^ 0xffffffff;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * decompress, handles both gzip and zlib trailers
|
||
|
+ * it also automatically allocates the output buffer and expands it as
|
||
|
+ * necessary.
|
||
|
+ */
|
||
|
+static int
|
||
|
+decompress(CKYBuffer *out,
|
||
|
+ CKYBuffer *in, CKYOffset offset, CKYSize len)
|
||
|
+{
|
||
|
+ int zret;
|
||
|
+ CKYStatus status;
|
||
|
+ z_stream stream;
|
||
|
+ int chunk = len *2;
|
||
|
+ int outlen = 0;
|
||
|
+
|
||
|
+
|
||
|
+ /* allocate inflate state */
|
||
|
+ stream.zalloc = Z_NULL;
|
||
|
+ stream.zfree = Z_NULL;
|
||
|
+ stream.opaque = Z_NULL;
|
||
|
+ stream.avail_in = 0;
|
||
|
+ stream.next_in = Z_NULL;
|
||
|
+ zret = inflateInit(&stream);
|
||
|
+ if (zret != Z_OK)
|
||
|
+ return zret;
|
||
|
+
|
||
|
+ status = CKYBuffer_Reserve(out, outlen);
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ return Z_MEM_ERROR;
|
||
|
+ }
|
||
|
+
|
||
|
+ stream.avail_in = len;
|
||
|
+ stream.next_in = (Bytef *)(CKYBuffer_Data(in) + offset);
|
||
|
+
|
||
|
+ do {
|
||
|
+ CKYBuffer_Resize(out, outlen + chunk);
|
||
|
+ stream.avail_out = chunk;
|
||
|
+
|
||
|
+ stream.next_out = (Bytef *)CKYBuffer_Data(out)+ outlen;
|
||
|
+
|
||
|
+ zret= inflate(&stream, Z_NO_FLUSH);
|
||
|
+
|
||
|
+ /* we need the length early so it can be used in error processing */
|
||
|
+ outlen += chunk - stream.avail_out;
|
||
|
+
|
||
|
+ /* proccess the error codes */
|
||
|
+ switch (zret) {
|
||
|
+ case Z_DATA_ERROR:
|
||
|
+ /* a DATA error can occur on either corrupted data, or on gzip.
|
||
|
+ * data. This is because gzip uses CRC32 and zlib used ADLER32
|
||
|
+ * checksums. We need to check to see if this failure is do to
|
||
|
+ * a gzip header. */
|
||
|
+ /* 1) a gzip header includes 4 extra bytes containing the length
|
||
|
+ * of the gziped data. This means there must be 4 more bytes
|
||
|
+ * in our input buffer that have not been processed */
|
||
|
+ if (stream.avail_in != 4) {
|
||
|
+ break; /* not a gzip header */
|
||
|
+ }
|
||
|
+ /* The last 4 bytes of a gzip header include the uncompressed length
|
||
|
+ * modulo 2^32. Make sure the actual uncompressed length matches
|
||
|
+ * the header. */
|
||
|
+ if ((outlen & 0xffffffffL)
|
||
|
+ != CKYBuffer_GetLongLE(in, offset+len-4)) {
|
||
|
+ break; /* didn't decode the full length */
|
||
|
+ }
|
||
|
+ /* At this point it''s pretty likely we have a gzip trailer. Verify
|
||
|
+ * the crc32 values to make sure there hasn't been any corruption.
|
||
|
+ */
|
||
|
+ if (calc_crc32(CKYBuffer_Data(out), outlen) !=
|
||
|
+ CKYBuffer_GetLongLE(in,offset+len-8)) {
|
||
|
+ break; /* CRC didn't match */
|
||
|
+ }
|
||
|
+ /* This was valid gzip data, and we've successfully uncompressed
|
||
|
+ * it. We're now done. */
|
||
|
+ zret=Z_STREAM_END;
|
||
|
+ break;
|
||
|
+ case Z_NEED_DICT:
|
||
|
+ /* if we need the dict, it wasn't in the data,
|
||
|
+ * so it's a data error */
|
||
|
+ zret = Z_DATA_ERROR;
|
||
|
+ break;
|
||
|
+ case Z_OK:
|
||
|
+ /* Z_OK means we need more data, expand the buffer and go again.
|
||
|
+ * if we don't need more buffer space, then the input must have
|
||
|
+ * been truncated, that's a data error */
|
||
|
+ if (stream.avail_out != 0) {
|
||
|
+ zret = Z_DATA_ERROR;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ } while (zret == Z_OK);
|
||
|
+
|
||
|
+ /* cleanup */
|
||
|
+ if (zret == Z_STREAM_END) {
|
||
|
+ zret = Z_OK;
|
||
|
+ CKYBuffer_Resize(out, outlen);
|
||
|
+ } else {
|
||
|
+ CKYBuffer_Resize(out, 0);
|
||
|
+ }
|
||
|
+ (void)inflateEnd(&stream);
|
||
|
+ return zret;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* only necessary for old CAC cards. New CAC cards have to read the
|
||
|
* whole cert in anyway above....
|
||
|
@@ -2304,7 +2761,7 @@ Slot::loadCACCert(CKYByte instance)
|
||
|
// catch the applet selection errors if they don't
|
||
|
//
|
||
|
try {
|
||
|
- selectCACApplet(instance);
|
||
|
+ selectCACApplet(instance, false);
|
||
|
} catch(PKCS11Exception& e) {
|
||
|
// all CAC's must have instance '0', throw the error it
|
||
|
// they don't.
|
||
|
@@ -2322,6 +2779,10 @@ Slot::loadCACCert(CKYByte instance)
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
@@ -2364,7 +2825,7 @@ Slot::loadCACCert(CKYByte instance)
|
||
|
} else {
|
||
|
status = readCACCertificateFirst(&rawCert, &nextSize, false);
|
||
|
|
||
|
- if (status != CKYSUCCESS) {
|
||
|
+ 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) {
|
||
|
@@ -2393,31 +2854,61 @@ Slot::loadCACCert(CKYByte instance)
|
||
|
|
||
|
log->log("CAC Cert %d: Cert has been read: %d ms\n",
|
||
|
instance, OSTimeNow() - time);
|
||
|
- if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) {
|
||
|
- CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
|
||
|
- CKYSize certSize = 0;
|
||
|
- CKYOffset offset = mOldCAC ? 1 : 0;
|
||
|
+ /* new CACs, and old CACs with the high one bit are compressed,
|
||
|
+ * uncompress them */
|
||
|
+ if ((CKYBuffer_GetChar(&rawCert,0) & 0x3) == 1) {
|
||
|
+ CKYOffset offset = 1;
|
||
|
int zret = Z_MEM_ERROR;
|
||
|
|
||
|
- do {
|
||
|
- guessFinalSize *= 2;
|
||
|
- status = CKYBuffer_Resize(&cert, guessFinalSize);
|
||
|
- if (status != CKYSUCCESS) {
|
||
|
- break;
|
||
|
+ /* process the GZIP header if present */
|
||
|
+ /* header_id = 0x1f, 0x8b. CM=8. If we ever support something other
|
||
|
+ * than CM=8, we need to change the zlib header below. Currently both
|
||
|
+ * gzip and zlib only support CM=8 (DEFLATE) compression */
|
||
|
+ if ((CKYBuffer_GetChar(&rawCert,1) == 0x1f) &&
|
||
|
+ (CKYBuffer_GetChar(&rawCert,2) == 0x8b) &&
|
||
|
+ (CKYBuffer_GetChar(&rawCert,3) == 8)) {
|
||
|
+ CKYByte flags = CKYBuffer_GetChar(&rawCert,4);
|
||
|
+ /* this has a gzip header, not raw data. */
|
||
|
+ offset += 10; /* base size of the gzip header */
|
||
|
+ if (flags & 4) { /* FEXTRA */
|
||
|
+ CKYSize len = CKYBuffer_GetShortLE(&rawCert,offset);
|
||
|
+ offset += len;
|
||
|
}
|
||
|
- certSize = guessFinalSize;
|
||
|
- zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
|
||
|
- CKYBuffer_Data(&rawCert)+offset,
|
||
|
- CKYBuffer_Size(&rawCert)-offset);
|
||
|
- } while (zret == Z_BUF_ERROR);
|
||
|
+ if (flags & 8) { /* FNAME */
|
||
|
+ while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
|
||
|
+ offset++;
|
||
|
+ }
|
||
|
+ offset++;
|
||
|
+ }
|
||
|
+ if (flags & 0x10) { /* FComment */
|
||
|
+ while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
|
||
|
+ offset++;
|
||
|
+ }
|
||
|
+ offset++;
|
||
|
+ }
|
||
|
+ if (flags & 2) { /* FHCRC */
|
||
|
+ offset += 2;
|
||
|
+ }
|
||
|
+ offset -= 2;
|
||
|
+
|
||
|
+ /* add zlib header, so libz will be happy */
|
||
|
+ /* CINFO=7, CM=8, LEVEL=2, DICTFLAG=0, FCHECK= 1c */
|
||
|
+ /* NOTE: the zlib will fail when procssing the trailer. this is
|
||
|
+ * ok because decompress automatically notices the failure and
|
||
|
+ * and checks the gzip trailer. */
|
||
|
+ CKYBuffer_SetChar(&rawCert, offset, 0x78);
|
||
|
+ CKYBuffer_SetChar(&rawCert, offset+1, 0x9c);
|
||
|
+ }
|
||
|
+ /* uncompress. This expands cert as necessary. */
|
||
|
+ zret = decompress(&cert, &rawCert, offset,
|
||
|
+ CKYBuffer_Size(&rawCert)-offset);
|
||
|
|
||
|
if (zret != Z_OK) {
|
||
|
CKYBuffer_FreeData(&rawCert);
|
||
|
CKYBuffer_FreeData(&cert);
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR,
|
||
|
- "Corrupted compressed CAC Cert");
|
||
|
+ "Corrupted compressed CAC/PIV Cert");
|
||
|
}
|
||
|
- CKYBuffer_Resize(&cert,certSize);
|
||
|
} else {
|
||
|
CKYBuffer_InitFromBuffer(&cert,&rawCert,1,CKYBuffer_Size(&rawCert)-1);
|
||
|
}
|
||
|
@@ -2431,6 +2922,9 @@ Slot::loadCACCert(CKYByte instance)
|
||
|
tokenObjects.push_back(privKey);
|
||
|
tokenObjects.push_back(pubKey);
|
||
|
tokenObjects.push_back(certObj);
|
||
|
+ if ( pubKey.getKeyType() == PKCS11Object::ecc) {
|
||
|
+ mECC = 1;
|
||
|
+ }
|
||
|
|
||
|
if (personName == NULL) {
|
||
|
const char *name = certObj.getName();
|
||
|
@@ -2459,7 +2953,7 @@ Slot::loadObjects()
|
||
|
list<ListObjectInfo> objInfoList;
|
||
|
std::list<ListObjectInfo>::iterator iter;
|
||
|
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
loadCACCert(0);
|
||
|
loadCACCert(1);
|
||
|
loadCACCert(2);
|
||
|
@@ -2704,6 +3198,7 @@ Slot::login(SessionHandleSuffix handleSu
|
||
|
}
|
||
|
|
||
|
if (!isVersion1Key) {
|
||
|
+ pinCache.invalidate();
|
||
|
pinCache.set((const char *)pPin, ulPinLen);
|
||
|
} else if (nonceValid) {
|
||
|
throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN);
|
||
|
@@ -2713,15 +3208,15 @@ Slot::login(SessionHandleSuffix handleSu
|
||
|
CKYStatus status = trans.begin(conn);
|
||
|
if(status != CKYSUCCESS ) handleConnectionError();
|
||
|
|
||
|
- if (state & CAC_CARD) {
|
||
|
- selectCACApplet(0);
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ selectCACApplet(0, true);
|
||
|
} else {
|
||
|
selectApplet();
|
||
|
}
|
||
|
|
||
|
if (isVersion1Key) {
|
||
|
attemptLogin((const char *)pPin);
|
||
|
- } else if (state & CAC_CARD) {
|
||
|
+ } else if (state & GOV_CARD) {
|
||
|
attemptCACLogin();
|
||
|
} else {
|
||
|
oldAttemptLogin();
|
||
|
@@ -2738,7 +3233,8 @@ Slot::attemptCACLogin()
|
||
|
CKYISOStatus result;
|
||
|
|
||
|
status = CACApplet_VerifyPIN(conn,
|
||
|
- (const char *)CKYBuffer_Data(pinCache.get()), &result);
|
||
|
+ (const char *)CKYBuffer_Data(pinCache.get()),
|
||
|
+ mCACLocalLogin, &result);
|
||
|
if( status == CKYSCARDERR ) {
|
||
|
handleConnectionError();
|
||
|
}
|
||
|
@@ -2746,8 +3242,10 @@ Slot::attemptCACLogin()
|
||
|
case CKYISO_SUCCESS:
|
||
|
break;
|
||
|
case 0x6981:
|
||
|
+ pinCache.clearPin();
|
||
|
throw PKCS11Exception(CKR_PIN_LOCKED);
|
||
|
default:
|
||
|
+ pinCache.clearPin();
|
||
|
if ((result & 0xff00) == 0x6300) {
|
||
|
throw PKCS11Exception(CKR_PIN_INCORRECT);
|
||
|
}
|
||
|
@@ -2776,10 +3274,13 @@ Slot::oldAttemptLogin()
|
||
|
case CKYISO_SUCCESS:
|
||
|
break;
|
||
|
case CKYISO_AUTH_FAILED:
|
||
|
+ pinCache.clearPin();
|
||
|
throw PKCS11Exception(CKR_PIN_INCORRECT);
|
||
|
case CKYISO_IDENTITY_BLOCKED:
|
||
|
+ pinCache.clearPin();
|
||
|
throw PKCS11Exception(CKR_PIN_LOCKED);
|
||
|
default:
|
||
|
+ pinCache.clearPin();
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x",
|
||
|
result);
|
||
|
}
|
||
|
@@ -2866,7 +3367,7 @@ Slot::logout(SessionHandleSuffix suffix)
|
||
|
throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
}
|
||
|
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
CACLogout();
|
||
|
return;
|
||
|
}
|
||
|
@@ -2993,7 +3494,7 @@ Slot::getAttributeValue(SessionHandleSuf
|
||
|
ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
|
||
|
ObjectHandleMatch(hObject));
|
||
|
|
||
|
- if( iter == tokenObjects.end() ) {
|
||
|
+ if ( iter == tokenObjects.end()) {
|
||
|
throw PKCS11Exception(CKR_OBJECT_HANDLE_INVALID);
|
||
|
}
|
||
|
|
||
|
@@ -3077,6 +3578,21 @@ SlotList::generateRandom(CK_SESSION_HAND
|
||
|
}
|
||
|
|
||
|
void
|
||
|
+SlotList::derive(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
|
||
|
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
|
||
|
+{
|
||
|
+
|
||
|
+ CK_SLOT_ID slotID;
|
||
|
+ SessionHandleSuffix suffix;
|
||
|
+
|
||
|
+ decomposeSessionHandle(hSession, slotID, suffix);
|
||
|
+
|
||
|
+ slots[slotIDToIndex(slotID)]->derive(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey);
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
Slot::ensureValidSession(SessionHandleSuffix suffix)
|
||
|
{
|
||
|
if( ! isValidSession(suffix) ) {
|
||
|
@@ -3110,6 +3626,23 @@ Slot::objectHandleToKeyNum(CK_OBJECT_HAN
|
||
|
return keyNum & 0xFF;
|
||
|
}
|
||
|
|
||
|
+PKCS11Object::KeyType
|
||
|
+Slot::getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey)
|
||
|
+{
|
||
|
+ ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
|
||
|
+ ObjectHandleMatch(hKey));
|
||
|
+
|
||
|
+ if( iter == tokenObjects.end() ) {
|
||
|
+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
|
||
|
+ }
|
||
|
+
|
||
|
+ if( getObjectClass(iter->getMuscleObjID()) != 'k' ) {
|
||
|
+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
|
||
|
+ }
|
||
|
+
|
||
|
+ return iter->getKeyType();
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
Slot::signInit(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
|
||
|
CK_OBJECT_HANDLE hKey)
|
||
|
@@ -3119,7 +3652,10 @@ Slot::signInit(SessionHandleSuffix suffi
|
||
|
if( session == sessions.end() ) {
|
||
|
throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
}
|
||
|
- session->signatureState.initialize(objectHandleToKeyNum(hKey));
|
||
|
+
|
||
|
+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
|
||
|
+
|
||
|
+ session->signatureState.initialize(objectHandleToKeyNum(hKey), keyType);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
@@ -3131,7 +3667,10 @@ Slot::decryptInit(SessionHandleSuffix su
|
||
|
if( session == sessions.end() ) {
|
||
|
throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
}
|
||
|
- session->decryptionState.initialize(objectHandleToKeyNum(hKey));
|
||
|
+
|
||
|
+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
|
||
|
+
|
||
|
+ session->decryptionState.initialize(objectHandleToKeyNum(hKey), keyType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -3240,54 +3779,141 @@ stripRSAPadding(CKYBuffer *stripped, con
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-class RSASignatureParams : public CryptParams {
|
||
|
+class ECCKeyAgreementParams : public CryptParams {
|
||
|
public:
|
||
|
- RSASignatureParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
+ ECCKeyAgreementParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
|
||
|
- CKYByte getDirection() const { return CKY_DIR_ENCRYPT; }
|
||
|
+ CKYByte getDirection() const { return CKY_DIR_NONE;}
|
||
|
|
||
|
CryptOpState& getOpState(Session& session) const {
|
||
|
- return session.signatureState;
|
||
|
+ return session.keyAgreementState;
|
||
|
}
|
||
|
|
||
|
void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
|
||
|
- // RSA_NO_PAD requires RSA PKCS #1 Type 1 padding
|
||
|
- CKYStatus status = CKYBuffer_Resize(paddedInput,getKeySize()/8);
|
||
|
- if (status != CKYSUCCESS) {
|
||
|
- throw PKCS11Exception(CKR_HOST_MEMORY);
|
||
|
- }
|
||
|
- padRSAType1(unpaddedInput, paddedInput);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
|
||
|
- // no need to unpad ciphertext
|
||
|
- CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(paddedOutput),
|
||
|
- CKYBuffer_Size(paddedOutput));
|
||
|
-
|
||
|
+ return;
|
||
|
}
|
||
|
+
|
||
|
};
|
||
|
|
||
|
-class RSADecryptParams: public CryptParams {
|
||
|
+class SignatureParams : public CryptParams {
|
||
|
public:
|
||
|
- RSADecryptParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
+ SignatureParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
|
||
|
- CKYByte getDirection() const { return CKY_DIR_DECRYPT; }
|
||
|
+ CKYByte getDirection() const { return CKY_DIR_NONE; }
|
||
|
|
||
|
CryptOpState& getOpState(Session& session) const {
|
||
|
- return session.decryptionState;
|
||
|
+ return session.signatureState;
|
||
|
}
|
||
|
|
||
|
void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
|
||
|
- // no need to unpad ciphertext
|
||
|
- CKYBuffer_Replace(paddedInput, 0, CKYBuffer_Data(unpaddedInput),
|
||
|
- CKYBuffer_Size(unpaddedInput));
|
||
|
+ return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
|
||
|
- // strip off PKCS #1 padding
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+class ECCSignatureParams : public CryptParams {
|
||
|
+ public:
|
||
|
+ ECCSignatureParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
+
|
||
|
+ CKYByte getDirection() const { return CKY_DIR_NONE; }
|
||
|
+
|
||
|
+ CryptOpState& getOpState(Session& session) const {
|
||
|
+ return session.signatureState;
|
||
|
+ }
|
||
|
+
|
||
|
+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ void
|
||
|
+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
|
||
|
+ /* Here we will unpack the DER encoding of the signature */
|
||
|
+
|
||
|
+ if ( unpaddedOutput == NULL || paddedOutput == NULL) {
|
||
|
+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer rawSignature;
|
||
|
+ CKYBuffer_InitEmpty(&rawSignature);
|
||
|
+
|
||
|
+ DEREncodedSignature sig(paddedOutput);
|
||
|
+
|
||
|
+ int rv = sig.getRawSignature(&rawSignature, getKeySize() );
|
||
|
+
|
||
|
+ if (rv == CKYSUCCESS) {
|
||
|
+ CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(&rawSignature),
|
||
|
+ CKYBuffer_Size(&rawSignature));
|
||
|
+ } else {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR);
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_FreeData(&rawSignature);
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+
|
||
|
+class RSASignatureParams : public CryptParams {
|
||
|
+ public:
|
||
|
+ RSASignatureParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
+
|
||
|
+ CKYByte getDirection() const { return CKY_DIR_ENCRYPT; }
|
||
|
+
|
||
|
+ CryptOpState& getOpState(Session& session) const {
|
||
|
+ return session.signatureState;
|
||
|
+ }
|
||
|
+
|
||
|
+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
|
||
|
+ // RSA_NO_PAD requires RSA PKCS #1 Type 1 padding
|
||
|
+ CKYStatus status = CKYBuffer_Resize(paddedInput,getKeySize()/8);
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ throw PKCS11Exception(CKR_HOST_MEMORY);
|
||
|
+ }
|
||
|
+ padRSAType1(unpaddedInput, paddedInput);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ void
|
||
|
+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
|
||
|
+ // no need to unpad ciphertext
|
||
|
+ CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(paddedOutput),
|
||
|
+ CKYBuffer_Size(paddedOutput));
|
||
|
+
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+class RSADecryptParams: public CryptParams {
|
||
|
+ public:
|
||
|
+ RSADecryptParams(unsigned int keysize) : CryptParams(keysize) { }
|
||
|
+
|
||
|
+ CKYByte getDirection() const { return CKY_DIR_DECRYPT; }
|
||
|
+
|
||
|
+ CryptOpState& getOpState(Session& session) const {
|
||
|
+ return session.decryptionState;
|
||
|
+ }
|
||
|
+
|
||
|
+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
|
||
|
+ // no need to unpad ciphertext
|
||
|
+ CKYBuffer_Replace(paddedInput, 0, CKYBuffer_Data(unpaddedInput),
|
||
|
+ CKYBuffer_Size(unpaddedInput));
|
||
|
+ }
|
||
|
+
|
||
|
+ void
|
||
|
+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
|
||
|
+ // strip off PKCS #1 padding
|
||
|
stripRSAPadding( unpaddedOutput, paddedOutput );
|
||
|
return;
|
||
|
}
|
||
|
@@ -3298,9 +3924,38 @@ Slot::sign(SessionHandleSuffix suffix, C
|
||
|
CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
|
||
|
CK_ULONG_PTR pulSignatureLen)
|
||
|
{
|
||
|
- RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE);
|
||
|
- cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
|
||
|
- params);
|
||
|
+
|
||
|
+ refreshTokenState();
|
||
|
+ SessionIter session = findSession(suffix);
|
||
|
+ if( session == sessions.end() ) {
|
||
|
+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!isVersion1Key && ! isLoggedIn() ) {
|
||
|
+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Create a default one just to get the sigState */
|
||
|
+ SignatureParams dummyParams(CryptParams::DEFAULT_KEY_SIZE);
|
||
|
+
|
||
|
+ CryptOpState sigState = dummyParams.getOpState(*session);
|
||
|
+
|
||
|
+ PKCS11Object::KeyType keyType = sigState.keyType;
|
||
|
+
|
||
|
+ if ( keyType == PKCS11Object::unknown) {
|
||
|
+ throw PKCS11Exception(CKR_DATA_INVALID);
|
||
|
+ }
|
||
|
+
|
||
|
+ if( keyType == Key::ecc ) {
|
||
|
+ ECCSignatureParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
|
||
|
+ signECC(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
|
||
|
+ params);
|
||
|
+
|
||
|
+ } else if (keyType == Key::rsa) {
|
||
|
+ RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE);
|
||
|
+ cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
|
||
|
+ params);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
void
|
||
|
@@ -3334,9 +3989,9 @@ Slot::cryptRSA(SessionHandleSuffix suffi
|
||
|
CKYBuffer *result = &opState.result;
|
||
|
CKYByte keyNum = opState.keyNum;
|
||
|
|
||
|
- unsigned int keySize = getKeySize(keyNum);
|
||
|
+ unsigned int keySize = getRSAKeySize(keyNum);
|
||
|
|
||
|
- if(keySize != CryptParams::DEFAULT_KEY_SIZE)
|
||
|
+ if (keySize != CryptParams::DEFAULT_KEY_SIZE)
|
||
|
params.setKeySize(keySize);
|
||
|
|
||
|
if( CKYBuffer_Size(result) == 0 ) {
|
||
|
@@ -3358,7 +4013,8 @@ Slot::cryptRSA(SessionHandleSuffix suffi
|
||
|
}
|
||
|
try {
|
||
|
params.padInput(&inputPad, &input);
|
||
|
- performRSAOp(&output, &inputPad, keyNum, params.getDirection());
|
||
|
+ performRSAOp(&output, &inputPad, params.getKeySize(),
|
||
|
+ keyNum, params.getDirection());
|
||
|
params.unpadOutput(result, &output);
|
||
|
CKYBuffer_FreeData(&input);
|
||
|
CKYBuffer_FreeData(&inputPad);
|
||
|
@@ -3395,10 +4051,166 @@ Slot::getNonce()
|
||
|
return &nonce;
|
||
|
}
|
||
|
|
||
|
+void Slot::signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
|
||
|
+ CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
|
||
|
+ CK_ULONG_PTR pulOutputLen, CryptParams& params)
|
||
|
+{
|
||
|
+
|
||
|
+ if( pulOutputLen == NULL ) {
|
||
|
+ throw PKCS11Exception(CKR_DATA_INVALID,
|
||
|
+ "output length is NULL");
|
||
|
+ }
|
||
|
+
|
||
|
+ refreshTokenState();
|
||
|
+ SessionIter session = findSession(suffix);
|
||
|
+ if( session == sessions.end() ) {
|
||
|
+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
+ }
|
||
|
+ /* version 1 keys may not need login. We catch the error
|
||
|
+ on the operation. The token will not allow us to sign with
|
||
|
+ a protected key unless we are logged in.
|
||
|
+ can be removed when version 0 support is depricated.
|
||
|
+ */
|
||
|
+
|
||
|
+ if (!isVersion1Key && ! isLoggedIn() ) {
|
||
|
+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
|
||
|
+ }
|
||
|
+ CryptOpState& opState = params.getOpState(*session);
|
||
|
+ CKYBuffer *result = &opState.result;
|
||
|
+ CKYByte keyNum = opState.keyNum;
|
||
|
+
|
||
|
+ unsigned int keySize = getECCKeySize(keyNum);
|
||
|
+
|
||
|
+ if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
|
||
|
+ params.setKeySize(keySize);
|
||
|
+
|
||
|
+ if( CKYBuffer_Size(result) == 0 ) {
|
||
|
+ unsigned int maxSize = params.getKeySize()/8;
|
||
|
+
|
||
|
+ if( pInput == NULL || ulInputLen == 0) {
|
||
|
+ throw PKCS11Exception(CKR_DATA_LEN_RANGE);
|
||
|
+ }
|
||
|
+ if (ulInputLen > maxSize) {
|
||
|
+ //pInput += ulInputLen - maxSize;
|
||
|
+ ulInputLen = maxSize;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer input;
|
||
|
+ CKYBuffer output;
|
||
|
+ CKYBuffer_InitEmpty(&output);
|
||
|
+ CKYStatus status = CKYBuffer_InitFromData(&input, pInput, ulInputLen);
|
||
|
+
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ CKYBuffer_FreeData(&output);
|
||
|
+ throw PKCS11Exception(CKR_HOST_MEMORY);
|
||
|
+ }
|
||
|
+ try {
|
||
|
+ performECCSignature(&output, &input, params.getKeySize(), keyNum);
|
||
|
+ params.unpadOutput(result, &output);
|
||
|
+ CKYBuffer_FreeData(&input);
|
||
|
+ CKYBuffer_FreeData(&output);
|
||
|
+ } catch(PKCS11Exception& e) {
|
||
|
+ CKYBuffer_FreeData(&input);
|
||
|
+ CKYBuffer_FreeData(&output);
|
||
|
+ throw(e);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if( pOutput != NULL ) {
|
||
|
+ if( *pulOutputLen < CKYBuffer_Size(result) ) {
|
||
|
+ *pulOutputLen = CKYBuffer_Size(result);
|
||
|
+ throw PKCS11Exception(CKR_BUFFER_TOO_SMALL);
|
||
|
+ }
|
||
|
+ memcpy(pOutput, CKYBuffer_Data(result), CKYBuffer_Size(result));
|
||
|
+ }
|
||
|
+ *pulOutputLen = CKYBuffer_Size(result);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+Slot::performECCSignature(CKYBuffer *output, const CKYBuffer *input,
|
||
|
+ unsigned int keySize, CKYByte keyNum)
|
||
|
+{
|
||
|
+
|
||
|
+ /* establish a transaction */
|
||
|
+ Transaction trans;
|
||
|
+ CKYStatus status = trans.begin(conn);
|
||
|
+ if( status != CKYSUCCESS ) handleConnectionError();
|
||
|
+
|
||
|
+ if (!mECC) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ selectCACApplet(keyNum, true);
|
||
|
+ } else {
|
||
|
+ selectApplet();
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYISOStatus result;
|
||
|
+ int loginAttempted = 0;
|
||
|
+
|
||
|
+retry:
|
||
|
+ if (state & PIV_CARD) {
|
||
|
+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
|
||
|
+ } else if (state & CAC_CARD) {
|
||
|
+ status = CACApplet_SignDecrypt(conn, input, output, &result);
|
||
|
+ } else {
|
||
|
+ status = CKYApplet_ComputeECCSignature(conn, keyNum, input, NULL, output, getNonce(), &result);
|
||
|
+ }
|
||
|
+ /* map the ISO not logged in code to the coolkey one */
|
||
|
+ if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
|
||
|
+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
|
||
|
+ result = (CKYStatus) CKYISO_UNAUTHORIZED;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ if ( status == CKYSCARDERR ) {
|
||
|
+ handleConnectionError();
|
||
|
+ }
|
||
|
+
|
||
|
+ if (result == CKYISO_DATA_INVALID) {
|
||
|
+ throw PKCS11Exception(CKR_DATA_INVALID);
|
||
|
+ }
|
||
|
+ /* version0 keys could be logged out in the middle by someone else,
|
||
|
+ reauthenticate... This code can go away when we depricate.
|
||
|
+ version0 applets.
|
||
|
+ */
|
||
|
+ if (!isVersion1Key && !loginAttempted &&
|
||
|
+ (result == CKYISO_UNAUTHORIZED)) {
|
||
|
+ /* try to reauthenticate */
|
||
|
+ try {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ attemptCACLogin();
|
||
|
+ } else {
|
||
|
+ oldAttemptLogin();
|
||
|
+ }
|
||
|
+ } catch(PKCS11Exception& ) {
|
||
|
+ /* attemptLogin can throw things like CKR_PIN_INCORRECT
|
||
|
+ that don't make sense from a crypto operation. This is
|
||
|
+ a result of pin caching. We will reformat any login
|
||
|
+ exception to a CKR_DEVICE_ERROR.
|
||
|
+ */
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR);
|
||
|
+ }
|
||
|
+ loginAttempted = true;
|
||
|
+ goto retry; /* easier to understand than a while loop in this case. */
|
||
|
+ }
|
||
|
+ throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
|
||
|
+ CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
void
|
||
|
-Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input,
|
||
|
+Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, unsigned int keySize,
|
||
|
CKYByte keyNum, CKYByte direction)
|
||
|
{
|
||
|
+ if ( mECC ) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
|
||
|
+ }
|
||
|
+
|
||
|
//
|
||
|
// establish a transaction
|
||
|
//
|
||
|
@@ -3409,8 +4221,8 @@ Slot::performRSAOp(CKYBuffer *output, co
|
||
|
//
|
||
|
// select the applet
|
||
|
//
|
||
|
- if (state & CAC_CARD) {
|
||
|
- selectCACApplet(keyNum);
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ selectCACApplet(keyNum, true);
|
||
|
} else {
|
||
|
selectApplet();
|
||
|
}
|
||
|
@@ -3418,12 +4230,21 @@ Slot::performRSAOp(CKYBuffer *output, co
|
||
|
CKYISOStatus result;
|
||
|
int loginAttempted = 0;
|
||
|
retry:
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & PIV_CARD) {
|
||
|
+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
|
||
|
+ } else if (state & CAC_CARD) {
|
||
|
status = CACApplet_SignDecrypt(conn, input, output, &result);
|
||
|
} else {
|
||
|
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 ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
|
||
|
+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
|
||
|
+ result = CKYISO_UNAUTHORIZED;
|
||
|
+ }
|
||
|
+
|
||
|
if (status != CKYSUCCESS) {
|
||
|
if ( status == CKYSCARDERR ) {
|
||
|
handleConnectionError();
|
||
|
@@ -3434,11 +4255,15 @@ retry:
|
||
|
// version0 keys could be logged out in the middle by someone else,
|
||
|
// reauthenticate... This code can go away when we depricate.
|
||
|
// version0 applets.
|
||
|
- if (!isVersion1Key && !loginAttempted &&
|
||
|
+ if (!isVersion1Key && !loginAttempted && pinCache.isValid() &&
|
||
|
(result == CKYISO_UNAUTHORIZED)) {
|
||
|
// try to reauthenticate
|
||
|
try {
|
||
|
- oldAttemptLogin();
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ attemptCACLogin();
|
||
|
+ } else {
|
||
|
+ oldAttemptLogin();
|
||
|
+ }
|
||
|
} catch(PKCS11Exception& ) {
|
||
|
// attemptLogin can throw things like CKR_PIN_INCORRECT
|
||
|
// that don't make sense from a crypto operation. This is
|
||
|
@@ -3458,7 +4283,7 @@ void
|
||
|
Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
|
||
|
CK_ULONG ulDataLen)
|
||
|
{
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
/* should throw unsupported */
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR);
|
||
|
}
|
||
|
@@ -3510,7 +4335,7 @@ void
|
||
|
Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData,
|
||
|
CK_ULONG ulDataLen)
|
||
|
{
|
||
|
- if (state & CAC_CARD) {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
/* should throw unsupported */
|
||
|
throw PKCS11Exception(CKR_DEVICE_ERROR);
|
||
|
}
|
||
|
@@ -3544,7 +4369,7 @@ Slot::generateRandom(SessionHandleSuffix
|
||
|
|
||
|
#define MAX_NUM_KEYS 8
|
||
|
unsigned int
|
||
|
-Slot::getKeySize(CKYByte keyNum)
|
||
|
+Slot::getRSAKeySize(CKYByte keyNum)
|
||
|
{
|
||
|
unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE;
|
||
|
int modSize = 0;
|
||
|
@@ -3574,3 +4399,238 @@ Slot::getKeySize(CKYByte keyNum)
|
||
|
|
||
|
return keySize;
|
||
|
}
|
||
|
+
|
||
|
+unsigned int
|
||
|
+Slot::getECCKeySize(CKYByte keyNum)
|
||
|
+{
|
||
|
+ return calcECCKeySize(keyNum);
|
||
|
+}
|
||
|
+
|
||
|
+unsigned int
|
||
|
+Slot::calcECCKeySize(CKYByte keyNum)
|
||
|
+{
|
||
|
+ unsigned int keySize = CryptParams::ECC_DEFAULT_KEY_SIZE;
|
||
|
+
|
||
|
+ if(keyNum >= MAX_NUM_KEYS) {
|
||
|
+ return keySize;
|
||
|
+ }
|
||
|
+
|
||
|
+ ObjectConstIter iter;
|
||
|
+ iter = find_if(tokenObjects.begin(), tokenObjects.end(),
|
||
|
+ KeyNumMatch(keyNum,*this));
|
||
|
+
|
||
|
+ if( iter == tokenObjects.end() ) {
|
||
|
+ return keySize;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer const *eccParams = iter->getAttribute(CKA_EC_PARAMS);
|
||
|
+
|
||
|
+ if (eccParams == NULL) {
|
||
|
+ return keySize;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Extract the oid from the params */
|
||
|
+
|
||
|
+ CKYByte ecParamsLen = CKYBuffer_GetChar(eccParams, 1);
|
||
|
+
|
||
|
+ if ( ecParamsLen == 0 ) {
|
||
|
+ return keySize;
|
||
|
+ }
|
||
|
+
|
||
|
+/* Now compare against the limited known list of oid byte info */
|
||
|
+
|
||
|
+ unsigned int oidByteLen = 0;
|
||
|
+
|
||
|
+ CKYByte curByte = 0;
|
||
|
+
|
||
|
+ for (int i = 0 ; i < numECCurves ; i++ ) {
|
||
|
+
|
||
|
+ oidByteLen = curveBytesNamePair[i].bytes[0];
|
||
|
+
|
||
|
+ if ( oidByteLen != (unsigned int ) ecParamsLen ) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ int match = 1;
|
||
|
+ for ( int j = 0 ; j < ecParamsLen ; j++ ) {
|
||
|
+ curByte = CKYBuffer_GetChar(eccParams, 2 + j );
|
||
|
+ if ( curveBytesNamePair[i].bytes[ j + 1 ] != curByte ) {
|
||
|
+ match = 0;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if ( match == 1 ) {
|
||
|
+ keySize = curveBytesNamePair[i].length;
|
||
|
+ return keySize;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ return keySize;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+Slot::derive(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
|
||
|
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
|
||
|
+{
|
||
|
+
|
||
|
+ log->log("Inside of Slot::Derive! \n");
|
||
|
+
|
||
|
+ ECCKeyAgreementParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
|
||
|
+ SessionIter session = findSession(suffix);
|
||
|
+
|
||
|
+ PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hBaseKey);
|
||
|
+
|
||
|
+ session->keyAgreementState.initialize(objectHandleToKeyNum(hBaseKey), keyType);
|
||
|
+ deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey, params);
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+void Slot::deriveECC(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params)
|
||
|
+{
|
||
|
+ if (pMechanism == NULL ) {
|
||
|
+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
|
||
|
+ }
|
||
|
+
|
||
|
+ CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
|
||
|
+
|
||
|
+ mechParams = (CK_ECDH1_DERIVE_PARAMS*) pMechanism->pParameter;
|
||
|
+
|
||
|
+ if (mechParams == NULL || mechParams->kdf != CKD_NULL ) {
|
||
|
+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
|
||
|
+ }
|
||
|
+
|
||
|
+ refreshTokenState();
|
||
|
+ SessionIter session = findSession(suffix);
|
||
|
+ if( session == sessions.end() ) {
|
||
|
+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* version 1 keys may not need login. We catch the error
|
||
|
+ on the operation. The token will not allow us to sign with
|
||
|
+ a protected key unless we are logged in.
|
||
|
+ can be removed when version 0 support is depricated. */
|
||
|
+
|
||
|
+ if (!isVersion1Key && ! isLoggedIn() ) {
|
||
|
+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
|
||
|
+ }
|
||
|
+
|
||
|
+ CryptOpState& opState = params.getOpState(*session);
|
||
|
+ CKYBuffer *result = &opState.result;
|
||
|
+ CKYByte keyNum = opState.keyNum;
|
||
|
+
|
||
|
+ unsigned int keySize = getECCKeySize(keyNum);
|
||
|
+
|
||
|
+ if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
|
||
|
+ params.setKeySize(keySize);
|
||
|
+
|
||
|
+ CK_MECHANISM_TYPE deriveMech = pMechanism->mechanism;
|
||
|
+
|
||
|
+ CK_ULONG otherPublicLen = mechParams->ulPublicDataLen;
|
||
|
+ CK_BYTE_PTR otherPublicData = mechParams->pPublicData;
|
||
|
+
|
||
|
+ CKYBuffer secretKeyBuffer;
|
||
|
+ CKYBuffer_InitEmpty(&secretKeyBuffer);
|
||
|
+ CKYBuffer publicDataBuffer;
|
||
|
+ CKYStatus status = CKYBuffer_InitFromData(&publicDataBuffer,otherPublicData, otherPublicLen);
|
||
|
+
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ CKYBuffer_FreeData(&secretKeyBuffer);
|
||
|
+ throw PKCS11Exception(CKR_HOST_MEMORY);
|
||
|
+ }
|
||
|
+
|
||
|
+ PKCS11Object *secret = NULL;
|
||
|
+ *phKey = 0;
|
||
|
+
|
||
|
+ if( CKYBuffer_Size(result) == 0 ) {
|
||
|
+ try {
|
||
|
+ performECCKeyAgreement(deriveMech, &publicDataBuffer, &secretKeyBuffer,
|
||
|
+ keyNum, params.getKeySize());
|
||
|
+ CK_OBJECT_HANDLE keyObjectHandle = generateUnusedObjectHandle();
|
||
|
+ secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, pTemplate, ulAttributeCount);
|
||
|
+ } catch(PKCS11Exception& e) {
|
||
|
+ CKYBuffer_FreeData(&secretKeyBuffer);
|
||
|
+ CKYBuffer_FreeData(&publicDataBuffer);
|
||
|
+ throw(e);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_FreeData(&secretKeyBuffer);
|
||
|
+ CKYBuffer_FreeData(&publicDataBuffer);
|
||
|
+
|
||
|
+ if ( secret ) {
|
||
|
+
|
||
|
+ *phKey = secret->getHandle();
|
||
|
+ delete secret;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, CKYBuffer *publicDataBuffer,
|
||
|
+ CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize)
|
||
|
+{
|
||
|
+ if (!mECC) {
|
||
|
+ throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
|
||
|
+ }
|
||
|
+
|
||
|
+ Transaction trans;
|
||
|
+ CKYStatus status = trans.begin(conn);
|
||
|
+ if( status != CKYSUCCESS ) handleConnectionError();
|
||
|
+
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ selectCACApplet(keyNum, true);
|
||
|
+ } else {
|
||
|
+ selectApplet();
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYISOStatus result;
|
||
|
+ int loginAttempted = 0;
|
||
|
+
|
||
|
+retry:
|
||
|
+
|
||
|
+ if (state & PIV_CARD) {
|
||
|
+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, publicDataBuffer,
|
||
|
+ secretKeyBuffer, &result);
|
||
|
+ } else if (state & CAC_CARD) {
|
||
|
+ status = CACApplet_SignDecrypt(conn, publicDataBuffer, secretKeyBuffer, &result);
|
||
|
+ } else {
|
||
|
+ status = CKYApplet_ComputeECCKeyAgreement(conn, keyNum,
|
||
|
+ publicDataBuffer , NULL, secretKeyBuffer, getNonce(), &result);
|
||
|
+ }
|
||
|
+ /* map the ISO not logged in code to the coolkey one */
|
||
|
+ if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
|
||
|
+ (result == CKYISO_SECURITY_NOT_SATISFIED)) {
|
||
|
+ result = (CKYStatus) CKYISO_UNAUTHORIZED;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (status != CKYSUCCESS) {
|
||
|
+ if ( status == CKYSCARDERR ) {
|
||
|
+ handleConnectionError();
|
||
|
+ }
|
||
|
+
|
||
|
+ if (result == CKYISO_DATA_INVALID) {
|
||
|
+ throw PKCS11Exception(CKR_DATA_INVALID);
|
||
|
+ }
|
||
|
+ if (!isVersion1Key && !loginAttempted &&
|
||
|
+ (result == CKYISO_UNAUTHORIZED)) {
|
||
|
+ try {
|
||
|
+ if (state & GOV_CARD) {
|
||
|
+ attemptCACLogin();
|
||
|
+ } else {
|
||
|
+ oldAttemptLogin();
|
||
|
+ }
|
||
|
+ } catch(PKCS11Exception& ) {
|
||
|
+ throw PKCS11Exception(CKR_DEVICE_ERROR);
|
||
|
+ }
|
||
|
+ loginAttempted = true;
|
||
|
+ goto retry;
|
||
|
+ }
|
||
|
+
|
||
|
+ throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
|
||
|
+ CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
|
||
|
+
|
||
|
+ }
|
||
|
+}
|
||
|
diff -up ./src/coolkey/slot.h.piv-ecc ./src/coolkey/slot.h
|
||
|
--- ./src/coolkey/slot.h.piv-ecc 2013-09-08 15:50:33.098428320 -0700
|
||
|
+++ ./src/coolkey/slot.h 2013-09-08 15:50:33.125428774 -0700
|
||
|
@@ -211,24 +211,27 @@ class CryptOpState {
|
||
|
State state;
|
||
|
CKYByte keyNum;
|
||
|
CKYBuffer result;
|
||
|
+ PKCS11Object::KeyType keyType;
|
||
|
|
||
|
- CryptOpState() : state(NOT_INITIALIZED), keyNum(0)
|
||
|
+ CryptOpState() : state(NOT_INITIALIZED), keyNum(0), keyType(PKCS11Object::unknown)
|
||
|
{ CKYBuffer_InitEmpty(&result); }
|
||
|
CryptOpState(const CryptOpState &cpy) :
|
||
|
- state(cpy.state), keyNum(cpy.keyNum) {
|
||
|
+ state(cpy.state), keyNum(cpy.keyNum), keyType(cpy.keyType) {
|
||
|
CKYBuffer_InitFromCopy(&result, &cpy.result);
|
||
|
}
|
||
|
CryptOpState &operator=(const CryptOpState &cpy) {
|
||
|
state = cpy.state,
|
||
|
keyNum = cpy.keyNum;
|
||
|
+ keyType = cpy.keyType;
|
||
|
CKYBuffer_Replace(&result, 0, CKYBuffer_Data(&cpy.result),
|
||
|
CKYBuffer_Size(&cpy.result));
|
||
|
return *this;
|
||
|
}
|
||
|
~CryptOpState() { CKYBuffer_FreeData(&result); }
|
||
|
- void initialize(CKYByte keyNum) {
|
||
|
+ void initialize(CKYByte keyNum, PKCS11Object::KeyType theKeyType) {
|
||
|
state = IN_PROCESS;
|
||
|
this->keyNum = keyNum;
|
||
|
+ this->keyType = theKeyType;
|
||
|
CKYBuffer_Resize(&result, 0);
|
||
|
}
|
||
|
};
|
||
|
@@ -258,6 +261,7 @@ class Session {
|
||
|
|
||
|
CryptOpState signatureState;
|
||
|
CryptOpState decryptionState;
|
||
|
+ CryptOpState keyAgreementState;
|
||
|
};
|
||
|
|
||
|
typedef list<Session> SessionList;
|
||
|
@@ -267,12 +271,11 @@ typedef SessionList::const_iterator Sess
|
||
|
class CryptParams {
|
||
|
private:
|
||
|
unsigned int keySize; // in bits
|
||
|
- protected:
|
||
|
- unsigned int getKeySize() const { return keySize; }
|
||
|
public:
|
||
|
// set the actual key size obtained from the card
|
||
|
void setKeySize(unsigned int newKeySize) { keySize = newKeySize; }
|
||
|
- enum { DEFAULT_KEY_SIZE = 1024 };
|
||
|
+ unsigned int getKeySize() const { return keySize; }
|
||
|
+ enum { DEFAULT_KEY_SIZE = 1024, ECC_DEFAULT_KEY_SIZE=256 };
|
||
|
|
||
|
|
||
|
CryptParams(unsigned int keySize_) : keySize(keySize_) { }
|
||
|
@@ -304,12 +307,15 @@ class Slot {
|
||
|
ATR_MATCH = 0x04,
|
||
|
APPLET_SELECTABLE = 0x08,
|
||
|
APPLET_PERSONALIZED = 0x10,
|
||
|
- CAC_CARD = 0x20
|
||
|
+ CAC_CARD = 0x20,
|
||
|
+ PIV_CARD = 0x40
|
||
|
};
|
||
|
enum {
|
||
|
NONCE_SIZE = 8
|
||
|
};
|
||
|
|
||
|
+ static const SlotState GOV_CARD = (SlotState)(CAC_CARD|PIV_CARD);
|
||
|
+
|
||
|
private:
|
||
|
Log *log;
|
||
|
char *readerName;
|
||
|
@@ -339,7 +345,10 @@ class Slot {
|
||
|
bool fullTokenName;
|
||
|
bool mCoolkey;
|
||
|
bool mOldCAC;
|
||
|
-
|
||
|
+ bool mCACLocalLogin;
|
||
|
+ int pivContainer;
|
||
|
+ int pivKey;
|
||
|
+ bool mECC;
|
||
|
//enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 };
|
||
|
|
||
|
#ifdef USE_SHMEM
|
||
|
@@ -386,6 +395,7 @@ class Slot {
|
||
|
const CKYBuffer *getATR();
|
||
|
bool isLoggedIn();
|
||
|
bool needLoggedIn();
|
||
|
+ bool getPIVLoginType();
|
||
|
void testNonce();
|
||
|
|
||
|
void addKeyObject(list<PKCS11Object>& objectList,
|
||
|
@@ -395,6 +405,7 @@ class Slot {
|
||
|
const CKYBuffer *derCert, CK_OBJECT_HANDLE handle);
|
||
|
void addObject(list<PKCS11Object>& objectList,
|
||
|
const ListObjectInfo& info, CK_OBJECT_HANDLE handle);
|
||
|
+ PKCS11Object *createSecretKeyObject(CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer,CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount);
|
||
|
|
||
|
void ensureValidSession(SessionHandleSuffix suffix);
|
||
|
|
||
|
@@ -408,7 +419,7 @@ class Slot {
|
||
|
CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize);
|
||
|
|
||
|
void selectApplet();
|
||
|
- void selectCACApplet(CKYByte instance);
|
||
|
+ void selectCACApplet(CKYByte instance,bool do_disconnect);
|
||
|
void unloadObjects();
|
||
|
void loadCACObjects();
|
||
|
void loadCACCert(CKYByte instance);
|
||
|
@@ -432,12 +443,23 @@ class Slot {
|
||
|
CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
|
||
|
CK_ULONG_PTR pulOutputLen, CryptParams& params);
|
||
|
|
||
|
- void performRSAOp(CKYBuffer *out, const CKYBuffer *input, CKYByte keyNum,
|
||
|
- CKYByte direction);
|
||
|
+ void performRSAOp(CKYBuffer *out, const CKYBuffer *input, unsigned int keySize,
|
||
|
+ CKYByte keyNum, CKYByte direction);
|
||
|
+
|
||
|
+ void signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
|
||
|
+ CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
|
||
|
+ CK_ULONG_PTR pulOutputLen, CryptParams& params);
|
||
|
+
|
||
|
+ void performECCSignature(CKYBuffer *out, const CKYBuffer *input,
|
||
|
+ unsigned int keySize, CKYByte keyNum);
|
||
|
+ void performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech,
|
||
|
+ CKYBuffer *publicDataBuffer,
|
||
|
+ CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize);
|
||
|
|
||
|
void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu);
|
||
|
|
||
|
CKYByte objectHandleToKeyNum(CK_OBJECT_HANDLE hKey);
|
||
|
+ unsigned int calcECCKeySize(CKYByte keyNum);
|
||
|
Slot(const Slot &cpy)
|
||
|
#ifdef USE_SHMEM
|
||
|
: shmem(readerName)
|
||
|
@@ -469,7 +491,10 @@ class Slot {
|
||
|
}
|
||
|
|
||
|
// actually get the size of a key in bits from the card
|
||
|
- unsigned int getKeySize(CKYByte keyNum);
|
||
|
+ unsigned int getRSAKeySize(CKYByte keyNum);
|
||
|
+ unsigned int getECCKeySize(CKYByte keyNum);
|
||
|
+
|
||
|
+ PKCS11Object::KeyType getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey);
|
||
|
|
||
|
SessionHandleSuffix openSession(Session::Type type);
|
||
|
void closeSession(SessionHandleSuffix handleSuffix);
|
||
|
@@ -511,6 +536,16 @@ class Slot {
|
||
|
CK_ULONG len);
|
||
|
void generateRandom(SessionHandleSuffix suffix, CK_BYTE_PTR data,
|
||
|
CK_ULONG len);
|
||
|
+
|
||
|
+ void derive(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_PTR pTemplate,
|
||
|
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
|
||
|
+
|
||
|
+ void deriveECC(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
|
||
|
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params);
|
||
|
+
|
||
|
+ bool getIsECC() { return mECC; }
|
||
|
};
|
||
|
|
||
|
class SlotList {
|
||
|
@@ -604,6 +639,10 @@ class SlotList {
|
||
|
void seedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
|
||
|
CK_ULONG ulDataLen);
|
||
|
|
||
|
+ void derive(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
|
||
|
+ CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_PTR pTemplate,
|
||
|
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
|
||
|
+
|
||
|
|
||
|
};
|
||
|
#endif
|
||
|
diff -up ./src/install/pk11install.c.piv-ecc ./src/install/pk11install.c
|
||
|
--- ./src/install/pk11install.c.piv-ecc 2007-02-06 11:40:36.000000000 -0800
|
||
|
+++ ./src/install/pk11install.c 2013-09-08 15:50:33.126428790 -0700
|
||
|
@@ -171,7 +171,7 @@ int dirListCount = sizeof(dirList)/sizeo
|
||
|
static void
|
||
|
usage(char *prog)
|
||
|
{
|
||
|
- fprintf(stderr,"usage: %s [-u][-v] [-p path] module\n", prog);
|
||
|
+ fprintf(stderr,"usage: %s [-u][-v][-s][-l] [-p path] module\n", prog);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -181,9 +181,9 @@ usage(char *prog)
|
||
|
|
||
|
#define CONFIG_TAG "configDir="
|
||
|
int
|
||
|
-installPKCS11(char *dirPath, InstType type, char *module)
|
||
|
+installPKCS11(char *dirPath, char *dbType, InstType type, char *module)
|
||
|
{
|
||
|
- char *paramString = (char *)malloc(strlen(dirPath)+sizeof(CONFIG_TAG)+3);
|
||
|
+ char *paramString = (char *)malloc(strlen(dbType)+strlen(dirPath)+sizeof(CONFIG_TAG)+3);
|
||
|
char *cp;
|
||
|
char **rc;
|
||
|
|
||
|
@@ -191,7 +191,7 @@ installPKCS11(char *dirPath, InstType ty
|
||
|
PINST_SET_ERROR(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
return 0;
|
||
|
}
|
||
|
- sprintf(paramString,CONFIG_TAG"\"%s\" ",dirPath);
|
||
|
+ sprintf(paramString,CONFIG_TAG"\"%s%s\" ",dbType,dirPath);
|
||
|
|
||
|
/* translate all the \'s to /'s */
|
||
|
for (cp=paramString; *cp; cp++) {
|
||
|
@@ -214,7 +214,7 @@ installPKCS11(char *dirPath, InstType ty
|
||
|
|
||
|
|
||
|
int
|
||
|
-installAllPKCS11(char *dirPath, char *search, char *tail,
|
||
|
+installAllPKCS11(char *dirPath, char *dbType, char *search, char *tail,
|
||
|
InstType type, char *module)
|
||
|
{
|
||
|
char *searchString;
|
||
|
@@ -282,9 +282,9 @@ installAllPKCS11(char *dirPath, char *se
|
||
|
|
||
|
myPath=PINST_FULLPATH(tempPath,path);
|
||
|
if (tail) {
|
||
|
- installAllPKCS11(myPath, tail, NULL, type, module);
|
||
|
+ installAllPKCS11(myPath, dbType, tail, NULL, type, module);
|
||
|
} else {
|
||
|
- installPKCS11(myPath, type, module);
|
||
|
+ installPKCS11(myPath, dbType, type, module);
|
||
|
}
|
||
|
} while (PINST_NEXT(iter, fileData));
|
||
|
free(tempPath);
|
||
|
@@ -309,6 +309,7 @@ int main(int argc, char **argv)
|
||
|
int i;
|
||
|
InstType type = Install;
|
||
|
char * path = NULL;
|
||
|
+ char *dbType = "";
|
||
|
#ifdef WIN32
|
||
|
BOOL brc;
|
||
|
HKEY regKey;
|
||
|
@@ -333,6 +334,12 @@ int main(int argc, char **argv)
|
||
|
case 'v':
|
||
|
verbose = 1;
|
||
|
break;
|
||
|
+ case 'l':
|
||
|
+ dbType = "dbm:";
|
||
|
+ break;
|
||
|
+ case 's':
|
||
|
+ dbType = "sql:";
|
||
|
+ break;
|
||
|
case 'p':
|
||
|
path = *argv++;
|
||
|
if (path == NULL) {
|
||
|
@@ -359,7 +366,7 @@ int main(int argc, char **argv)
|
||
|
}
|
||
|
|
||
|
if (path) {
|
||
|
- installAllPKCS11(path, "", NULL, type, module);
|
||
|
+ installAllPKCS11(path, dbType, "", NULL, type, module);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -444,7 +451,7 @@ int main(int argc, char **argv)
|
||
|
if (!dirPath) {
|
||
|
continue;
|
||
|
}
|
||
|
- installAllPKCS11(dirPath, dirList[i].search, dirList[i].tail,
|
||
|
+ installAllPKCS11(dirPath, dbType, dirList[i].search, dirList[i].tail,
|
||
|
type, module);
|
||
|
}
|
||
|
|
||
|
diff -up ./src/libckyapplet/cky_applet.c.piv-ecc ./src/libckyapplet/cky_applet.c
|
||
|
--- ./src/libckyapplet/cky_applet.c.piv-ecc 2013-09-08 15:50:33.099428337 -0700
|
||
|
+++ ./src/libckyapplet/cky_applet.c 2013-09-08 15:50:33.126428790 -0700
|
||
|
@@ -103,6 +103,22 @@ CKYAppletFactory_ComputeCryptOneStep(CKY
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
+CKYAppletFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, const void *param)
|
||
|
+{
|
||
|
+ const CKYAppletArgComputeECCSignature *ccs=(const CKYAppletArgComputeECCSignature *)param;
|
||
|
+ return CKYAPDUFactory_ComputeECCSignatureOneStep(apdu, ccs->keyNumber,
|
||
|
+ ccs->location, ccs->data, ccs->sig);
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+CKYAppletFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, const void *param)
|
||
|
+{
|
||
|
+
|
||
|
+ const CKYAppletArgComputeECCKeyAgreement *ccs=(const CKYAppletArgComputeECCKeyAgreement *)param;
|
||
|
+ return CKYAPDUFactory_ComputeECCKeyAgreementOneStep(apdu, ccs->keyNumber, ccs->location, ccs->publicValue, ccs->secretKey);
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
CKYAppletFactory_CreatePIN(CKYAPDU *apdu, const void *param)
|
||
|
{
|
||
|
const CKYAppletArgCreatePIN *cps = (const CKYAppletArgCreatePIN *)param;
|
||
|
@@ -245,10 +261,25 @@ CACAppletFactory_SignDecryptFinal(CKYAPD
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
+PIVAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param)
|
||
|
+{
|
||
|
+ const PIVAppletArgSignDecrypt *psd = (const PIVAppletArgSignDecrypt *)param;
|
||
|
+ return PIVAPDUFactory_SignDecrypt(apdu, psd->chain, psd->alg, psd->key,
|
||
|
+ psd->len, psd->buf);
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
CACAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
|
||
|
{
|
||
|
const char *pin=(const char *)param;
|
||
|
- return CACAPDUFactory_VerifyPIN(apdu, pin);
|
||
|
+ return CACAPDUFactory_VerifyPIN(apdu, CAC_LOGIN_GLOBAL, pin);
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+PIVAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
|
||
|
+{
|
||
|
+ const char *pin=(const char *)param;
|
||
|
+ return CACAPDUFactory_VerifyPIN(apdu, PIV_LOGIN_LOCAL, pin);
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
@@ -259,6 +290,13 @@ CACAppletFactory_GetCertificate(CKYAPDU
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
+PIVAppletFactory_GetCertificate(CKYAPDU *apdu, const void *param)
|
||
|
+{
|
||
|
+ CKYBuffer *tag =(CKYBuffer*)param;
|
||
|
+ return PIVAPDUFactory_GetData(apdu, tag, 0);
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param)
|
||
|
{
|
||
|
const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param;
|
||
|
@@ -325,6 +363,7 @@ CKYAppletFill_AppendBuffer(const CKYBuff
|
||
|
CKYBuffer_Size(response) -2);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
CKYStatus
|
||
|
CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param)
|
||
|
{
|
||
|
@@ -725,6 +764,32 @@ CKYApplet_ComputeCryptProcess(CKYCardCon
|
||
|
&ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC);
|
||
|
}
|
||
|
|
||
|
+/* computeECCValue returns data in the form :
|
||
|
+ * len: short
|
||
|
+ * data: byte[len]
|
||
|
+ * This fill routine returns A buffer with a copy of data and a length of len */
|
||
|
+static CKYStatus
|
||
|
+ckyAppletFill_ComputeECCValueFinal(const CKYBuffer *response,
|
||
|
+ CKYSize size, void *param)
|
||
|
+{
|
||
|
+ CKYBuffer *cbuf = (CKYBuffer *)param;
|
||
|
+ CKYSize respSize = CKYBuffer_Size(response);
|
||
|
+ CKYSize dataLen;
|
||
|
+
|
||
|
+ if (cbuf == 0) {
|
||
|
+ return CKYSUCCESS; /* app didn't want the result */
|
||
|
+ }
|
||
|
+ /* data response code + length code */
|
||
|
+ if (respSize < 4) {
|
||
|
+ return CKYAPDUFAIL;
|
||
|
+ }
|
||
|
+ dataLen = CKYBuffer_GetShort(response, 0);
|
||
|
+ if (dataLen > (respSize-4)) {
|
||
|
+ return CKYAPDUFAIL;
|
||
|
+ }
|
||
|
+ return CKYBuffer_Replace(cbuf, 0, CKYBuffer_Data(response)+2, dataLen);
|
||
|
+}
|
||
|
+
|
||
|
/* computeCrypt returns data in the form :
|
||
|
* len: short
|
||
|
* data: byte[len]
|
||
|
@@ -872,6 +937,77 @@ fail:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+CKYStatus
|
||
|
+CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
|
||
|
+ const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
|
||
|
+ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
|
||
|
+{
|
||
|
+ CKYStatus ret = CKYAPDUFAIL;
|
||
|
+ CKYAppletArgComputeECCKeyAgreement ccd;
|
||
|
+ CKYBuffer empty;
|
||
|
+ CKYISOStatus status;
|
||
|
+ /* Routine creates a sym key, should easily fit in one apdu */
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&empty);
|
||
|
+ ccd.keyNumber = keyNumber;
|
||
|
+ ccd.location = CKY_DL_APDU;
|
||
|
+
|
||
|
+ if (!apduRC)
|
||
|
+ apduRC = &status;
|
||
|
+
|
||
|
+ if (ccd.location == CKY_DL_APDU) {
|
||
|
+ ccd.publicValue = publicValue;
|
||
|
+ ccd.secretKey = sharedSecret;
|
||
|
+ ret = CKYApplet_HandleAPDU(conn,
|
||
|
+ CKYAppletFactory_ComputeECCKeyAgreementOneStep, &ccd, nonce,
|
||
|
+ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
|
||
|
+ result, apduRC);
|
||
|
+ if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
|
||
|
+ const CKYBuffer *data, CKYBuffer *sig,
|
||
|
+ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
|
||
|
+{
|
||
|
+ int use2APDUs = 0;
|
||
|
+ int use_dl_object = 0;
|
||
|
+ short dataSize = 0;
|
||
|
+ CKYStatus ret = CKYAPDUFAIL;
|
||
|
+ CKYAppletArgComputeECCSignature ccd;
|
||
|
+ CKYBuffer empty;
|
||
|
+ CKYISOStatus status;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&empty);
|
||
|
+ ccd.keyNumber = keyNumber;
|
||
|
+
|
||
|
+ /* Assume APDU, the signature can only get so big with our key sizes, ~ 130 for 521 bit key. */
|
||
|
+ ccd.location = CKY_DL_APDU;
|
||
|
+
|
||
|
+ if (!apduRC)
|
||
|
+ apduRC = &status;
|
||
|
+
|
||
|
+ if (ccd.location == CKY_DL_APDU) {
|
||
|
+ ccd.data = data;
|
||
|
+ ccd.sig = sig;
|
||
|
+ ret = CKYApplet_HandleAPDU(conn,
|
||
|
+ CKYAppletFactory_ComputeECCSignatureOneStep, &ccd, nonce,
|
||
|
+ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
|
||
|
+ result, apduRC);
|
||
|
+ if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* do a CAC Sign/Decrypt
|
||
|
*/
|
||
|
@@ -920,7 +1056,7 @@ done:
|
||
|
* do a CAC VerifyPIN
|
||
|
*/
|
||
|
CKYStatus
|
||
|
-CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin,
|
||
|
+CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, int local,
|
||
|
CKYISOStatus *apduRC)
|
||
|
{
|
||
|
CKYStatus ret;
|
||
|
@@ -929,7 +1065,7 @@ CACApplet_VerifyPIN(CKYCardConnection *c
|
||
|
apduRC = &status;
|
||
|
}
|
||
|
|
||
|
- ret = CKYApplet_HandleAPDU(conn,
|
||
|
+ ret = CKYApplet_HandleAPDU(conn, local ? PIVAppletFactory_VerifyPIN :
|
||
|
CACAppletFactory_VerifyPIN, pin, NULL,
|
||
|
0, CKYAppletFill_Null,
|
||
|
NULL, apduRC);
|
||
|
@@ -942,6 +1078,7 @@ CACApplet_VerifyPIN(CKYCardConnection *c
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
/*
|
||
|
* Get a CAC Certificate
|
||
|
*/
|
||
|
@@ -1078,6 +1215,278 @@ CACApplet_GetCertificateAppend(CKYCardCo
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/* Select the PIV applet */
|
||
|
+static CKYByte pivAid[] = {0xa0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00,
|
||
|
+ 0x10, 0x00};
|
||
|
+CKYStatus
|
||
|
+PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC)
|
||
|
+{
|
||
|
+ CKYStatus ret;
|
||
|
+ CKYBuffer PIV_Applet_AID,return_AID;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&return_AID);
|
||
|
+ CKYBuffer_InitFromData(&PIV_Applet_AID, pivAid, sizeof(pivAid));
|
||
|
+ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile,
|
||
|
+ &PIV_Applet_AID,
|
||
|
+ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer,
|
||
|
+ &return_AID, apduRC);
|
||
|
+ /* Some cards return OK, but don't switch to our applet */
|
||
|
+ /* PIV has a well defined return for it's select, check to see if we have
|
||
|
+ * a PIV card here */
|
||
|
+ if (CKYBuffer_GetChar(&return_AID,0) != 0x61) {
|
||
|
+ /* not an application property template, so not a PIV. We could
|
||
|
+ * check that the aid tag (0x4f) and theallocation authority tag (0x79)
|
||
|
+ * are present, but what we are really avoiding is broken cards that
|
||
|
+ * lie about being able to switch to a particular applet, so the first
|
||
|
+ * tag should be sufficient */
|
||
|
+ ret = CKYAPDUFAIL; /* what we should have gotten */
|
||
|
+ }
|
||
|
+ CKYBuffer_FreeData(&PIV_Applet_AID);
|
||
|
+ CKYBuffer_FreeData(&return_AID);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Get a PIV Certificate
|
||
|
+ */
|
||
|
+CKYStatus
|
||
|
+PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert, int tag,
|
||
|
+ CKYISOStatus *apduRC)
|
||
|
+{
|
||
|
+ CKYStatus ret;
|
||
|
+ CKYISOStatus status;
|
||
|
+ CKYBuffer tagBuf;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&tagBuf);
|
||
|
+ CKYBuffer_Reserve(&tagBuf,4); /* can be up to 4 bytes */
|
||
|
+
|
||
|
+ CKYBuffer_Resize(cert,0);
|
||
|
+ if (apduRC == NULL) {
|
||
|
+ apduRC = &status;
|
||
|
+ }
|
||
|
+ if (tag >= 0x01000000) {
|
||
|
+ ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 24) & 0xff);
|
||
|
+ if (ret != CKYSUCCESS) { goto loser; }
|
||
|
+ }
|
||
|
+ if (tag >= 0x010000) {
|
||
|
+ ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 16) & 0xff);
|
||
|
+ if (ret != CKYSUCCESS) { goto loser; }
|
||
|
+ }
|
||
|
+ if (tag >= 0x0100) {
|
||
|
+ ret =CKYBuffer_AppendChar(&tagBuf, (tag >> 8) & 0xff);
|
||
|
+ if (ret != CKYSUCCESS) { goto loser; }
|
||
|
+ }
|
||
|
+ ret = CKYBuffer_AppendChar(&tagBuf, tag & 0xff);
|
||
|
+ if (ret != CKYSUCCESS) { goto loser; }
|
||
|
+
|
||
|
+
|
||
|
+ ret = CKYApplet_HandleAPDU(conn,
|
||
|
+ PIVAppletFactory_GetCertificate, &tagBuf, NULL,
|
||
|
+ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
|
||
|
+ apduRC);
|
||
|
+loser:
|
||
|
+ CKYBuffer_FreeData(&tagBuf);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/*
|
||
|
+ * record the next ber tag and length. NOTE: this is a state machine.
|
||
|
+ * we can handle the case where we are passed the data just one byte
|
||
|
+ * at a time.
|
||
|
+ */
|
||
|
+static CKYStatus
|
||
|
+pivUnwrap(const CKYBuffer *buf, CKYOffset *offset,
|
||
|
+ CKYSize *dataSize, PIVUnwrapState *unwrap)
|
||
|
+{
|
||
|
+ if (unwrap->tag == 0) {
|
||
|
+ unwrap->tag = CKYBuffer_GetChar(buf, *offset);
|
||
|
+ if (unwrap->tag == 0) unwrap->tag = 0xff;
|
||
|
+ (*offset)++;
|
||
|
+ (*dataSize)--;
|
||
|
+ }
|
||
|
+ if (*dataSize == 0) {
|
||
|
+ return CKYSUCCESS;
|
||
|
+ }
|
||
|
+ if (unwrap->length_bytes != 0) {
|
||
|
+ int len;
|
||
|
+ if (unwrap->length_bytes == -1) {
|
||
|
+ len = CKYBuffer_GetChar(buf, *offset);
|
||
|
+ unwrap->length_bytes = 0;
|
||
|
+ unwrap->length = len;
|
||
|
+ (*offset)++;
|
||
|
+ (*dataSize)--;
|
||
|
+ if (len & 0x80) {
|
||
|
+ unwrap->length = 0;
|
||
|
+ unwrap->length_bytes = len & 0x7f;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ while ((*dataSize != 0) && (unwrap->length_bytes != 0)) {
|
||
|
+ len = CKYBuffer_GetChar(buf, *offset);
|
||
|
+ (*offset) ++;
|
||
|
+ (*dataSize) --;
|
||
|
+ unwrap->length = ((unwrap->length) << 8 | len);
|
||
|
+ unwrap->length_bytes--;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return CKYSUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Remove the BER wrapping first...
|
||
|
+ */
|
||
|
+static CKYStatus
|
||
|
+pivAppletFill_AppendUnwrapBuffer(const CKYBuffer *response,
|
||
|
+ CKYSize size, void *param)
|
||
|
+{
|
||
|
+ PIVAppletRespSignDecrypt *prsd = (PIVAppletRespSignDecrypt *)param;
|
||
|
+ CKYBuffer *buf = prsd->buf;
|
||
|
+ CKYSize dataSize = CKYBuffer_Size(response);
|
||
|
+ CKYOffset offset = 0;
|
||
|
+
|
||
|
+ if (dataSize <= 2) {
|
||
|
+ return CKYSUCCESS;
|
||
|
+ }
|
||
|
+ dataSize -= 2;
|
||
|
+ /* remove the first tag */
|
||
|
+ (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_1);
|
||
|
+ if (dataSize == 0) {
|
||
|
+ return CKYSUCCESS;
|
||
|
+ }
|
||
|
+ /* remove the second tag */
|
||
|
+ (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_2);
|
||
|
+ if (dataSize == 0) {
|
||
|
+ return CKYSUCCESS;
|
||
|
+ }
|
||
|
+ /* the rest is real data */
|
||
|
+ return CKYBuffer_AppendData(buf, CKYBuffer_Data(response) + offset,
|
||
|
+ dataSize);
|
||
|
+}
|
||
|
+
|
||
|
+static CKYStatus
|
||
|
+piv_wrapEncodeLength(CKYBuffer *buf, int length, int ber_len)
|
||
|
+{
|
||
|
+ if (ber_len== 1) {
|
||
|
+ CKYBuffer_AppendChar(buf,length);
|
||
|
+ } else {
|
||
|
+ ber_len--;
|
||
|
+ CKYBuffer_AppendChar(buf,0x80+ber_len);
|
||
|
+ while(ber_len--) {
|
||
|
+ CKYBuffer_AppendChar(buf,(length >> (8*ber_len)) & 0xff);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return CKYSUCCESS;
|
||
|
+}
|
||
|
+/*
|
||
|
+ * do a PIV Sign/Decrypt
|
||
|
+ */
|
||
|
+CKYStatus
|
||
|
+PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key, unsigned int keySize, int derive,
|
||
|
+ const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC)
|
||
|
+{
|
||
|
+ CKYStatus ret;
|
||
|
+ CKYSize dataSize = CKYBuffer_Size(data);
|
||
|
+ CKYSize outputSize = keySize;
|
||
|
+ CKYOffset offset = 0;
|
||
|
+ CKYBuffer tmp;
|
||
|
+ CKYByte alg;
|
||
|
+ int ber_len_1;
|
||
|
+ int ber_len_2;
|
||
|
+ int length;
|
||
|
+ PIVAppletArgSignDecrypt pasd;
|
||
|
+ PIVAppletRespSignDecrypt prsd;
|
||
|
+
|
||
|
+ /* PIV only defines RSA 1024 and 2048, ECC 256 and ECC 384!!! */
|
||
|
+ if (keySize == 128) { /* 1024 bit == 128 bytes */
|
||
|
+ ber_len_2 = 2;
|
||
|
+ ber_len_1 = 2;
|
||
|
+ alg = 0x6;
|
||
|
+ } else if (keySize == 256) { /* 2048 bits == 256 bytes */
|
||
|
+ ber_len_2 = 3;
|
||
|
+ ber_len_1 = 3;
|
||
|
+ alg = 0x7;
|
||
|
+ } else if (keySize == 32) { /* 256 bits = 32 bytes */
|
||
|
+ ber_len_2 = 1;
|
||
|
+ ber_len_1 = 1;
|
||
|
+ alg = 0x11;
|
||
|
+ if (!derive) outputSize = keySize*2;
|
||
|
+ } else if (keySize == 48) { /* 384 bits = 48 bytes */
|
||
|
+ ber_len_2 = 1;
|
||
|
+ ber_len_1 = 1;
|
||
|
+ alg = 0x14;
|
||
|
+ if (!derive) outputSize = keySize*2;
|
||
|
+ } else {
|
||
|
+ return CKYINVALIDARGS;
|
||
|
+ }
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&tmp);
|
||
|
+ ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ CKYBuffer_AppendChar(&tmp,0x7c);
|
||
|
+ piv_wrapEncodeLength(&tmp,dataSize + ber_len_2 + 3,ber_len_1);
|
||
|
+ CKYBuffer_AppendChar(&tmp,0x82);
|
||
|
+ CKYBuffer_AppendChar(&tmp,0x0);
|
||
|
+ CKYBuffer_AppendChar(&tmp, derive ? 0x85 : 0x81);
|
||
|
+ piv_wrapEncodeLength(&tmp,dataSize,ber_len_2);
|
||
|
+
|
||
|
+ /* now length == header length from here to the end*/
|
||
|
+ length = CKYBuffer_Size(&tmp);
|
||
|
+
|
||
|
+ if (length + dataSize > CKY_MAX_WRITE_CHUNK_SIZE) {
|
||
|
+ CKYBuffer_AppendBuffer(&tmp, data, 0, CKY_MAX_WRITE_CHUNK_SIZE-length);
|
||
|
+ } else {
|
||
|
+ CKYBuffer_AppendBuffer(&tmp, data, 0, dataSize);
|
||
|
+ }
|
||
|
+
|
||
|
+ prsd.tag_1.tag = 0;
|
||
|
+ prsd.tag_1.length_bytes = -1;
|
||
|
+ prsd.tag_1.length = 0;
|
||
|
+ prsd.tag_2.tag = 0;
|
||
|
+ prsd.tag_2.length_bytes = -1;
|
||
|
+ prsd.tag_2.length = 0;
|
||
|
+ prsd.buf = result;
|
||
|
+ pasd.alg = alg;
|
||
|
+ pasd.key = key;
|
||
|
+ pasd.buf = &tmp;
|
||
|
+
|
||
|
+ CKYBuffer_Resize(result,0);
|
||
|
+ for(offset = -length; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; ) {
|
||
|
+ pasd.chain = 1;
|
||
|
+ pasd.len = 0;
|
||
|
+ ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt,
|
||
|
+ &pasd, NULL, CKY_SIZE_UNKNOWN,
|
||
|
+ pivAppletFill_AppendUnwrapBuffer,
|
||
|
+ &prsd, apduRC);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ CKYBuffer_Resize(&tmp,0);
|
||
|
+ /* increment before we append the next tmp buffer */
|
||
|
+ offset += CKY_MAX_WRITE_CHUNK_SIZE;
|
||
|
+ CKYBuffer_AppendBuffer(&tmp, data, offset,
|
||
|
+ MIN(dataSize-offset, CKY_MAX_WRITE_CHUNK_SIZE));
|
||
|
+ }
|
||
|
+
|
||
|
+ pasd.chain = 0;
|
||
|
+ pasd.len = outputSize;
|
||
|
+
|
||
|
+ ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt,
|
||
|
+ &pasd, NULL, CKY_SIZE_UNKNOWN,
|
||
|
+ pivAppletFill_AppendUnwrapBuffer,
|
||
|
+ &prsd, apduRC);
|
||
|
+
|
||
|
+ if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != outputSize)) {
|
||
|
+ /* RSA returns the same data size as input, didn't happen, so
|
||
|
+ * something is wrong. */
|
||
|
+ }
|
||
|
+
|
||
|
+done:
|
||
|
+ CKYBuffer_FreeData(&tmp);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
|
||
|
/*
|
||
|
* PIN cluster
|
||
|
diff -up ./src/libckyapplet/cky_applet.h.piv-ecc ./src/libckyapplet/cky_applet.h
|
||
|
--- ./src/libckyapplet/cky_applet.h.piv-ecc 2013-09-08 15:50:33.099428337 -0700
|
||
|
+++ ./src/libckyapplet/cky_applet.h 2013-09-08 15:50:33.127428807 -0700
|
||
|
@@ -43,6 +43,8 @@ typedef unsigned short CKYISOStatus; /*
|
||
|
#define CKYISO_MORE_MASK 0xff00 /* More data mask */
|
||
|
#define CKYISO_MORE 0x6300 /* More data available */
|
||
|
#define CKYISO_DATA_INVALID 0x6984
|
||
|
+#define CKYISO_CONDITION_NOT_SATISFIED 0x6985 /* AKA not logged in (CAC)*/
|
||
|
+#define CKYISO_SECURITY_NOT_SATISFIED 0x6982 /* AKA not logged in (PIV)*/
|
||
|
/* Applet Defined Return codes */
|
||
|
#define CKYISO_NO_MEMORY_LEFT 0x9c01 /* There have been memory
|
||
|
* problems on the card */
|
||
|
@@ -78,6 +80,7 @@ typedef unsigned short CKYISOStatus; /*
|
||
|
|
||
|
#define CAC_TAG_CARDURL 0xf3
|
||
|
#define CAC_TAG_CERTIFICATE 0x70
|
||
|
+#define CAC_TAG_CERTINFO 0x71
|
||
|
#define CAC_TLV_APP_PKI 0x04
|
||
|
|
||
|
/*
|
||
|
@@ -218,12 +221,47 @@ typedef struct _CKYAppletArgComputeCrypt
|
||
|
const CKYBuffer *sig;
|
||
|
} CKYAppletArgComputeCrypt;
|
||
|
|
||
|
+typedef struct _CKYAppletArgComputeECCSignature {
|
||
|
+ CKYByte keyNumber;
|
||
|
+ CKYByte location;
|
||
|
+ const CKYBuffer *data;
|
||
|
+ const CKYBuffer *sig;
|
||
|
+} CKYAppletArgComputeECCSignature;
|
||
|
+
|
||
|
+typedef struct _CKYAppletArgComputeECCKeyAgreement {
|
||
|
+ CKYByte keyNumber;
|
||
|
+ CKYByte location;
|
||
|
+ const CKYBuffer *publicValue;
|
||
|
+ const CKYBuffer *secretKey;
|
||
|
+} CKYAppletArgComputeECCKeyAgreement;
|
||
|
+
|
||
|
+
|
||
|
typedef struct _CACAppletArgReadFile {
|
||
|
CKYByte type;
|
||
|
CKYByte count;
|
||
|
unsigned short offset;
|
||
|
} CACAppletArgReadFile;
|
||
|
|
||
|
+typedef struct _PIVAppletArgSignDecrypt {
|
||
|
+ CKYByte alg;
|
||
|
+ CKYByte key;
|
||
|
+ CKYByte chain;
|
||
|
+ CKYSize len;
|
||
|
+ CKYBuffer *buf;
|
||
|
+} PIVAppletArgSignDecrypt;
|
||
|
+
|
||
|
+typedef struct _pivUnwrapState {
|
||
|
+ CKYByte tag;
|
||
|
+ CKYByte length;
|
||
|
+ int length_bytes;
|
||
|
+} PIVUnwrapState;
|
||
|
+
|
||
|
+typedef struct _PIVAppletRespSignDecrypt {
|
||
|
+ PIVUnwrapState tag_1;
|
||
|
+ PIVUnwrapState tag_2;
|
||
|
+ CKYBuffer *buf;
|
||
|
+} PIVAppletRespSignDecrypt;
|
||
|
+
|
||
|
/* fills in an APDU from a structure -- form of all the generic factories*/
|
||
|
typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param);
|
||
|
/* fills in an a structure from a response -- form of all the fill structures*/
|
||
|
@@ -335,7 +373,6 @@ CKYStatus CKYAppletFill_AppendBuffer(con
|
||
|
/* Single value fills: Byte, Short, & Long */
|
||
|
/* param == CKYByte * */
|
||
|
CKYStatus CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param);
|
||
|
-/* param == CKYByte * */
|
||
|
CKYStatus CKYAppletFill_Short(const CKYBuffer *response, CKYSize size, void *param);
|
||
|
CKYStatus CKYAppletFill_Long(const CKYBuffer *response, CKYSize size, void *param);
|
||
|
|
||
|
@@ -361,7 +398,7 @@ CKYBool CKYApplet_VerifyResponse(const C
|
||
|
* Sends the ADPU to the card through the connection conn.
|
||
|
* Checks that the response was valid (returning the responce code in apduRC.
|
||
|
* Formats the response data into fillArg with fillFunc
|
||
|
- * nonce and apduRC can be NULL (no nonce is added, not status returned
|
||
|
+ * nonce and apduRC can be NULL (no nonce is added, no status returned
|
||
|
* legal values for afArg are depened on afFunc.
|
||
|
* legal values for fillArg are depened on fillFunc.
|
||
|
*/
|
||
|
@@ -377,7 +414,7 @@ CKYStatus CKYApplet_HandleAPDU(CKYCardCo
|
||
|
* into function calls, with input and output parameters.
|
||
|
* The application is still responsible for
|
||
|
* 1) creating a connection to the card,
|
||
|
- * 2) Getting a tranaction long, then
|
||
|
+ * 2) Getting a transaction lock, then
|
||
|
* 3) selecting the appropriate applet (or Card manager).
|
||
|
* Except for those calls that have been noted, the appropriate applet
|
||
|
* is the CoolKey applet.
|
||
|
@@ -490,9 +527,18 @@ CKYStatus CACApplet_GetCertificateAppend
|
||
|
CKYISOStatus *apduRC);
|
||
|
|
||
|
/*CKYStatus CACApplet_GetProperties(); */
|
||
|
-CKYStatus CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin,
|
||
|
- CKYISOStatus *apduRC);
|
||
|
+CKYStatus CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin,
|
||
|
+ int local, CKYISOStatus *apduRC);
|
||
|
|
||
|
+/* Select a PIV applet */
|
||
|
+CKYStatus PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC);
|
||
|
+
|
||
|
+CKYStatus PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert,
|
||
|
+ int tag, CKYISOStatus *apduRC);
|
||
|
+CKYStatus PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
|
||
|
+ unsigned int keySize, int derive,
|
||
|
+ const CKYBuffer *data, CKYBuffer *result,
|
||
|
+ CKYISOStatus *apduRC);
|
||
|
/*
|
||
|
* There are 3 read commands:
|
||
|
*
|
||
|
@@ -553,6 +599,18 @@ CKYStatus CKYApplet_GetIssuerInfo(CKYCar
|
||
|
CKYStatus CKYApplet_GetBuiltinACL(CKYCardConnection *conn,
|
||
|
CKYAppletRespGetBuiltinACL *gba, CKYISOStatus *apduRC);
|
||
|
|
||
|
+/** ECC commands
|
||
|
+ * * */
|
||
|
+
|
||
|
+CKYStatus CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
|
||
|
+ const CKYBuffer *data, CKYBuffer *sig,
|
||
|
+ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
|
||
|
+ const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
|
||
|
+ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
|
||
|
+
|
||
|
|
||
|
/*
|
||
|
* deprecates 0.x functions
|
||
|
diff -up ./src/libckyapplet/cky_base.c.piv-ecc ./src/libckyapplet/cky_base.c
|
||
|
--- ./src/libckyapplet/cky_base.c.piv-ecc 2013-09-08 15:50:33.100428354 -0700
|
||
|
+++ ./src/libckyapplet/cky_base.c 2013-09-08 15:50:33.128428824 -0700
|
||
|
@@ -41,6 +41,7 @@ ckyBuffer_initBuffer(CKYBuffer *buf)
|
||
|
buf->data = NULL;
|
||
|
buf->size = 0;
|
||
|
buf->len = 0;
|
||
|
+ buf->reserved = NULL; /* make coverity happy */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -573,6 +574,7 @@ CKYAPDU_Init(CKYAPDU *apdu)
|
||
|
assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
|
||
|
#endif
|
||
|
ckyBuffer_initBuffer(&apdu->apduBuf);
|
||
|
+ apdu->reserved = NULL;
|
||
|
return CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_MIN_LEN);
|
||
|
}
|
||
|
|
||
|
@@ -583,6 +585,7 @@ CKYAPDU_InitFromData(CKYAPDU *apdu, cons
|
||
|
assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
|
||
|
#endif
|
||
|
ckyBuffer_initBuffer(&apdu->apduBuf);
|
||
|
+ apdu->reserved = NULL;
|
||
|
if (len > CKYAPDU_MAX_DATA_LEN) {
|
||
|
return CKYDATATOOLONG;
|
||
|
}
|
||
|
@@ -710,8 +713,15 @@ CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKY
|
||
|
return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, recvlen);
|
||
|
}
|
||
|
|
||
|
+CKYStatus
|
||
|
+CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen)
|
||
|
+{
|
||
|
+ return CKYBuffer_AppendChar(&apdu->apduBuf, recvlen);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
void
|
||
|
-CKY_SetName(char *p)
|
||
|
+CKY_SetName(const char *p)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
diff -up ./src/libckyapplet/cky_base.h.piv-ecc ./src/libckyapplet/cky_base.h
|
||
|
--- ./src/libckyapplet/cky_base.h.piv-ecc 2013-09-08 15:50:33.100428354 -0700
|
||
|
+++ ./src/libckyapplet/cky_base.h 2013-09-08 15:50:33.128428824 -0700
|
||
|
@@ -278,9 +278,10 @@ CKYStatus CKYAPDU_AppendSendDataBuffer(C
|
||
|
/* set Le in the APDU header to the amount of bytes expected to be
|
||
|
* returned. */
|
||
|
CKYStatus CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
|
||
|
+CKYStatus CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
|
||
|
|
||
|
/* set the parent loadmodule name */
|
||
|
-void CKY_SetName(char *name);
|
||
|
+void CKY_SetName(const char *name);
|
||
|
|
||
|
CKY_END_PROTOS
|
||
|
|
||
|
diff -up ./src/libckyapplet/cky_card.c.piv-ecc ./src/libckyapplet/cky_card.c
|
||
|
--- ./src/libckyapplet/cky_card.c.piv-ecc 2013-09-08 15:50:33.109428505 -0700
|
||
|
+++ ./src/libckyapplet/cky_card.c 2013-09-08 15:50:33.128428824 -0700
|
||
|
@@ -27,6 +27,7 @@
|
||
|
|
||
|
#ifndef WINAPI
|
||
|
#define WINAPI
|
||
|
+typedef SCARD_READERSTATE *LPSCARD_READERSTATE;
|
||
|
#endif
|
||
|
|
||
|
#ifndef SCARD_E_NO_READERS_AVAILABLE
|
||
|
@@ -843,6 +844,11 @@ CKYCardContext_WaitForStatusChange(CKYCa
|
||
|
rv = ctx->scard->SCardGetStatusChange(ctx->context, timeout,
|
||
|
readers, readerCount);
|
||
|
if (rv != SCARD_S_SUCCESS) {
|
||
|
+ if ((rv == SCARD_E_NO_SERVICE) || (rv == SCARD_E_SERVICE_STOPPED)) {
|
||
|
+ /* if we were stopped, don't reuse the old context,
|
||
|
+ * pcsc-lite hangs */
|
||
|
+ ckyCardContext_release(ctx);
|
||
|
+ }
|
||
|
ctx->lastError = rv;
|
||
|
return CKYSCARDERR;
|
||
|
}
|
||
|
@@ -1071,25 +1077,39 @@ CKYCardConnection_ExchangeAPDU(CKYCardCo
|
||
|
CKYBuffer *response)
|
||
|
{
|
||
|
CKYStatus ret;
|
||
|
+ CKYBuffer getResponse;
|
||
|
+ CKYSize size = 0;
|
||
|
|
||
|
ret = CKYCardConnection_TransmitAPDU(conn, apdu, response);
|
||
|
if (ret != CKYSUCCESS) {
|
||
|
return ret;
|
||
|
}
|
||
|
+ CKYBuffer_InitEmpty(&getResponse);
|
||
|
|
||
|
- if (CKYBuffer_Size(response) == 2 && CKYBuffer_GetChar(response,0) == 0x61) {
|
||
|
+ /* automatically handle the response data protocol */
|
||
|
+ while ((ret == CKYSUCCESS) &&
|
||
|
+ (size = CKYBuffer_Size(response)) >= 2 &&
|
||
|
+ (CKYBuffer_GetChar(response,size-2) == 0x61)) {
|
||
|
/* get the response */
|
||
|
CKYAPDU getResponseAPDU;
|
||
|
|
||
|
+ CKYBuffer_Zero(&getResponse);
|
||
|
CKYAPDU_Init(&getResponseAPDU);
|
||
|
CKYAPDU_SetCLA(&getResponseAPDU, 0x00);
|
||
|
CKYAPDU_SetINS(&getResponseAPDU, 0xc0);
|
||
|
CKYAPDU_SetP1(&getResponseAPDU, 0x00);
|
||
|
CKYAPDU_SetP2(&getResponseAPDU, 0x00);
|
||
|
- CKYAPDU_SetReceiveLen(&getResponseAPDU, CKYBuffer_GetChar(response,1));
|
||
|
- ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU, response);
|
||
|
+ CKYAPDU_SetReceiveLen(&getResponseAPDU,
|
||
|
+ CKYBuffer_GetChar(response,size-1));
|
||
|
+ ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU,
|
||
|
+ &getResponse);
|
||
|
CKYAPDU_FreeData(&getResponseAPDU);
|
||
|
+ if ((ret == CKYSUCCESS) && (CKYBuffer_Size(&getResponse) >= 2)) {
|
||
|
+ CKYBuffer_Resize(response, size-2);
|
||
|
+ CKYBuffer_AppendCopy(response,&getResponse);
|
||
|
+ }
|
||
|
}
|
||
|
+ CKYBuffer_FreeData(&getResponse);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
diff -up ./src/libckyapplet/cky_card.h.piv-ecc ./src/libckyapplet/cky_card.h
|
||
|
diff -up ./src/libckyapplet/cky_factory.c.piv-ecc ./src/libckyapplet/cky_factory.c
|
||
|
--- ./src/libckyapplet/cky_factory.c.piv-ecc 2013-09-08 15:50:33.101428370 -0700
|
||
|
+++ ./src/libckyapplet/cky_factory.c 2013-09-08 15:50:33.129428841 -0700
|
||
|
@@ -62,7 +62,6 @@ CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu
|
||
|
CKYAPDU_SetP2(apdu, 0x7f);
|
||
|
return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_CPLCDATA);
|
||
|
}
|
||
|
-
|
||
|
/*
|
||
|
* applet commands must be issued with the appplet selected.
|
||
|
*/
|
||
|
@@ -184,6 +183,49 @@ fail:
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
+CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte keyNumber,
|
||
|
+ CKYByte location,
|
||
|
+ const CKYBuffer *publicData, const CKYBuffer *secretKey)
|
||
|
+{
|
||
|
+ CKYStatus ret = CKYINVALIDARGS;
|
||
|
+ CKYSize len;
|
||
|
+ CKYBuffer buf;
|
||
|
+
|
||
|
+ if (!publicData)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ if (!(len = CKYBuffer_Size(publicData)))
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
|
||
|
+ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_KEY_AGREEMENT);
|
||
|
+ CKYAPDU_SetP1(apdu, keyNumber);
|
||
|
+ CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&buf);
|
||
|
+
|
||
|
+ ret = CKYBuffer_Reserve(&buf, 3);
|
||
|
+
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYBuffer_AppendChar(&buf, location);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, publicData);
|
||
|
+ if (ret == CKYSUCCESS && secretKey && 0 < (len = CKYBuffer_Size(secretKey))) {
|
||
|
+ CKYBuffer_Resize(&buf,2);
|
||
|
+ CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, secretKey);
|
||
|
+ }
|
||
|
+ CKYBuffer_FreeData(&buf);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber, CKYByte mode,
|
||
|
CKYByte direction, CKYByte location,
|
||
|
const CKYBuffer *idata, const CKYBuffer *sig)
|
||
|
@@ -386,6 +428,49 @@ fail:
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
+CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
|
||
|
+ CKYByte location,
|
||
|
+ const CKYBuffer *idata, const CKYBuffer *sig)
|
||
|
+{
|
||
|
+ CKYStatus ret = CKYINVALIDARGS;
|
||
|
+ CKYSize len;
|
||
|
+ CKYBuffer buf;
|
||
|
+
|
||
|
+ if (!idata)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
|
||
|
+ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_SIGNATURE);
|
||
|
+ CKYAPDU_SetP1(apdu, keyNumber);
|
||
|
+ CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&buf);
|
||
|
+
|
||
|
+ ret = CKYBuffer_Reserve(&buf, 3);
|
||
|
+
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYBuffer_AppendChar(&buf, location);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, idata);
|
||
|
+ if (ret == CKYSUCCESS && sig && 0 < (len = CKYBuffer_Size(sig))) {
|
||
|
+ CKYBuffer_Resize(&buf,2);
|
||
|
+ CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
|
||
|
+ if (ret == CKYSUCCESS)
|
||
|
+ ret = CKYAPDU_AppendSendDataBuffer(apdu, sig);
|
||
|
+ }
|
||
|
+ CKYBuffer_FreeData(&buf);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
CKYAPDUFactory_ReadObject(CKYAPDU *apdu, unsigned long objectID,
|
||
|
CKYOffset offset, CKYByte size)
|
||
|
{
|
||
|
@@ -622,7 +707,6 @@ fail:
|
||
|
CKYBuffer_FreeData(&buf);
|
||
|
return ret;
|
||
|
}
|
||
|
-
|
||
|
CKYStatus
|
||
|
CACAPDUFactory_GetProperties(CKYAPDU *apdu)
|
||
|
{
|
||
|
@@ -634,7 +718,7 @@ CACAPDUFactory_GetProperties(CKYAPDU *ap
|
||
|
}
|
||
|
|
||
|
CKYStatus
|
||
|
-CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin)
|
||
|
+CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const char *pin)
|
||
|
{
|
||
|
CKYStatus ret;
|
||
|
CKYSize size;
|
||
|
@@ -642,7 +726,7 @@ CACAPDUFactory_VerifyPIN(CKYAPDU *apdu,
|
||
|
CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
|
||
|
CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN);
|
||
|
CKYAPDU_SetP1(apdu, 0x00);
|
||
|
- CKYAPDU_SetP2(apdu, 0x00);
|
||
|
+ CKYAPDU_SetP2(apdu, keyRef);
|
||
|
/* no pin, send an empty buffer */
|
||
|
if (!pin) {
|
||
|
return CKYAPDU_SetReceiveLen(apdu, 0);
|
||
|
@@ -663,3 +747,63 @@ CACAPDUFactory_VerifyPIN(CKYAPDU *apdu,
|
||
|
return ret;
|
||
|
|
||
|
}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg,
|
||
|
+ CKYByte key, int len, const CKYBuffer *data)
|
||
|
+{
|
||
|
+ CKYStatus ret;
|
||
|
+ CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN :
|
||
|
+ CKY_CLASS_ISO7816);
|
||
|
+ CKYAPDU_SetINS(apdu, PIV_INS_GEN_AUTHENTICATE);
|
||
|
+ CKYAPDU_SetP1(apdu, alg);
|
||
|
+ CKYAPDU_SetP2(apdu, key);
|
||
|
+ ret = CKYAPDU_SetSendDataBuffer(apdu, data);
|
||
|
+ if (ret == CKYSUCCESS && chain == 0 && len != 0) {
|
||
|
+ if (len >= 256) len = 0;
|
||
|
+ ret = CKYAPDU_AppendReceiveLen(apdu, len);
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+CKYStatus
|
||
|
+PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object, CKYByte count)
|
||
|
+{
|
||
|
+ CKYStatus ret;
|
||
|
+ CKYBuffer buf;
|
||
|
+ CKYByte objectSize;
|
||
|
+
|
||
|
+ CKYBuffer_InitEmpty(&buf);
|
||
|
+ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
|
||
|
+ CKYAPDU_SetINS(apdu, 0xcb);
|
||
|
+ CKYAPDU_SetP1(apdu, 0x3f);
|
||
|
+ CKYAPDU_SetP2(apdu, 0xff);
|
||
|
+
|
||
|
+ objectSize = CKYBuffer_Size(object);
|
||
|
+
|
||
|
+ ret = CKYBuffer_Reserve(&buf, 2+objectSize);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ ret = CKYBuffer_AppendChar(&buf, 0x5c);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ ret = CKYBuffer_AppendChar(&buf, objectSize);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ ret = CKYBuffer_AppendCopy(&buf, object);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
|
||
|
+ if (ret != CKYSUCCESS) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ ret = CKYAPDU_AppendReceiveLen(apdu, count);
|
||
|
+fail:
|
||
|
+ CKYBuffer_FreeData(&buf);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
diff -up ./src/libckyapplet/cky_factory.h.piv-ecc ./src/libckyapplet/cky_factory.h
|
||
|
--- ./src/libckyapplet/cky_factory.h.piv-ecc 2013-09-08 15:50:33.101428370 -0700
|
||
|
+++ ./src/libckyapplet/cky_factory.h 2013-09-08 15:50:33.130428858 -0700
|
||
|
@@ -25,10 +25,11 @@
|
||
|
/*
|
||
|
* Various Class bytes
|
||
|
*/
|
||
|
-#define CKY_CLASS_ISO7816 0x00
|
||
|
+#define CKY_CLASS_ISO7816 0x00
|
||
|
+#define CKY_CLASS_ISO7816_CHAIN 0x10
|
||
|
#define CKY_CLASS_GLOBAL_PLATFORM 0x80
|
||
|
-#define CKY_CLASS_SECURE 0x84
|
||
|
-#define CKY_CLASS_COOLKEY 0xb0
|
||
|
+#define CKY_CLASS_SECURE 0x84
|
||
|
+#define CKY_CLASS_COOLKEY 0xb0
|
||
|
|
||
|
/*
|
||
|
* Applet Instruction Bytes
|
||
|
@@ -66,6 +67,8 @@
|
||
|
/* nonce validated & Secure Channel */
|
||
|
#define CKY_INS_IMPORT_KEY 0x32
|
||
|
#define CKY_INS_COMPUTE_CRYPT 0x36
|
||
|
+#define CKY_INS_COMPUTE_ECC_SIGNATURE 0x37
|
||
|
+#define CKY_INS_COMPUTE_ECC_KEY_AGREEMENT 0x38
|
||
|
#define CKY_INS_CREATE_PIN 0x40
|
||
|
#define CKY_INS_CHANGE_PIN 0x44
|
||
|
#define CKY_INS_CREATE_OBJ 0x5A
|
||
|
@@ -91,6 +94,12 @@
|
||
|
#define CAC_SIZE_GET_PROPERTIES 48
|
||
|
#define CAC_P1_STEP 0x80
|
||
|
#define CAC_P1_FINAL 0x00
|
||
|
+#define CAC_LOGIN_GLOBAL 0x00
|
||
|
+
|
||
|
+/* PIV */
|
||
|
+#define PIV_LOGIN_LOCAL 0x80
|
||
|
+#define PIV_LOGIN_GLOBAL CAC_LOGIN_GLOBAL
|
||
|
+#define PIV_INS_GEN_AUTHENTICATE 0x87
|
||
|
|
||
|
/*
|
||
|
* Fixed return sized from various commands
|
||
|
@@ -123,6 +132,7 @@
|
||
|
#define CKY_DES_ECB_NOPAD 0x21
|
||
|
|
||
|
/* operations (Cipher Direction) */
|
||
|
+#define CKY_DIR_NONE 0x00
|
||
|
#define CKY_DIR_SIGN 0x01
|
||
|
#define CKY_DIR_VERIFY 0x02
|
||
|
#define CKY_DIR_ENCRYPT 0x03
|
||
|
@@ -187,6 +197,12 @@ CKYStatus CKYAPDUFactory_ComputeCryptFin
|
||
|
CKYStatus CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber,
|
||
|
CKYByte mode, CKYByte direction, CKYByte location,
|
||
|
const CKYBuffer *data, const CKYBuffer *sig);
|
||
|
+CKYStatus CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
|
||
|
+ CKYByte location,
|
||
|
+ const CKYBuffer *data, const CKYBuffer *sig);
|
||
|
+CKYStatus CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte keyNumber,
|
||
|
+ CKYByte location,
|
||
|
+ const CKYBuffer *publicData, const CKYBuffer *secretKey);
|
||
|
CKYStatus CKYAPDUFactory_CreatePIN(CKYAPDU *apdu, CKYByte pinNumber,
|
||
|
CKYByte maxAttempts, const char *pinValue);
|
||
|
CKYStatus CKYAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte pinNumber,
|
||
|
@@ -218,11 +234,16 @@ CKYStatus CKYAPDUFactory_GetBuiltinACL(C
|
||
|
|
||
|
CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type,
|
||
|
const CKYBuffer *data);
|
||
|
-CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin);
|
||
|
+CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef,
|
||
|
+ const char *pin);
|
||
|
CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size);
|
||
|
CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset,
|
||
|
CKYByte type, CKYByte count);
|
||
|
CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu);
|
||
|
+CKYStatus PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object,
|
||
|
+ CKYByte count);
|
||
|
+CKYStatus PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg,
|
||
|
+ CKYByte key, int len, const CKYBuffer *data);
|
||
|
|
||
|
CKY_END_PROTOS
|
||
|
|