diff --git a/coolkey-1.1.0-fail-on-bad-mechanisms.patch b/coolkey-1.1.0-fail-on-bad-mechanisms.patch deleted file mode 100644 index 1a113c6..0000000 --- a/coolkey-1.1.0-fail-on-bad-mechanisms.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff -up ./src/coolkey/coolkey.cpp.fail-on-bad-mechanisms ./src/coolkey/coolkey.cpp ---- ./src/coolkey/coolkey.cpp.fail-on-bad-mechanisms 2016-06-16 14:36:05.934755563 -0700 -+++ ./src/coolkey/coolkey.cpp 2016-06-16 14:36:05.945755372 -0700 -@@ -77,7 +77,8 @@ rsaMechanismList[] = { - - 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} } -+ {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, -+ {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } - }; - - unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo); -diff -up ./src/coolkey/slot.cpp.fail-on-bad-mechanisms ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.fail-on-bad-mechanisms 2016-06-16 14:36:05.943755407 -0700 -+++ ./src/coolkey/slot.cpp 2016-06-16 15:07:40.255882660 -0700 -@@ -4185,11 +4185,30 @@ Slot::signInit(SessionHandleSuffix suffi - { - refreshTokenState(); - SessionIter session = findSession(suffix); -+ PKCS11Object *key = getKeyFromHandle(hKey); - if( session == sessions.end() ) { - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } -+ if (pMechanism == NULL) { -+ throw PKCS11Exception(CKR_ARGUMENTS_BAD); -+ } -+ -+ switch (pMechanism->mechanism) { -+ case CKM_RSA_PKCS: -+ if (key->getKeyType() != Key::rsa) { -+ throw PKCS11Exception(CKR_KEY_TYPE_INCONSISTENT); -+ } -+ break; -+ case CKM_ECDSA: -+ if (key->getKeyType() != Key::ecc) { -+ throw PKCS11Exception(CKR_KEY_TYPE_INCONSISTENT); -+ } -+ break; -+ default: -+ throw PKCS11Exception(CKR_MECHANISM_INVALID); -+ } - -- session->signatureState.initialize(getKeyFromHandle(hKey)); -+ session->signatureState.initialize(key); - } - - void -@@ -4198,11 +4217,24 @@ Slot::decryptInit(SessionHandleSuffix su - { - refreshTokenState(); - SessionIter session = findSession(suffix); -+ PKCS11Object *key = getKeyFromHandle(hKey); - if( session == sessions.end() ) { - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } -+ if (pMechanism == NULL) { -+ throw PKCS11Exception(CKR_ARGUMENTS_BAD); -+ } -+ switch (pMechanism->mechanism) { -+ case CKM_RSA_PKCS: -+ if (key->getKeyType() != Key::rsa) { -+ throw PKCS11Exception(CKR_KEY_TYPE_INCONSISTENT); -+ } -+ break; -+ default: -+ throw PKCS11Exception(CKR_MECHANISM_INVALID); -+ } - -- session->decryptionState.initialize(getKeyFromHandle(hKey)); -+ session->decryptionState.initialize(key); - } - - /** -@@ -5008,8 +5040,23 @@ Slot::derive(SessionHandleSuffix suffix, - - ECCKeyAgreementParams params(CryptParams::ECC_DEFAULT_KEY_SIZE); - SessionIter session = findSession(suffix); -+ PKCS11Object *key=getKeyFromHandle(hBaseKey); - -- session->keyAgreementState.initialize(getKeyFromHandle(hBaseKey)); -+ if (pMechanism == NULL ) { -+ throw PKCS11Exception(CKR_ARGUMENTS_BAD); -+ } -+ -+ switch (pMechanism->mechanism) { -+ case CKM_ECDH1_DERIVE: -+ if (key->getKeyType() != Key::ecc) { -+ throw PKCS11Exception(CKR_KEY_TYPE_INCONSISTENT); -+ } -+ break; -+ default: -+ throw PKCS11Exception(CKR_MECHANISM_INVALID); -+ } -+ -+ session->keyAgreementState.initialize(key); - deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, - phKey, params); - -@@ -5018,9 +5065,6 @@ Slot::derive(SessionHandleSuffix suffix, - 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; - diff --git a/coolkey-1.1.0-fix-spurious-event.patch b/coolkey-1.1.0-fix-spurious-event.patch deleted file mode 100644 index 6e4114c..0000000 --- a/coolkey-1.1.0-fix-spurious-event.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -up ./src/coolkey/slot.cpp.fix-spurious ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.fix-spurious 2014-09-26 15:31:17.277958895 -0700 -+++ ./src/coolkey/slot.cpp 2014-09-26 15:34:33.218313227 -0700 -@@ -1412,6 +1412,7 @@ SlotList::waitForSlotEvent(CK_FLAGS flag - #endif - } while ((status == CKYSUCCESS) || - (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) || -+ (CKYCardContext_GetLastError(context) == SCARD_E_UNKNOWN_READER) || - (CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE) || - (CKYCardContext_GetLastError(context) == SCARD_E_NO_SERVICE) || - (CKYCardContext_GetLastError(context) == SCARD_E_SERVICE_STOPPED) ); diff --git a/coolkey-1.1.0-max-cpu-bug.patch b/coolkey-1.1.0-max-cpu-bug.patch deleted file mode 100644 index cf90313..0000000 --- a/coolkey-1.1.0-max-cpu-bug.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up ./src/coolkey/slot.cpp.max-cpu-bug ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.max-cpu-bug 2016-06-30 14:36:10.502785885 -0700 -+++ ./src/coolkey/slot.cpp 2016-06-30 14:36:15.812876256 -0700 -@@ -1875,6 +1875,8 @@ SlotList::waitForSlotEvent(CK_FLAGS flag - if (status != CKYSUCCESS) { - if ((CKYCardContext_GetLastError(context) == - SCARD_E_READER_UNAVAILABLE) || -+ (CKYCardContext_GetLastError(context) == -+ SCARD_E_UNKNOWN_READER) || - (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT)) { - OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY); - } diff --git a/coolkey-1.1.0-more-keys.patch b/coolkey-1.1.0-more-keys.patch deleted file mode 100644 index 94dceb9..0000000 --- a/coolkey-1.1.0-more-keys.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff -up ./src/coolkey/slot.cpp.more_keys ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.more_keys 2016-06-16 11:50:01.027432856 -0700 -+++ ./src/coolkey/slot.cpp 2016-06-16 11:50:13.267224824 -0700 -@@ -32,7 +32,8 @@ - - #define MIN(x, y) ((x) < (y) ? (x) : (y)) - -- -+#define MAX_NUM_KEYS 32 -+#define MAX_NUM_CERTS 32 - - #ifdef DEBUG - #define PRINTF(args) printf args -@@ -3458,7 +3459,7 @@ Slot::loadObjects() - } else if( type == 'c' ) { - // cert attribute object. find the DER encoding - unsigned short certnum = getObjectIndex(iter->obj.objectID); -- if( certnum > 9 ) { -+ if( certnum > MAX_NUM_CERTS ) { - //invalid object id - throw PKCS11Exception(CKR_DEVICE_ERROR, - "Invalid object id %08x",iter->obj.objectID); -@@ -4154,7 +4155,7 @@ Slot::objectToKeyNum(const PKCS11Object - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); - } - unsigned short keyNum = getObjectIndex(id); -- if( keyNum > 9 ) { -+ if( keyNum > MAX_NUM_KEYS ) { - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); - } - return keyNum & 0xFF; -@@ -4911,7 +4912,6 @@ Slot::generateRandom(SessionHandleSuffix - } - } - --#define MAX_NUM_KEYS 8 - unsigned int - Slot::getRSAKeySize(PKCS11Object *key) - { -diff -up ./src/coolkey/slot.h.more_keys ./src/coolkey/slot.h ---- ./src/coolkey/slot.h.more_keys 2016-06-16 11:50:08.627303984 -0700 -+++ ./src/coolkey/slot.h 2016-06-16 11:54:08.872153180 -0700 -@@ -512,7 +512,17 @@ class Slot { - return (char) (objectID >> 24) & 0xff; - } - unsigned short getObjectIndex(unsigned long objectID) const { -- return (char )((objectID >> 16) & 0xff) - '0'; -+ char char_index = (char) ((objectID >> 16) & 0xff); -+ if (char_index >= '0' && char_index <= '9') { -+ return char_index - '0'; -+ } -+ if (char_index >= 'A' && char_index <= 'Z') { -+ return char_index - 'A' + 10; -+ } -+ if (char_index >= 'a' && char_index <= 'z') { -+ return char_index - 'a' + 26 + 10; -+ } -+ return 0x0100 + char_index; - } - - // actually get the size of a key in bits from the card diff --git a/coolkey-1.1.0-noapplet.patch b/coolkey-1.1.0-noapplet.patch deleted file mode 100644 index 45f2760..0000000 --- a/coolkey-1.1.0-noapplet.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff -up ./src/coolkey/slot.cpp.noapplet ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.noapplet 2013-09-30 14:30:40.069595018 -0700 -+++ ./src/coolkey/slot.cpp 2013-09-30 14:31:27.488595000 -0700 -@@ -762,13 +762,7 @@ Slot::connectToToken() - 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(); -+ /* CARD is unknown */ - return; - } - state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; diff --git a/coolkey-1.1.0-p15-coverity.patch b/coolkey-1.1.0-p15-coverity.patch deleted file mode 100644 index 4ae1092..0000000 --- a/coolkey-1.1.0-p15-coverity.patch +++ /dev/null @@ -1,210 +0,0 @@ -diff -up ./src/coolkey/object.cpp.p15-coverity ./src/coolkey/object.cpp ---- ./src/coolkey/object.cpp.p15-coverity 2015-07-06 18:02:34.604191118 -0700 -+++ ./src/coolkey/object.cpp 2015-07-06 19:06:04.432062377 -0700 -@@ -1558,7 +1558,7 @@ unsigned long GetBits(const CKYByte *ent - /* turn the flags into an int */ - for (i=0; i < entrySize; i++) { - CKYByte c = rev[entry[i]]; -- bits = bits | (c << i*8); -+ bits = bits | (((unsigned long)c) << (i*8)); - } - return bits | bitFlag; - } -@@ -1585,8 +1585,8 @@ CKYStatus PK15ObjectPath::setObjectPath( - if (entry == NULL) { return CKYINVALIDDATA; } - tagSize = entry - current; - current += entrySize + tagSize; -+ if (size < (entrySize + tagSize)) { return CKYINVALIDDATA; } - size -= (entrySize +tagSize); -- if (size < 0) { return CKYINVALIDDATA; } - status = CKYBuffer_Replace(&path, 0, entry, entrySize); - if (status != CKYSUCCESS) { - return status; -@@ -1598,8 +1598,8 @@ CKYStatus PK15ObjectPath::setObjectPath( - if (entry == NULL) { return CKYINVALIDDATA; } - tagSize = entry - current; - current += entrySize + tagSize; -+ if (size < (entrySize + tagSize)) { return CKYINVALIDDATA; } - size -= (entrySize +tagSize); -- if (size < 0) { return CKYINVALIDDATA; } - if (entrySize > 5) { return CKYINVALIDDATA; } - for (index = 0, i=0; i < entrySize; i++) { - index = (index << 8) + (unsigned int) entry[i]; -@@ -1612,8 +1612,8 @@ CKYStatus PK15ObjectPath::setObjectPath( - if (entry == NULL) { return CKYINVALIDDATA; } - tagSize = entry - current; - current += entrySize + tagSize; -+ if (size < (entrySize + tagSize)) { return CKYINVALIDDATA; } - size -= (entrySize +tagSize); -- if (size < 0) { return CKYINVALIDDATA; } - if (entrySize > 5) { return CKYINVALIDDATA; } - for (length = 0, i=0; i < entrySize; i++) { - length = (length << 8) + (unsigned int) entry[i]; -@@ -1741,8 +1741,8 @@ set_key_type: - /* point current to the next section (cass attributes) */ - tagSize = commonAttributes - current; - current += commonSize + tagSize; -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } - currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } - - /* get the CKA_LABEL */ - if (commonAttributes[0] != ASN1_UTF8_STRING) { return CKYINVALIDDATA; } -@@ -1835,8 +1835,8 @@ PK15Object::completeCertObject(const CKY - /* point current to the next section (type attributes) */ - tagSize = commonCertAttributes - current; - current += commonSize + tagSize; -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } - currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } - - /* get the id */ - if (commonCertAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; } -@@ -1907,8 +1907,8 @@ PK15Object::completeAuthObject(const CKY - if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; } - tagSize = commonAuthAttributes - current; - current += commonSize + tagSize; -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } - currentSize -= (commonSize + tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } - if (commonAuthAttributes[0] != ASN1_OCTET_STRING) { - return CKYINVALIDDATA; - } -@@ -1930,8 +1930,8 @@ PK15Object::completeAuthObject(const CKY - if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; } - tagSize = commonAuthAttributes - current; - current += commonSize + tagSize; -- currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } -+ currentSize -= (commonSize + tagSize); - /* - * parse the Pin Auth Attributes - * pinFlags BIT_STRING -@@ -2093,8 +2093,8 @@ PK15Object::completeKeyObject(const CKYB - /* point current to the next section (sublcass attributes) */ - tagSize = commonKeyAttributes - current; - current += commonSize + tagSize; -- currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } -+ currentSize -= (commonSize + tagSize); - - /* get the id */ - if (commonKeyAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; } -@@ -2263,8 +2263,8 @@ CKYStatus PK15Object::completePrivKeyObj - /* point current to the next section (type attributes) */ - tagSize = commonPrivKeyAttributes - current; - current += commonSize + tagSize; -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } - currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } - - /* subjectName */ - if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) { -@@ -2385,8 +2385,8 @@ PK15Object::completePubKeyObject(const C - /* point current to the next section (type attributes) */ - tagSize = commonPubKeyAttributes - current; - current += commonSize + tagSize; -- currentSize -= (commonSize +tagSize); -- if (currentSize < 0) { return CKYINVALIDDATA; } -+ if (currentSize < (commonSize + tagSize)) { return CKYINVALIDDATA; } -+ currentSize -= (commonSize + tagSize); - - /* subjectName */ - if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { -@@ -2535,8 +2535,8 @@ PK15Object::completeRawPublicKey(const C - if (entry == NULL) { return CKYINVALIDDATA; } - tagSize = entry - current; - current += entrySize + tagSize; -+ if (size < (entrySize + tagSize)) { return CKYINVALIDDATA; } - size -= (entrySize +tagSize); -- if (size < 0) { return CKYINVALIDDATA; } - if ((entry[0] == 0) && (entrySize > 1)) { - entry++; entrySize--; - } -@@ -2548,8 +2548,8 @@ PK15Object::completeRawPublicKey(const C - if (entry == NULL) { return CKYINVALIDDATA; } - tagSize = entry - current; - current += entrySize + tagSize; -- size -= (entrySize +tagSize); -- if (size < 0) { return CKYINVALIDDATA; } -+ if (size < (entrySize + tagSize)) { return CKYINVALIDDATA; } -+ size -= (entrySize + tagSize); - if ((entry[0] == 0) && (entrySize > 1)) { - entry++; entrySize--; - } -@@ -2682,11 +2682,11 @@ DEREncodedTokenInfo::DEREncodedTokenInfo - if (entry == NULL) return; - tagSize = entry - current; - current += tagSize + entrySize; -+ if (size < tagSize + entrySize) return; - size -= tagSize + entrySize; - if (entrySize < 1) { - version = *entry; - } -- if (size < 0) return; - - /* get the serial number */ - if (current[0] != ASN1_OCTET_STRING) { return ; } -@@ -2729,6 +2729,8 @@ DEREncodedTokenInfo::DEREncodedTokenInfo - } - - /* parsing flags */ -+#ifdef notdef -+ /* we arn't using this right now, keep it for future reference */ - if (current[0] == ASN1_BIT_STRING) { - /* recordinfo parsing would go here */ - unsigned long bits; -@@ -2739,6 +2741,7 @@ DEREncodedTokenInfo::DEREncodedTokenInfo - size -= tagSize + entrySize; - bits = GetBits(entry, entrySize,8,2); - } -+#endif - return; - } - -diff -up ./src/coolkey/slot.cpp.p15-coverity ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.p15-coverity 2015-07-06 18:02:34.606191081 -0700 -+++ ./src/coolkey/slot.cpp 2015-07-06 18:02:34.610191006 -0700 -@@ -3714,7 +3714,6 @@ void - Slot::attemptP15Login(CK_USER_TYPE user) - { - PinCache *pinCachePtr = userPinCache(user); -- const CKYBuffer *path; - - if (user == CKU_USER) { - loggedIn = false; -@@ -3729,7 +3728,6 @@ Slot::attemptP15Login(CK_USER_TYPE user) - "No PKCS #15 auth object for user %d\n", user); - } - -- path = auth[user]->getObjectPath().getPath(); - status = selectPath(auth[user]->getObjectPath().getPath(), &result); - if( status == CKYSCARDERR ) { - handleConnectionError(); -diff -up ./src/libckyapplet/cky_applet.c.p15-coverity ./src/libckyapplet/cky_applet.c ---- ./src/libckyapplet/cky_applet.c.p15-coverity 2015-07-06 18:02:34.606191081 -0700 -+++ ./src/libckyapplet/cky_applet.c 2015-07-06 18:02:34.610191006 -0700 -@@ -1361,6 +1361,9 @@ P15Applet_SignDecrypt(CKYCardConnection - appendLength = length; - } else { - ret = CKYBuffer_Reserve(&tmp, length); -+ if (ret != CKYSUCCESS) { -+ goto done; -+ } - } - CKYBuffer_AppendBuffer(&tmp, data, offset, appendLength); - pso.chain = 0; -diff -up ./src/libckyapplet/cky_base.c.p15-coverity ./src/libckyapplet/cky_base.c ---- ./src/libckyapplet/cky_base.c.p15-coverity 2015-07-06 18:02:34.607191062 -0700 -+++ ./src/libckyapplet/cky_base.c 2015-07-06 18:02:34.610191006 -0700 -@@ -736,7 +736,7 @@ CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu - CKYStatus ret; - - if (recvlen <= CKYAPDU_MAX_DATA_LEN) { -- return APDU_SetReceiveLen(apdu, (CKYByte)(recvlen & 0xff)); -+ return CKYAPDU_SetReceiveLen(apdu, (CKYByte)(recvlen & 0xff)); - } - ret = CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_HEADER_LEN+2); - if (ret != CKYSUCCESS) { diff --git a/coolkey-1.1.0-p15.patch b/coolkey-1.1.0-p15.patch deleted file mode 100644 index 75724ea..0000000 --- a/coolkey-1.1.0-p15.patch +++ /dev/null @@ -1,4379 +0,0 @@ -diff -up ./src/coolkey/coolkey.cpp.p15 ./src/coolkey/coolkey.cpp ---- ./src/coolkey/coolkey.cpp.p15 2015-07-06 10:27:55.769827286 -0700 -+++ ./src/coolkey/coolkey.cpp 2015-07-06 10:27:55.784827002 -0700 -@@ -599,13 +599,10 @@ C_Login(CK_SESSION_HANDLE hSession, CK_U - } - try { - log->log("C_Login called\n"); -- if( userType != CKU_USER ) { -- throw PKCS11Exception(CKR_USER_TYPE_INVALID); -- } - if( pPin == NULL ) { - throw PKCS11Exception(CKR_ARGUMENTS_BAD); - } -- slotList->login(hSession, pPin, ulPinLen); -+ slotList->login(hSession, userType, pPin, ulPinLen); - return CKR_OK; - } catch(PKCS11Exception &e) { - e.log(log); -diff -up ./src/coolkey/object.cpp.p15 ./src/coolkey/object.cpp ---- ./src/coolkey/object.cpp.p15 2015-07-06 10:27:55.770827267 -0700 -+++ ./src/coolkey/object.cpp 2015-07-06 10:27:55.785826984 -0700 -@@ -19,9 +19,9 @@ - - #include "mypkcs11.h" - #include "PKCS11Exception.h" --#include "object.h" - #include - #include -+#include "object.h" - - using std::find_if; - -@@ -29,7 +29,7 @@ const CKYByte rsaOID[] = {0x2A,0x86,0x48 - const CKYByte eccOID[] = {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01}; - - #ifdef DEBUG --void dump(CKYBuffer *buf) -+void dump(const char *label, const CKYBuffer *buf) - { - CKYSize i; - CKYSize size = CKYBuffer_Size(buf); -@@ -38,8 +38,10 @@ void dump(CKYBuffer *buf) - char *bp = &string[0]; - CKYByte c; - -+ printf("%s size=%d\n", label, (int)size); -+ - for (i=0; i < size; i++) { -- if (i && ((i % (ROW_LENGTH-1)) == 0) ) { -+ if (i && ((i % (ROW_LENGTH)) == 0) ) { - *bp = 0; - printf(" %s\n",string); - bp = &string[0]; -@@ -49,7 +51,35 @@ void dump(CKYBuffer *buf) - *bp++ = (c < ' ') ? '.' : ((c & 0x80) ? '*' : c); - } - *bp = 0; -- for (i= (i % (ROW_LENGTH-1)); i && (i < ROW_LENGTH); i++) { -+ for (i= (i % (ROW_LENGTH)); i && (i < ROW_LENGTH); i++) { -+ printf(" "); -+ } -+ printf(" %s\n",string); -+ fflush(stdout); -+} -+ -+void dumpData(const char *label, const CKYByte *buf, CKYSize size) -+{ -+ CKYSize i; -+#define ROW_LENGTH 16 -+ char string[ROW_LENGTH+1]; -+ char *bp = &string[0]; -+ CKYByte c; -+ -+ printf("%s size=%d:\n",label, (int)size); -+ -+ for (i=0; i < size; i++) { -+ if (i && ((i % (ROW_LENGTH)) == 0) ) { -+ *bp = 0; -+ printf(" %s\n",string); -+ bp = &string[0]; -+ } -+ c = buf[i]; -+ printf("%02x ",c); -+ *bp++ = (c < ' ') ? '.' : ((c & 0x80) ? '*' : c); -+ } -+ *bp = 0; -+ for (i= (i % (ROW_LENGTH)); i && (i < ROW_LENGTH); i++) { - printf(" "); - } - printf(" %s\n",string); -@@ -77,16 +107,23 @@ class AttributeTypeMatch - }; - - PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_) -- : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL), keyType(unknown) -+ : muscleObjID(muscleObjID_), handle(handle_), label(NULL), keySize(0), -+ user(CKU_USER), name(NULL), keyType(unknown), -+ keyRef(PK15_INVALID_KEY_REF) - { - CKYBuffer_InitEmpty(&pubKey); -+ CKYBuffer_InitEmpty(&authId); -+ CKYBuffer_InitEmpty(&pinAuthId); - } - - PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data, - CK_OBJECT_HANDLE handle_) : muscleObjID(muscleObjID_), handle(handle_), -- label(NULL), name(NULL), keyType(unknown) -+ label(NULL), keySize(0), user(CKU_USER), name(NULL), -+ keyType(unknown), keyRef(PK15_INVALID_KEY_REF) - { - CKYBuffer_InitEmpty(&pubKey); -+ CKYBuffer_InitEmpty(&authId); -+ CKYBuffer_InitEmpty(&pinAuthId); - - CKYByte type = CKYBuffer_GetChar(data,0); - // verify object ID is what we think it is -@@ -582,6 +619,21 @@ PKCS11Object::setAttribute(CK_ATTRIBUTE_ - } - - void -+PKCS11Object::setAttribute(CK_ATTRIBUTE_TYPE type, const CKYByte *data, -+ CKYSize size) -+{ -+ AttributeIter iter; -+ -+ iter = find_if(attributes.begin(), attributes.end(), -+ AttributeTypeMatch(type)); -+ if( iter != attributes.end() ) { -+ iter->setValue( data, size); -+ } else { -+ attributes.push_back(PKCS11Attribute(type, data, size)); -+ } -+} -+ -+void - PKCS11Object::setAttribute(CK_ATTRIBUTE_TYPE type, const char *string) - { - CKYBuffer buf; -@@ -613,7 +665,7 @@ PKCS11Object::setAttributeULong(CK_ATTRI - - typedef struct { - const CKYByte*data; -- unsigned int len; -+ CKYSize len; - } CCItem; - - typedef enum { -@@ -621,9 +673,9 @@ typedef enum { - SECFailure=1 - } SECStatus; - --static const CKYByte* --dataStart(const CKYByte *buf, unsigned int length, -- unsigned int *data_length, bool includeTag) { -+const CKYByte* -+dataStart(const CKYByte *buf, CKYSize length, -+ CKYSize *data_length, bool includeTag) { - unsigned char tag; - unsigned int used_length= 0; - -@@ -673,7 +725,7 @@ dataStart(const CKYByte *buf, unsigned i - } - - static const CKYByte * --unwrapBitString(const CKYByte *buf, unsigned int len, unsigned int *retLen) -+unwrapBitString(const CKYByte *buf, CKYSize len, CKYSize *retLen) - { - /* for RSA, bit string always has byte number of bits */ - if (buf[0] != 0) { -@@ -687,15 +739,15 @@ unwrapBitString(const CKYByte *buf, unsi - } - - static SECStatus --GetECKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length, -+GetECKeyFieldItems(const CKYByte *spki_data, CKYSize spki_length, - CCItem *point, CCItem *params) - { - const CKYByte *buf = spki_data; -- unsigned int buf_length = spki_length; -+ CKYSize buf_length = spki_length; - const CKYByte *algid; -- unsigned int algidlen; -+ CKYSize algidlen; - const CKYByte *dummy; -- unsigned int dummylen; -+ CKYSize dummylen; - - if (!point || !params || !buf) - return SECFailure; -@@ -756,12 +808,12 @@ GetKeyOIDMatches(const CKYByte *spki_dat - } - - static SECStatus --GetKeyAlgorithmId(const CKYByte *spki_data, unsigned int spki_length, -+GetKeyAlgorithmId(const CKYByte *spki_data, CKYSize spki_length, - CCItem *algorithmId) - { - - const CKYByte *buf = spki_data; -- unsigned int buf_length = spki_length; -+ CKYSize buf_length = spki_length; - - if ( algorithmId == NULL) return SECFailure; - -@@ -786,7 +838,7 @@ GetKeyTypeFromSPKI(const CKYBuffer *key) - "Failed to decode key algorithm ID."); - } - -- unsigned int length = 0; -+ CKYSize length = 0; - const CKYByte *keyData = NULL; - - /* Get actual oid buffer */ -@@ -829,13 +881,13 @@ GetKeyTypeFromSPKI(const CKYBuffer *key) - } - - static SECStatus --GetKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length, -+GetKeyFieldItems(const CKYByte *spki_data,CKYSize spki_length, - CCItem *modulus, CCItem *exponent) - { - const CKYByte *buf = spki_data; -- unsigned int buf_length = spki_length; -+ CKYSize buf_length = spki_length; - const CKYByte*dummy; -- unsigned int dummylen; -+ CKYSize dummylen; - - /* skip past the algorithm id */ - dummy = dataStart(buf,buf_length,&dummylen,false); -@@ -955,7 +1007,7 @@ Key::Key(unsigned long muscleObjID, cons - } - - void --Key::completeKey(const PKCS11Object &cert) -+PKCS11Object::completeKey(const PKCS11Object &cert) - { - // infer key attributes from cert - bool modulusExists, exponentExists; -@@ -1015,14 +1067,14 @@ Key::completeKey(const PKCS11Object &cer - } - - static SECStatus --GetCertFieldItems(const CKYByte *dercert,unsigned int cert_length, -+GetCertFieldItems(const CKYByte *dercert, CKYSize cert_length, - CCItem *issuer, CCItem *serial, CCItem *derSN, CCItem *subject, - CCItem *valid, CCItem *subjkey) - { - const CKYByte *buf; -- unsigned int buf_length; -+ CKYSize buf_length; - const CKYByte*dummy; -- unsigned int dummylen; -+ CKYSize dummylen; - - /* get past the signature wrap */ - buf = dataStart(dercert,cert_length,&buf_length, false); -@@ -1330,10 +1382,10 @@ static const unsigned char CN_DATA[] = { - const unsigned int CN_LENGTH = sizeof(CN_DATA); - - static SECStatus --GetCN(const CKYByte *dn, unsigned int dn_length, CCItem *cn) -+GetCN(const CKYByte *dn, CKYSize dn_length, CCItem *cn) - { - const CKYByte *buf; -- unsigned int buf_length; -+ CKYSize buf_length; - - /* unwrap the sequence */ - buf = dataStart(dn,dn_length,&buf_length, false); -@@ -1341,9 +1393,9 @@ GetCN(const CKYByte *dn, unsigned int dn - - while (buf_length) { - const CKYByte *name; -- unsigned int name_length; -+ CKYSize name_length; - const CKYByte *oid; -- unsigned int oid_length; -+ CKYSize oid_length; - - /* unwrap the set */ - name = dataStart(buf, buf_length, &name_length, false); -@@ -1408,13 +1460,6 @@ CACCert::CACCert(CKYByte instance, const - { - CKYBuffer id; - CKYBuffer empty; -- CK_BBOOL decrypt = FALSE; -- -- /* So we know what the key is supposed to be used for based on -- * the instance */ -- if (instance == 2) { -- decrypt = TRUE; -- } - - CKYBuffer_InitEmpty(&empty); - setAttributeULong(CKA_CLASS, CKO_CERTIFICATE); -@@ -1456,6 +1501,1063 @@ CACCert::CACCert(CKYByte instance, const - CKYBuffer_FreeData(&derIssuer); - } - -+static const CKYByte rev[] = { -+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, -+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, -+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, -+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, -+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, -+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, -+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, -+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, -+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, -+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, -+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, -+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, -+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, -+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, -+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, -+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, -+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, -+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, -+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, -+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, -+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, -+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, -+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, -+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, -+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, -+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, -+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, -+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, -+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, -+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, -+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, -+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -+}; -+ -+unsigned long GetBits(const CKYByte *entry, CKYSize entrySize, -+ unsigned int numBits, unsigned int numBytes) -+{ -+ unsigned long bits = 0; -+ unsigned long bitFlag = 0; -+ unsigned int i; -+ -+ /* size of zero is valid for no bits */ -+ if (entrySize <= 1) { -+ return 0; -+ } -+ entrySize--; -+ entry++; -+ -+ /* if we are longer than and unsigned, just bail now */ -+ if (entrySize > sizeof (unsigned long)) { -+ bitFlag = BROKEN_FLAG; -+ entrySize = sizeof(unsigned long); -+ } -+ /* turn the flags into an int */ -+ for (i=0; i < entrySize; i++) { -+ CKYByte c = rev[entry[i]]; -+ bits = bits | (c << i*8); -+ } -+ return bits | bitFlag; -+} -+ -+ -+/* -+ * parse the path object. -+ * Caller has already unwrapped the outer ASN1Sequence -+ */ -+CKYStatus PK15ObjectPath::setObjectPath(const CKYByte *current, CKYSize size) -+{ -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ unsigned int i; -+ CKYStatus status; -+ -+ -+ if ((current == NULL) || (current[0] != ASN1_OCTET_STRING)) { -+ return CKYINVALIDDATA; -+ } -+ /* entry */ -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ tagSize = entry - current; -+ current += entrySize + tagSize; -+ size -= (entrySize +tagSize); -+ if (size < 0) { return CKYINVALIDDATA; } -+ status = CKYBuffer_Replace(&path, 0, entry, entrySize); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ -+ /* index */ -+ if ((size != 0) && current[0] == ASN1_INTEGER) { -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ tagSize = entry - current; -+ current += entrySize + tagSize; -+ size -= (entrySize +tagSize); -+ if (size < 0) { return CKYINVALIDDATA; } -+ if (entrySize > 5) { return CKYINVALIDDATA; } -+ for (index = 0, i=0; i < entrySize; i++) { -+ index = (index << 8) + (unsigned int) entry[i]; -+ } -+ } -+ -+ /* length */ -+ if ((size != 0) && ((current[0]|ASN1_CONSTRUCTED) == ASN1_CHOICE_0)) { -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ tagSize = entry - current; -+ current += entrySize + tagSize; -+ size -= (entrySize +tagSize); -+ if (size < 0) { return CKYINVALIDDATA; } -+ if (entrySize > 5) { return CKYINVALIDDATA; } -+ for (length = 0, i=0; i < entrySize; i++) { -+ length = (length << 8) + (unsigned int) entry[i]; -+ } -+ } -+ return CKYSUCCESS; -+} -+ -+static unsigned int pK15GetTag(PK15ObjectType type) { -+ switch (type) { case PK15PvKey: case PK15PuKey: return 'k'<<24; -+ case PK15Cert: return 'c' << 24; default: break; } -+ return 'v'; -+} -+ -+ -+PK15Object::PK15Object(CKYByte inst, PK15ObjectType type, -+ const CKYByte *der, CKYSize derSize) -+ : PKCS11Object(pK15GetTag(type) | ((inst+'0') << 16), 0xa000 | inst) -+{ -+ CKYStatus status; -+ -+ instance = inst; -+ p15Type = type; -+ CKYBuffer_InitEmpty(&authId); -+ CKYBuffer_InitEmpty(&pinAuthId); -+ state = PK15StateInit; -+ pinInfo.pinFlags = 0; -+ pinInfo.pinType = P15PinUTF8; -+ pinInfo.minLength = 4; -+ pinInfo.storedLength = 0; -+ pinInfo.maxLength = 0; -+ pinInfo.pinRef = 0; -+ pinInfo.padChar = 0xff; -+ -+ status = completeObject(der, derSize); -+ if (status != CKYSUCCESS) { -+ state = PK15StateInit; /* don't try to fetch any more if we failed */ -+ } -+} -+ -+/* returns true if there is more work to do... */ -+CKYStatus -+PK15Object::completeObject(const CKYByte *current, CKYSize currentSize) -+{ -+ const CKYByte *commonAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYByte objectTag; -+ CKYStatus status; -+ CKYBitFlags bits; -+ -+ switch (state) { -+ case PK15StateInit: -+ case PK15StateNeedObject: -+ break; -+ case PK15StateNeedRawPublicKey: -+ return completeRawPublicKey(current, currentSize); -+ case PK15StateNeedRawCertificate: -+ return completeRawCertificate(current, currentSize); -+ case PK15StateComplete: -+ return CKYSUCCESS; -+ } -+ -+ if (current == NULL) { return CKYINVALIDARGS; } -+ -+ objectTag = current[0]; -+ -+ setAttributeBool(CKA_TOKEN, TRUE); -+ -+ /* set type specific attributes */ -+ switch (p15Type) { -+ case PK15Cert: -+ setAttributeULong(CKA_CLASS, CKO_CERTIFICATE); -+ setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509); -+ if (objectTag != PK15X509CertType) { -+ return CKYUNSUPPORTED; -+ } -+ break; -+ case PK15PvKey: -+ setAttributeULong(CKA_CLASS, CKO_PRIVATE_KEY); -+ goto set_key_type; -+ case PK15PuKey: -+ setAttributeULong(CKA_CLASS, CKO_PUBLIC_KEY); -+set_key_type: -+ switch (objectTag) { -+ case PK15RSAKeyType: -+ keyType = rsa; -+ setAttributeULong(CKA_KEY_TYPE, CKK_RSA); -+ break; -+ case PK15ECCKeyType: -+ keyType = ecc; -+ setAttributeULong(CKA_KEY_TYPE, CKK_EC); -+ break; -+ case PK15DSAKeyType: -+ case PK15DHKeyType: -+ default: -+ return CKYUNSUPPORTED; -+ } -+ break; -+ case PK15AuthObj: -+ setAttributeULong(CKA_CLASS, CKO_DATA); -+ break; -+ default: -+ return CKYUNSUPPORTED; -+ } -+ -+ /* unwrap the object */ -+ current = dataStart(current, currentSize, ¤tSize, false); -+ if (current == NULL) { return CKYINVALIDDATA; } -+ -+ /* -+ * parse the Common Attributes -+ * label UTF8_STRING -+ * flags BIT_STRING (optional) -+ * authid OCTET_STRING (optional) -+ */ -+ if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) -+ { return CKYINVALIDDATA; } -+ /* unwrap */ -+ commonAttributes = dataStart(current, currentSize, &commonSize, false); -+ if (commonAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* point current to the next section (cass attributes) */ -+ tagSize = commonAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ -+ /* get the CKA_LABEL */ -+ if (commonAttributes[0] != ASN1_UTF8_STRING) { return CKYINVALIDDATA; } -+ entry = dataStart(commonAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAttributes; -+ commonAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_LABEL, entry, entrySize); -+ -+ /* parse optional flags */ -+ bits = BROKEN_FLAG; -+ if (commonAttributes[0] == ASN1_BIT_STRING) { -+ entry = dataStart(commonAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAttributes; -+ commonAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ bits = GetBits(entry,entrySize,2,1); -+ } -+ -+ if (commonAttributes[0] == ASN1_OCTET_STRING) { -+ entry = dataStart(commonAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAttributes; -+ commonAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ status = CKYBuffer_Replace(&authId, 0, entry, entrySize); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ } -+ -+ if (bits & BROKEN_FLAG) { -+ bits = defaultCommonBits(); -+ } -+ setAttributeBool(CKA_PRIVATE, -+ (bits & P15FlagsPrivate) ? TRUE: FALSE); -+ setAttributeBool(CKA_MODIFIABLE, FALSE); /* our token is ReadOnly, so the -+ * object is never modifiable for -+ * us */ -+ /* future common attributes here */ -+ -+ /* -+ * Parse Class variables -+ * -+ */ -+ switch (p15Type) { -+ case PK15Cert: -+ status = completeCertObject(current,currentSize); -+ break; -+ case PK15PuKey: -+ case PK15PvKey: -+ status = completeKeyObject(current,currentSize); -+ break; -+ case PK15AuthObj: -+ status = completeAuthObject(current, currentSize); -+ break; -+ } -+ return status; -+} -+ -+ -+CKYStatus -+PK15Object::completeCertObject(const CKYByte *current, CKYSize currentSize) -+{ -+ const CKYByte *commonCertAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYBuffer empty; -+ CKYStatus status; -+ CKYByte valueTag; -+ -+ CKYBuffer_InitEmpty(&empty); -+ -+ /* -+ * parse the Common Cert Attributes -+ * id OCTET_STRING -+ * authority BOOLEAN DEFAULT FALSE -+ * requestId BIT_STRING (optional) -+ * thumbprint [0] PKS15OOBCertHash (optional) -+ */ -+ if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) -+ { return CKYINVALIDARGS; } -+ /* unwrap */ -+ commonCertAttributes = dataStart(current, currentSize, &commonSize, false); -+ if (commonCertAttributes == NULL) { return CKYINVALIDDATA; } -+ /* point current to the next section (type attributes) */ -+ tagSize = commonCertAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ -+ /* get the id */ -+ if (commonCertAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; } -+ entry = dataStart(commonCertAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonCertAttributes; -+ commonCertAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_ID, entry, entrySize); -+ -+ -+ /* skip authority (currently unused) */ -+ /* skip requestID */ -+ /* skip thumbprint */ -+ /* future common cert attributes here */ -+ -+ /* certs have not subclass attributes ASN1_CHOICE_0 */ -+ -+ /* handle the X509 type attributes */ -+ if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; } -+ /* unwrap */ -+ commonCertAttributes = dataStart(current, currentSize, &commonSize, false); -+ if (commonCertAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* -+ * PCKS11X504CertificateAttributes -+ * value SEQUENCE or CHOICE_0 -+ * ... don't care about the rest. -+ */ -+ valueTag = commonCertAttributes[0]; -+ /* unwrapp */ -+ entry = dataStart(commonCertAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ if (valueTag == ASN1_SEQUENCE) { -+ entry = dataStart(entry, entrySize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ /* if we have a path, the actual object is in another file, -+ * tell the caller to get it and come back here */ -+ status = objectPath.setObjectPath(entry, entrySize); -+ state = PK15StateNeedRawCertificate; -+ return status; -+ } -+ if (valueTag != ASN1_CHOICE_0) { -+ return CKYINVALIDDATA; -+ } -+ return completeRawCertificate(entry, entrySize); -+} -+ -+CKYStatus -+PK15Object::completeAuthObject(const CKYByte *current, CKYSize currentSize) -+{ -+ const CKYByte *commonAuthAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYBuffer empty; -+ CKYStatus status; -+ -+ CKYBuffer_InitEmpty(&empty); -+ -+ if (current == NULL) { return CKYINVALIDARGS; } -+ /* common Auth attributes */ -+ if (current[0] == ASN1_SEQUENCE) { -+ /* unwrap */ -+ commonAuthAttributes = -+ dataStart(current, currentSize, &commonSize, false); -+ if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; } -+ tagSize = commonAuthAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize + tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ if (commonAuthAttributes[0] != ASN1_OCTET_STRING) { -+ return CKYINVALIDDATA; -+ } -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ status = CKYBuffer_Replace(&pinAuthId, 0, entry, entrySize); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ -+ } -+ /* auth specific values */ -+ if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDARGS; } -+ /* unwrap */ -+ commonAuthAttributes = dataStart(current, currentSize, &commonSize, false); -+ if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; } -+ tagSize = commonAuthAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ /* -+ * parse the Pin Auth Attributes -+ * pinFlags BIT_STRING -+ * pinType ENUMERATED (bcd, ascii-numeric, utf8) -+ * minLength INTEGER -+ * storedLength INTEGER -+ * maxlength INTEGER (optional) -+ * pinReference CHOICE_0 (optional) -+ * padChar OCTET_STRING (optional) -+ * lastPinChange GENERALIZED_TIME (optional) -+ * path PKCS15Path (optional) -+ */ -+ if (commonAuthAttributes[0] != ASN1_SEQUENCE) { return CKYINVALIDARGS; } -+ commonAuthAttributes = dataStart(commonAuthAttributes, -+ commonSize, &commonSize, false); -+ if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* parse pin flags */ -+ if (commonAuthAttributes[0] != ASN1_BIT_STRING) { return CKYINVALIDDATA; } -+ -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ pinInfo.pinFlags = GetBits(entry,entrySize,9,2); -+ -+ -+ /* parse PinType */ -+ if (commonAuthAttributes[0] != ASN1_ENUMERATED) { return CKYINVALIDDATA; } -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ /* turn entry into an int */ -+ if (entrySize > 1) { return CKYINVALIDARGS; } -+ pinInfo.pinType = (P15PinType) *entry; -+ -+ /* parse minLength */ -+ if (commonAuthAttributes[0] != ASN1_INTEGER) { return CKYINVALIDDATA; } -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 1) { return CKYINVALIDARGS; } -+ pinInfo.minLength = *entry; -+ -+ /* parse storedLength */ -+ if (commonAuthAttributes[0] != ASN1_INTEGER) { return CKYINVALIDDATA; } -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 1) { return CKYINVALIDARGS; } -+ pinInfo.storedLength = *entry; -+ -+ /* parse maxLength (optional) */ -+ if (commonAuthAttributes[0] == ASN1_INTEGER) { -+ unsigned long maxPin; -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > sizeof (maxPin)) { return CKYINVALIDARGS; } -+ maxPin = 0; -+ CKYSize i; -+ for (i=0; i < entrySize; i++) { -+ maxPin = (maxPin << 8) | entry[i]; -+ } -+ pinInfo.maxLength = maxPin; -+ } -+ -+ /* parse pin ref (optional) */ -+ if ((commonAuthAttributes[0]|ASN1_CONSTRUCTED) == ASN1_CHOICE_0) { -+ CKYByte pinRef; -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 2) { return CKYINVALIDARGS; } -+ if (entrySize == 2) { -+ if (*entry != 0) { return CKYINVALIDARGS; } -+ pinRef = entry[1]; -+ } else pinRef = entry[0]; -+ pinInfo.pinRef = pinRef; -+ } -+ -+ /* parse padChar */ -+ if (commonAuthAttributes[0] == ASN1_OCTET_STRING) { -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 1) { return CKYINVALIDARGS; } -+ pinInfo.padChar = *entry; -+ } -+ -+ /* skip lastPinChange */ -+ if (commonAuthAttributes[0] == ASN1_GENERALIZED_TIME) { -+ entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ } -+ /* parse path */ -+ if (commonAuthAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonAuthAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonAuthAttributes; -+ commonAuthAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ /* if we have a path, the actual object is in another file, -+ * tell the caller to get it and come back here */ -+ status = objectPath.setObjectPath(entry, entrySize); -+ if (status != CKYSUCCESS) { return status; } -+ } -+ state = PK15StateComplete; -+ return CKYSUCCESS; -+} -+ -+CKYStatus -+PK15Object::completeKeyObject(const CKYByte *current, CKYSize currentSize) -+{ -+ const CKYByte *commonKeyAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYBuffer empty; -+ CKYStatus status; -+ unsigned long bits; -+ /*bool native; */ -+ -+ CKYBuffer_InitEmpty(&empty); -+ /* -+ * parse the Common Key Attributes -+ * id OCTET_STRING -+ * usageFlags BIT_STRING -+ * native BOOLEAN DEFAULT TRUE -+ * accessFlags BIT_STRING (optional) -+ * keyReference OCTET_STRING (optional) -+ * startDate GENERALIZED_TIME (optional) -+ * endDate [0] GENERALIZED_TYPE (optional) -+ */ -+ if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) -+ { return CKYINVALIDARGS; } -+ /* unwrap */ -+ commonKeyAttributes = dataStart(current, currentSize, &commonSize, false); -+ if (commonKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* point current to the next section (sublcass attributes) */ -+ tagSize = commonKeyAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ -+ /* get the id */ -+ if (commonKeyAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; } -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_ID, entry, entrySize); -+ -+ /* parse flags */ -+ if (commonKeyAttributes[0] != ASN1_BIT_STRING) { return CKYINVALIDDATA; } -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ bits = GetBits(entry,entrySize,10,2); -+ if (bits & BROKEN_FLAG) { -+ bits = defaultUsageBits(); -+ } -+ setAttributeBool(CKA_ENCRYPT, -+ (bits & P15UsageEncrypt) ? TRUE : FALSE); -+ setAttributeBool(CKA_DECRYPT, -+ (bits & P15UsageDecrypt) ? TRUE : FALSE); -+ setAttributeBool(CKA_SIGN, -+ (bits & P15UsageSign) ? TRUE : FALSE); -+ setAttributeBool(CKA_SIGN_RECOVER, -+ (bits & P15UsageSignRecover) ? TRUE : FALSE); -+ setAttributeBool(CKA_WRAP, -+ (bits & P15UsageWrap) ? TRUE : FALSE); -+ setAttributeBool(CKA_UNWRAP, -+ (bits & P15UsageUnwrap) ? TRUE : FALSE); -+ setAttributeBool(CKA_VERIFY, -+ (bits & P15UsageVerify) ? TRUE : FALSE); -+ setAttributeBool(CKA_VERIFY_RECOVER, -+ (bits & P15UsageVerifyRecover) ? TRUE : FALSE); -+ setAttributeBool(CKA_DERIVE, -+ (bits & P15UsageDerive) ? TRUE : FALSE); -+ /* no CKA value for P15UsageNonRepudiation */ -+ if (bits & P15UsageNonRepudiation) { -+ /* set signing and sign recover. Non-repudiation keys are automatically -+ * signing keys */ -+ setAttributeBool(CKA_SIGN, TRUE); -+ if (keyType == rsa) { -+ setAttributeBool(CKA_SIGN_RECOVER, TRUE); -+ } -+ } -+ -+ /* parse native (currently unused) */ -+ /*native=true; */ -+ if (commonKeyAttributes[0] == ASN1_BOOLEAN) { -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ /*if ((entrySize == 1) && (entry[0] == 0)) { -+ native = false; -+ } */ -+ } -+ /* parse access flags */ -+ bits = BROKEN_FLAG; -+ if (commonKeyAttributes[0] == ASN1_BIT_STRING) { -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ bits = GetBits(entry,entrySize,4,1); -+ } -+ if (bits & BROKEN_FLAG) { -+ bits = defaultAccessBits(); -+ } -+ setAttributeBool(CKA_SENSITIVE, -+ (bits & P15AccessSensitive) ? TRUE : FALSE); -+ setAttributeBool(CKA_EXTRACTABLE, -+ (bits & P15AccessExtractable) ? TRUE : FALSE); -+ setAttributeBool(CKA_ALWAYS_SENSITIVE, -+ (bits & P15AccessAlwaysSenstive) ? TRUE : FALSE); -+ setAttributeBool(CKA_NEVER_EXTRACTABLE, -+ (bits & P15AccessNeverExtractable)? TRUE : FALSE); -+ setAttributeBool(CKA_LOCAL, -+ (bits & P15AccessLocal) ? TRUE : FALSE); -+ -+ /* parse the key reference */ -+ keyRef = PK15_INVALID_KEY_REF; /* invalid keyRef */ -+ if (commonKeyAttributes[0] == ASN1_INTEGER) { -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize == 1) { -+ keyRef = entry[0]; -+ } else if ((entrySize == 2) && (entry[0] == 0)) { -+ keyRef = entry[1]; -+ } -+ } -+ setAttribute(CKA_START_DATE, &empty); -+ if (commonKeyAttributes[0] == ASN1_GENERALIZED_TIME) { -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_START_DATE,entry, entrySize); -+ } -+ setAttribute(CKA_END_DATE, &empty); -+ if (commonKeyAttributes[0] == ASN1_CHOICE_0) { -+ entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonKeyAttributes; -+ commonKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_END_DATE,entry, entrySize); -+ } -+ /* future common key attributes here */ -+ -+ /* -+ * Parse Class variables -+ * -+ */ -+ switch (p15Type) { -+ case PK15PuKey: -+ status = completePubKeyObject(current,currentSize); -+ break; -+ case PK15PvKey: -+ status = completePrivKeyObject(current,currentSize); -+ break; -+ default: -+ status=CKYLIBFAIL; /* shouldn't happen */ -+ break; -+ } -+ return status; -+} -+ -+CKYStatus PK15Object::completePrivKeyObject(const CKYByte *current, -+ CKYSize currentSize) -+{ -+ const CKYByte *commonPrivKeyAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYBuffer empty; -+ CKYStatus status; -+ unsigned int modulusSize; -+ unsigned int i; -+ -+ CKYBuffer_InitEmpty(&empty); -+ if (current == NULL) { return CKYINVALIDARGS; } -+ -+ /* optional subclass = CommonPrivateKeyAttributes */ -+ if (current[0] == ASN1_CHOICE_0) { -+ /* -+ * PKCS15CommonPrivateKeyAttributes -+ * -+ * subjectName SEQUENCE optional -+ * keyIdentifiers CHOICE 0 optional -+ */ -+ /* unwrap */ -+ commonPrivKeyAttributes = -+ dataStart(current, currentSize, &commonSize, false); -+ if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ /* point current to the next section (type attributes) */ -+ tagSize = commonPrivKeyAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ -+ /* subjectName */ -+ if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonPrivKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPrivKeyAttributes; -+ commonPrivKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_SUBJECT, entry, entrySize); -+ } -+ -+ /* keyIdentfiers */ -+ /* future CommonPrivateKeyAttributes here */ -+ } -+ -+ -+ /* Type attributes (either PKCS15RSAPrivateKeyAttributes or -+ * PKCS15ECCPrivateKeyAttributes) -- Not Optional */ -+ if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; } -+ /* -+ * PKCS15RSAPrivateKeyAttributes -+ * value PKCS15ObjectValue -+ * modulusLength INTEGER -+ * keyInfo SEQUENCE optional -+ * PKCS15ECCPrivateKeyAttributes -+ * value PKCS15ObjectValue -+ * keyInfo SEQUENCE optional -+ */ -+ /* unwrap */ -+ commonPrivKeyAttributes = -+ dataStart(current, currentSize, &commonSize, false); -+ if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* value */ -+ /* don't support direct private key objects */ -+ if (commonPrivKeyAttributes[0] == ASN1_CHOICE_0) { return CKYUNSUPPORTED; } -+ if (commonPrivKeyAttributes[0] != ASN1_SEQUENCE) { return CKYINVALIDDATA; } -+ commonPrivKeyAttributes = dataStart(commonPrivKeyAttributes, commonSize, &commonSize, false); -+ if (commonPrivKeyAttributes == NULL) { return CKYINVALIDARGS; } -+ entry = dataStart(commonPrivKeyAttributes, commonSize, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPrivKeyAttributes; -+ commonPrivKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ /* if we have a path, the actual object is in another file, -+ * tell the caller to get it and come back here */ -+ status = objectPath.setObjectPath(entry, entrySize); -+ if (status != CKYSUCCESS) { return status; } -+ -+ /* parse modulus size */ -+ if ((keyType == rsa) && commonPrivKeyAttributes[0] == ASN1_INTEGER) { -+ entry = dataStart(commonPrivKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPrivKeyAttributes; -+ commonPrivKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 4) { -+ return CKYINVALIDDATA; -+ } -+ for (modulusSize = 0, i=0; i < entrySize; i++) { -+ modulusSize = (modulusSize << 8) + entry[i]; -+ } -+ setKeySize(modulusSize); -+ } -+ -+ if (keyType == rsa) { -+ state = PK15StateComplete; -+ return CKYSUCCESS; /* we're done with RSA */ -+ } -+ -+ /* parse keyinfo at this point all we are after is the EC_PARAM*/ -+ if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) { -+ /* unwrap */ -+ commonPrivKeyAttributes = dataStart(commonPrivKeyAttributes, -+ commonSize, &commonSize, true); -+ if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonPrivKeyAttributes, commonSize, -+ &entrySize, true); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ setAttribute(CKA_EC_PARAMS, entry, entrySize); -+ } -+ } -+ state = PK15StateComplete; -+ return CKYSUCCESS; -+} -+ -+CKYStatus -+PK15Object::completePubKeyObject(const CKYByte *current, CKYSize currentSize) -+{ -+ const CKYByte *commonPubKeyAttributes; -+ CKYSize commonSize; -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYBuffer empty; -+ CKYStatus status; -+ unsigned int modulusSize; -+ unsigned int i; -+ -+ CKYBuffer_InitEmpty(&empty); -+ if (current == NULL) { return CKYINVALIDDATA; } -+ -+ /* optional subclass = CommonPublicKeyAttributes */ -+ if (current[0] == ASN1_CHOICE_0) { -+ /* -+ * PKCS15CommonPublicKeyAttributes -+ * -+ * subjectName SEQUENCE optional -+ * keyIdentifiers CHOICE 0 optional -+ */ -+ /* unwrap */ -+ commonPubKeyAttributes = -+ dataStart(current, currentSize, &commonSize, false); -+ if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ /* point current to the next section (type attributes) */ -+ tagSize = commonPubKeyAttributes - current; -+ current += commonSize + tagSize; -+ currentSize -= (commonSize +tagSize); -+ if (currentSize < 0) { return CKYINVALIDDATA; } -+ -+ /* subjectName */ -+ if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonPubKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPubKeyAttributes; -+ commonPubKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ setAttribute(CKA_SUBJECT, entry, entrySize); -+ } -+ /* future CommonPublicKeyAttributes here */ -+ } -+ -+ -+ /* Type attributes (either PKCS15RSAPublicKeyAttributes or -+ * PKCS15ECCPublicKeyAttributes) -- Not Optional */ -+ if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; } -+ /* -+ * PKCS15RSAPublicKeyAttributes -+ * value PKCS15ObjectValue -+ * modulusLength INTEGER -+ * keyInfo SEQUENCE optional -+ * PKCS15ECCPublicKeyAttributes -+ * value PKCS15ObjectValue -+ * keyInfo SEQUENCE optional -+ */ -+ /* unwrap */ -+ commonPubKeyAttributes = -+ dataStart(current, currentSize, &commonSize, false); -+ if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ -+ /* value */ -+ if (commonPubKeyAttributes[0] == ASN1_CHOICE_0) { -+ entry = dataStart(commonPubKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ status = completeRawPublicKey(entry, entrySize); -+ if (status != CKYSUCCESS) { return status; } -+ } else if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonPubKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPubKeyAttributes; -+ commonPubKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ /* if we have a path, the actual object is in another file, -+ * tell the caller to get it and come back here */ -+ status = objectPath.setObjectPath(entry, entrySize); -+ if (status != CKYSUCCESS) { return status; } -+ state = PK15StateNeedRawPublicKey; -+ } -+ -+ /* parse modulus size */ -+ if ((keyType == rsa) && commonPubKeyAttributes[0] == ASN1_INTEGER) { -+ entry = dataStart(commonPubKeyAttributes, commonSize, -+ &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDARGS; } -+ tagSize = entry - commonPubKeyAttributes; -+ commonPubKeyAttributes += entrySize + tagSize; -+ commonSize -= (entrySize +tagSize); -+ if (entrySize > 4) { -+ return CKYINVALIDDATA; -+ } -+ for (modulusSize = 0, i=0; i < entrySize; i++) { -+ modulusSize = (modulusSize << 8) + entry[i]; -+ } -+ setKeySize(modulusSize); -+ } -+ -+ if (keyType == rsa) { -+ return CKYSUCCESS; /* we're done with RSA */ -+ } -+ -+ /* parse keyinfo at this point all we are after is the EC_PARAM*/ -+ if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { -+ /* unwrap */ -+ commonPubKeyAttributes = dataStart(commonPubKeyAttributes, -+ commonSize, &commonSize, true); -+ if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; } -+ if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { -+ entry = dataStart(commonPubKeyAttributes, commonSize, -+ &entrySize, true); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ setAttribute(CKA_EC_PARAMS, entry, entrySize); -+ } -+ } -+ return CKYSUCCESS; -+ -+} -+ -+CKYStatus -+PK15Object::completeRawCertificate(const CKYByte *derCert, CKYSize derCertSize) -+{ -+ SECStatus rv; -+ CCItem issuerItem, serialItem, derSerialItem, subjectItem, -+ validityItem, subjectKeyItem; -+ const char *certLabel; -+ -+ setAttribute(CKA_VALUE, derCert, derCertSize); -+ rv = GetCertFieldItems(derCert, derCertSize, -+ &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem, -+ &subjectKeyItem); -+ if (rv != SECSuccess) { -+ return CKYINVALIDDATA; -+ } -+ setAttribute(CKA_SERIAL_NUMBER, derSerialItem.data, derSerialItem.len); -+ setAttribute(CKA_SUBJECT, subjectItem.data, subjectItem.len); -+ setAttribute(CKA_ISSUER, issuerItem.data, issuerItem.len); -+ CKYBuffer_Replace(&pubKey, 0, subjectKeyItem.data, subjectKeyItem.len); -+ /* if we didn't get a label, set one based on the CN */ -+ certLabel = getLabel(); -+ if ((certLabel == NULL) || (*certLabel == 0)) { -+ CKYBuffer subject; -+ char *newLabel; -+ CKYBuffer_InitFromData(&subject, subjectItem.data, subjectItem.len); -+ newLabel = GetUserName(&subject); -+ if (newLabel) { -+ setAttribute(CKA_LABEL, (CKYByte *)newLabel, -+ (CKYSize) strlen(newLabel)-1); -+ delete [] newLabel; -+ } -+ CKYBuffer_FreeData(&subject); -+ } -+ state = PK15StateComplete; -+ return CKYSUCCESS; -+} -+ -+CKYStatus -+PK15Object::completeRawPublicKey(const CKYByte *current, CKYSize size) -+{ -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ -+ if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) { -+ return CKYINVALIDDATA; -+ } -+ /* unwrap*/ -+ current = dataStart(current, size, &size, false); -+ if (current == NULL) { return CKYINVALIDDATA; } -+ -+ /* modulus */ -+ if (current[0] != ASN1_INTEGER) { return CKYINVALIDDATA; } -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ tagSize = entry - current; -+ current += entrySize + tagSize; -+ size -= (entrySize +tagSize); -+ if (size < 0) { return CKYINVALIDDATA; } -+ if ((entry[0] == 0) && (entrySize > 1)) { -+ entry++; entrySize--; -+ } -+ setAttribute(CKA_MODULUS, entry, entrySize); -+ -+ /* exponent */ -+ if (current[0] != ASN1_INTEGER) { return CKYINVALIDDATA; } -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { return CKYINVALIDDATA; } -+ tagSize = entry - current; -+ current += entrySize + tagSize; -+ size -= (entrySize +tagSize); -+ if (size < 0) { return CKYINVALIDDATA; } -+ if ((entry[0] == 0) && (entrySize > 1)) { -+ entry++; entrySize--; -+ } -+ setAttribute(CKA_PUBLIC_EXPONENT, entry, entrySize); -+ state = PK15StateComplete; -+ return CKYSUCCESS; -+} -+ - DEREncodedSignature::DEREncodedSignature(const CKYBuffer *derSig) - { - -@@ -1483,9 +2585,9 @@ int DEREncodedSignature::getRawSignature - - 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 ; -+ CKYSize seq_length = 0; -+ CKYSize expected_sig_len = ( (keySize + 7) / 8 ) * 2 ; -+ CKYSize expected_piece_size = expected_sig_len / 2 ; - - /* unwrap the sequence */ - buf = dataStart(CKYBuffer_Data(&derEncodedSignature), CKYBuffer_Size(&derEncodedSignature),&seq_length, false); -@@ -1494,7 +2596,7 @@ int DEREncodedSignature::getRawSignature - - // unwrap first multi byte integer - -- unsigned int int_length = 0; -+ CKYSize int_length = 0; - const CKYByte *int1Buf = NULL; - const CKYByte *int2Buf = NULL; - -@@ -1525,7 +2627,7 @@ int DEREncodedSignature::getRawSignature - - // unwrap second multi byte integer - -- unsigned int second_int_length = 0; -+ CKYSize second_int_length = 0; - - int2Buf = dataStart(buf, seq_length, &second_int_length, false); - -@@ -1552,3 +2654,91 @@ int DEREncodedSignature::getRawSignature - - return CKYSUCCESS; - } -+ -+DEREncodedTokenInfo::DEREncodedTokenInfo(CKYBuffer *derTokenInfo) -+{ -+ const CKYByte *current = CKYBuffer_Data(derTokenInfo); -+ const CKYByte *entry; -+ CKYSize size = CKYBuffer_Size(derTokenInfo); -+ CKYSize entrySize; -+ CKYSize tagSize; -+ /* set token name, etc */ -+ -+ version = -1; -+ CKYBuffer_InitEmpty(&serialNumber); -+ manufacturer = NULL; -+ tokenName = NULL; -+ -+ if (current[0] != ASN1_SEQUENCE) { -+ return; /* just use the defaults */ -+ } -+ /* unwrap */ -+ current = dataStart(current, size, &size, false); -+ if (current == NULL) return; -+ -+ /* parse the version */ -+ if (current[0] != ASN1_INTEGER) { return; } -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) return; -+ tagSize = entry - current; -+ current += tagSize + entrySize; -+ size -= tagSize + entrySize; -+ if (entrySize < 1) { -+ version = *entry; -+ } -+ if (size < 0) return; -+ -+ /* get the serial number */ -+ if (current[0] != ASN1_OCTET_STRING) { return ; } -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) return; -+ tagSize = entry - current; -+ current += tagSize + entrySize; -+ size -= tagSize + entrySize; -+ CKYBuffer_Replace(&serialNumber, 0, entry, entrySize); -+ /* should we fake the cuid here? */ -+ -+ /* get the optional manufacture ID */ -+ if (current[0] == ASN1_UTF8_STRING) { -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) return; -+ tagSize = entry - current; -+ current += tagSize + entrySize; -+ size -= tagSize + entrySize; -+ manufacturer = (char *)malloc(entrySize+1); -+ if (manufacturer) { -+ memcpy(manufacturer, entry, entrySize); -+ manufacturer[entrySize] = 0; -+ } -+ } -+ -+ /* get the optional token name */ -+ /* most choices are constructed, -+ * but this one isn't explicity add the flag */ -+ if ((current[0]|ASN1_CONSTRUCTED) == ASN1_CHOICE_0) { -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) return; -+ tagSize = entry - current; -+ current += tagSize + entrySize; -+ size -= tagSize + entrySize; -+ tokenName = (char *)malloc(entrySize+1); -+ if (tokenName) { -+ memcpy(tokenName, entry, entrySize); -+ tokenName[entrySize] = 0; -+ } -+ } -+ -+ /* parsing flags */ -+ if (current[0] == ASN1_BIT_STRING) { -+ /* recordinfo parsing would go here */ -+ unsigned long bits; -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) return; -+ tagSize = entry - current; -+ current += tagSize + entrySize; -+ size -= tagSize + entrySize; -+ bits = GetBits(entry, entrySize,8,2); -+ } -+ return; -+} -+ -diff -up ./src/coolkey/object.h.p15 ./src/coolkey/object.h ---- ./src/coolkey/object.h.p15 2015-07-06 10:27:55.770827267 -0700 -+++ ./src/coolkey/object.h 2015-07-06 10:27:55.785826984 -0700 -@@ -27,6 +27,33 @@ - - using std::list; - -+/* -+ * Sigh PKCS 15 is heavily ASN.1... -+ */ -+const CKYByte ASN1_BOOLEAN = 0x01; -+const CKYByte ASN1_INTEGER = 0x02; -+const CKYByte ASN1_BIT_STRING = 0x03; -+const CKYByte ASN1_OCTET_STRING = 0x04; -+const CKYByte ASN1_ENUMERATED = 0x0a; -+const CKYByte ASN1_UTF8_STRING = 0x0c; -+const CKYByte ASN1_GENERALIZED_TIME = 0x18; -+const CKYByte ASN1_CONSTRUCTED = 0x20; -+const CKYByte ASN1_SEQUENCE = 0x30; -+const CKYByte ASN1_CHOICE_0 = 0xa0; -+const CKYByte ASN1_CHOICE_1 = 0xa1; -+const CKYByte ASN1_CHOICE_2 = 0xa2; -+const CKYByte ASN1_CHOICE_3 = 0xa3; -+ -+const CKYBitFlags BROKEN_FLAG = 0x80000000; -+const unsigned int PK11_INVALID_KEY_REF = -1; -+ -+const CKYByte PK15X509CertType = ASN1_SEQUENCE; -+const CKYByte PK15RSAKeyType = ASN1_SEQUENCE; -+const CKYByte PK15ECCKeyType = ASN1_CHOICE_0; -+const CKYByte PK15DHKeyType = ASN1_CHOICE_1; -+const CKYByte PK15DSAKeyType = ASN1_CHOICE_2; -+const CKYByte PK15KEAKeyType = ASN1_CHOICE_3; -+ - class PKCS11Attribute { - private: - CK_ATTRIBUTE_TYPE type; -@@ -52,9 +79,30 @@ class PKCS11Attribute { - PKCS11Attribute() : type(0){ CKYBuffer_InitEmpty(&value); } - PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYBuffer *value_) - : type(type_) { CKYBuffer_InitFromCopy(&value, value_); } -+ PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYByte *data_, -+ CKYSize size_) : type(type_) -+ { CKYBuffer_InitFromData(&value, data_, size_); } - ~PKCS11Attribute() { CKYBuffer_FreeData(&value); } - }; - -+class PK15ObjectPath { -+ private: -+ CKYBuffer path; -+ CKYOffset index; -+ CKYSize length; -+ public: -+ PK15ObjectPath() : index(0), length(0) { CKYBuffer_InitEmpty(&path); } -+ PK15ObjectPath(const PK15ObjectPath &cpy) : -+ index(cpy.index), length(cpy.length) -+ { CKYBuffer_InitFromCopy(&path, &cpy.path); } -+ ~PK15ObjectPath() { CKYBuffer_FreeData(&path); } -+ const CKYBuffer *getPath() const { return &path; } -+ CKYOffset getIndex() const { return index; } -+ CKYSize getLength() const { return length; } -+ CKYStatus setObjectPath(const CKYByte *entry, CKYSize size); -+}; -+ -+ - class PKCS11Object { - public: - enum KeyType { -@@ -72,6 +120,8 @@ class PKCS11Object { - unsigned long muscleObjID; - CK_OBJECT_HANDLE handle; - char *label; -+ unsigned int keySize; -+ CK_USER_TYPE user; - - void parseOldObject(const CKYBuffer *data); - void parseNewObject(const CKYBuffer *data); -@@ -82,19 +132,37 @@ class PKCS11Object { - protected : - char *name; - KeyType keyType; -+ unsigned int keyRef; - CKYBuffer pubKey; -+ CKYBuffer authId; -+ CKYBuffer pinAuthId; -+ PK15ObjectPath objectPath; - - 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); -- attributes.clear(); } -+ virtual ~PKCS11Object() { delete [] label; delete [] name; -+ CKYBuffer_FreeData(&pubKey); CKYBuffer_FreeData(&authId); -+ CKYBuffer_FreeData(&pinAuthId); attributes.clear(); } - - PKCS11Object(const PKCS11Object& cpy) : - attributes(cpy.attributes), muscleObjID(cpy.muscleObjID), -- handle(cpy.handle), label(NULL), name(NULL), keyType(cpy.keyType) { -- CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey); } -+ handle(cpy.handle), label(NULL), keySize(cpy.keySize), -+ user(cpy.user), name(NULL), keyType(cpy.keyType), keyRef(cpy.keyRef), -+ objectPath(cpy.objectPath) { -+ /* label is just a cached value, don't need -+ * to copy it. */ -+ if (cpy.name != NULL) { -+ int len = strlen(cpy.name); -+ name= new char [len+1]; -+ if (name) { -+ memcpy(name,cpy.name,len+1); -+ } -+ } -+ CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey); -+ CKYBuffer_InitFromCopy(&authId,&cpy.authId); -+ CKYBuffer_InitFromCopy(&pinAuthId,&cpy.pinAuthId); } - - - unsigned long getMuscleObjID() const { return muscleObjID; } -@@ -107,6 +175,8 @@ class PKCS11Object { - - void setAttribute(CK_ATTRIBUTE_TYPE type, const CKYBuffer *value); - void setAttribute(CK_ATTRIBUTE_TYPE type, const char *); -+ void setAttribute(CK_ATTRIBUTE_TYPE type, const CKYByte *data, -+ CKYSize size); - /* bools and ulongs are too close, don't abuse function overloading - * for these cases */ - void setAttributeBool(CK_ATTRIBUTE_TYPE type, CK_BBOOL); -@@ -124,14 +194,21 @@ class PKCS11Object { - return &pubKey; - } - -- KeyType getKeyType() const { return keyType;} -+ KeyType getKeyType(void) const { return keyType;} -+ unsigned int getKeySize(void) const { return keySize; } -+ unsigned int getKeyRef(void) const { return keyRef; } -+ CK_USER_TYPE getUser(void) const { return user; } - void setKeyType(KeyType theType) { keyType = theType; } -+ void setKeySize(unsigned int keySize_) { keySize = keySize_; } -+ const CKYBuffer *getAuthId(void) const { return &authId; } -+ const CKYBuffer *getPinAuthId(void) const { return &pinAuthId; } -+ const PK15ObjectPath &getObjectPath() const { return objectPath; } -+ void completeKey(const PKCS11Object &cert); - }; - - 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 { -@@ -155,6 +232,84 @@ class CACCert : public PKCS11Object { - CACCert(CKYByte instance, const CKYBuffer *derCert); - }; - -+typedef enum { PK15StateInit, PK15StateNeedObject, -+ PK15StateNeedRawPublicKey,PK15StateNeedRawCertificate, -+ PK15StateComplete } PK15State; -+ -+typedef enum {PK15PvKey, PK15PuKey, PK15Cert, PK15AuthObj} PK15ObjectType; -+const unsigned int PK15_INVALID_KEY_REF = -1; -+ -+class PK15Object : public PKCS11Object { -+ private: -+ CKYByte instance; -+ PK15ObjectType p15Type; -+ PK15State state; -+ P15PinInfo pinInfo; -+ -+ CKYStatus completeCertObject(const CKYByte *buf, CKYSize size); -+ CKYStatus completeAuthObject(const CKYByte *buf, CKYSize size); -+ CKYStatus completeKeyObject(const CKYByte *buf, CKYSize size); -+ CKYStatus completePrivKeyObject(const CKYByte *buf, CKYSize size); -+ CKYStatus completePubKeyObject(const CKYByte *buf, CKYSize size); -+ CKYStatus completeRawPublicKey(const CKYByte *buf, CKYSize size); -+ CKYStatus completeRawCertificate(const CKYByte *buf, CKYSize size); -+ -+ CKYBitFlags defaultCommonBits() { -+ return ((p15Type == PK15PvKey) && (CKYBuffer_Size(&authId) != 0)) ? -+ P15FlagsPrivate : 0; -+ } -+ CKYBitFlags defaultUsageBits() { -+ CKYBitFlags sign, recover, encrypt; -+ switch (p15Type) { -+ case PK15PuKey: -+ sign = P15UsageVerify; recover = P15UsageVerifyRecover; -+ encrypt = P15UsageEncrypt; -+ break; -+ case PK15PvKey: -+ sign = P15UsageSign; recover = P15UsageSignRecover; -+ encrypt = P15UsageDecrypt; -+ break; -+ default: -+ sign = 0; recover = 0; encrypt = 0; -+ break; -+ } -+ switch(keyType) { -+ case rsa: -+ return sign | recover | encrypt; -+ case ecc: -+ return sign | P15UsageDerive; -+ default: -+ break; -+ } -+ return 0; -+ } -+ CKYBitFlags defaultAccessBits() { -+ switch (p15Type) { -+ case PK15PuKey: -+ return P15AccessExtractable | P15AccessLocal; -+ case PK15PvKey: -+ return P15AccessSensitive | P15AccessLocal; -+ default: -+ break; -+ } -+ return 0; -+ } -+ CKYBitFlags defaultPinBits() { -+ return ((p15Type == PK15AuthObj) ? P15PinInitialized : 0); -+ } -+ -+ public: -+ PK15Object(CKYByte inst, PK15ObjectType type, -+ const CKYByte *derObject, CKYSize size); -+ CKYStatus completeObject(const CKYByte *data, CKYSize size); -+ PK15State getState(void) const { return state; } -+ bool isSO(void) const { return -+ (pinInfo.pinFlags & P15PinSOPin) ? true : false; } -+ bool isLocal(void) const { return -+ (pinInfo.pinFlags & P15PinLocal) ? true : false; } -+ const P15PinInfo *getPinInfo(void) const { return &pinInfo; } -+}; -+ - class Reader : public PKCS11Object { - public: - Reader(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, -@@ -180,6 +335,21 @@ class DEREncodedSignature { - - }; - -+class DEREncodedTokenInfo { -+public: -+ int version; -+ CKYBuffer serialNumber; -+ char *manufacturer; -+ char *tokenName; -+ public : -+ DEREncodedTokenInfo(CKYBuffer *derTokenInfo); -+ ~DEREncodedTokenInfo() { -+ CKYBuffer_FreeData(&serialNumber); -+ free(manufacturer); -+ free(tokenName); -+ } -+}; -+ - class AttributeMatch { - - private: -@@ -202,6 +372,9 @@ makeLEUInt(const CKYBuffer *buf, unsigne - (b[offset+0] << 0) ; - } - -+const CKYByte* dataStart(const CKYByte *buf, CKYSize length, -+ CKYSize *data_length, bool includeTag); -+ - // fixed object ID constants - #define READER_ID 0x72300000 /* 'r0\0\0' */ - #define COMBINED_ID 0x7a300000 /* 'z0\0\0' */ -diff -up ./src/coolkey/pkcs11t.h.p15 ./src/coolkey/pkcs11t.h ---- ./src/coolkey/pkcs11t.h.p15 2015-07-06 10:27:55.770827267 -0700 -+++ ./src/coolkey/pkcs11t.h 2015-07-06 10:29:32.293005407 -0700 -@@ -274,6 +274,7 @@ typedef CK_ULONG CK_USER_TYPE; - #define CKU_SO 0 - /* Normal user */ - #define CKU_USER 1 -+#define CKU_CONTEXT_SPECIFIC 2 - - - /* CK_STATE enumerates the session states */ -@@ -492,6 +493,9 @@ typedef CK_ULONG CK_ATTRIBUTE_T - #define CKA_RESET_ON_INIT 0x00000301 - #define CKA_HAS_RESET 0x00000302 - -+/* new for v2.20 */ -+#define CKA_ALWAYS_AUTHENTICATE 0x00000202 -+ - #define CKA_VENDOR_DEFINED 0x80000000 - - -diff -up ./src/coolkey/slot.cpp.p15 ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.p15 2015-07-06 10:27:55.782827040 -0700 -+++ ./src/coolkey/slot.cpp 2015-07-06 10:27:55.786826965 -0700 -@@ -54,6 +54,11 @@ const CKYByte ATR2[] = - { 0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 }; - -+/* PKCS #15 AID */ -+const CKYByte P15AID[] = -+{ 0xa0, 0, 0, 0, 0x63, 'P', 'K', 'C', 'S', '-', '1', '5'}; -+ -+ - - /* ECC curve information - * Provide information for the limited set of curves supported by our smart card(s). -@@ -405,19 +410,29 @@ SlotList::updateReaderList() - - Slot::Slot(const char *readerName_, Log *log_, CKYCardContext* context_) - : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL), -+ tokenManufacturer(NULL), - slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), - isVersion1Key(false), needLogin(false), fullTokenName(false), -- mCoolkey(false), mOldCAC(false),mCACLocalLogin(false), -- pivContainer(-1), pivKey(-1), mECC(false), -+ mCoolkey(false), mOldCAC(false), mCACLocalLogin(false), -+ pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0), -+ p15tokenInfoAddr(0), p15Instance(0), - #ifdef USE_SHMEM - shmem(readerName_), - #endif - sessionHandleCounter(1), objectHandleCounter(1) - { -+ int i; -+ -+ for (i=0; i < MAX_AUTH_USERS; i++) { -+ auth[i]=NULL; -+ } - - tokenFWVersion.major = 0; - tokenFWVersion.minor = 0; -- -+ CKYBuffer_InitFromData(&p15AID, P15AID, sizeof(P15AID)); -+ CKYBuffer_InitEmpty(&p15tokenInfo); -+ CKYBuffer_InitEmpty(&p15odf); -+ CKYBuffer_InitEmpty(&p15serialNumber); - - try { - conn = CKYCardConnection_Create(context); -@@ -433,6 +448,8 @@ Slot::Slot(const char *readerName_, Log - loggedIn = false; - pinCache.invalidate(); - pinCache.clearPin(); -+ contextPinCache.invalidate(); -+ contextPinCache.clearPin(); - //readSlotInfo(); - manufacturer = strdup("Unknown"); - if (!manufacturer) { -@@ -515,12 +532,23 @@ Slot::~Slot() - if (manufacturer) { - free(manufacturer); - } -+ if (tokenManufacturer) { -+ free(tokenManufacturer); -+ } - CKYBuffer_FreeData(&nonce); - CKYBuffer_FreeData(&cardATR); - CKYBuffer_FreeData(&mCUID); -+ CKYBuffer_FreeData(&p15AID); -+ CKYBuffer_FreeData(&p15odf); -+ CKYBuffer_FreeData(&p15tokenInfo); -+ CKYBuffer_FreeData(&p15serialNumber); - for (int i=0; i < MAX_CERT_SLOTS; i++) { - CKYBuffer_FreeData(&cardAID[i]); - } -+ for (int i=0; i < MAX_AUTH_USERS; i++) { -+ if (auth[i]) delete auth[i]; -+ auth[i]=NULL; -+ } - } - - template -@@ -637,9 +665,10 @@ Slot::getPIVLoginType(void) - } - done: - CKYBuffer_FreeData(&buffer); -- return true; -+ return local; - } - -+ - void - Slot::connectToToken() - { -@@ -745,7 +774,7 @@ Slot::connectToToken() - /* CARD is a PIV card */ - state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; - isVersion1Key = 0; -- needLogin = 1; -+ needLogin = true; - mCoolkey = 0; - mOldCAC = 0; - mCACLocalLogin = getPIVLoginType(); -@@ -757,12 +786,22 @@ Slot::connectToToken() - status = getCACAid(); - if (status != CKYSUCCESS) { - log->log("CAC Select failed 0x%x\n", status); -- if (status == CKYSCARDERR) { -+ status = getP15Params(); -+ if (status != CKYSUCCESS) { -+ if (status == CKYSCARDERR) { - log->log("Card Failure 0x%x\n", - CKYCardConnection_GetLastError(conn)); - disconnect(); -- } -- /* CARD is unknown */ -+ } -+ /* CARD is unknown */ -+ return; -+ } -+ /* enable PCKS 15 */ -+ state |= P15_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; -+ isVersion1Key = 0; -+ needLogin = false; /* get it from token info */ -+ mCoolkey = 0; -+ mCACLocalLogin = false; - return; - } - state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; -@@ -771,7 +810,7 @@ Slot::connectToToken() - * other apps may be running now, so resetting the cac is a bit - * unfriendly */ - isVersion1Key = 0; -- needLogin = 1; -+ needLogin = true; - mCoolkey = 0; - mCACLocalLogin = false; - return; -@@ -841,6 +880,8 @@ Slot::invalidateLogin(bool hard) - } else { - loggedIn = false; - pinCache.invalidate(); -+ contextPinCache.invalidate(); -+ contextPinCache.clearPin(); - if (hard) { - pinCache.clearPin(); - } -@@ -951,6 +992,414 @@ done: - return status; - } - -+CKYStatus Slot::getP15Params() -+{ -+ CKYStatus status = CKYSCARDERR; -+ int i; -+ CKYISOStatus apduRC; -+ -+ /* read the EF(DIR) */ -+ status = CACApplet_SelectFile(conn, 0x2f00, &apduRC); -+ if (status == CKYSUCCESS) { -+ CKYBuffer record; -+ -+ CKYBuffer_InitEmpty(&record); -+ /* dump it out */ -+ for (i=1; i < 255; i++) { -+ status = P15Applet_ReadRecord(conn, i, 0, P15_READ_P1, 255, -+ &record, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("EF(DIR) Read Record %d failed 0x%x apduRC=0x%x\n", -+ i, status, apduRC); -+ break; -+ } -+ } -+ CKYBuffer_FreeData(&record); -+ return CKYSCARDERR; /* don't yet support EF(DIR)*/ -+ -+ } else { -+ log->log("EF(DIR) Select failed 0x%x apduRC=0x%0x\n", status, apduRC); -+ p15aid = 0; /* use the default */ -+ p15odfAddr=0x5031; -+ p15tokenInfoAddr=0x5032; -+ } -+ -+ status = CKYApplet_SelectFile(conn, &p15AID, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("DF(PKCS-15) select failed 0x%x apduRC=0x%0x\n", status, -+ apduRC); -+ return status; -+ } -+ status = P15Applet_SelectFile(conn, p15tokenInfoAddr, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("EF(TokenInfo) select failed 0x%x apduRC=0x%0x\n", status, -+ apduRC); -+ return status; -+ } -+ /* dump it out */ -+ CKYBuffer_Resize(&p15tokenInfo, 0); -+ status = P15Applet_ReadBinary(conn, 0, 0, 0, 0, &p15tokenInfo, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("EF(TokenInfo) Read binary failed 0x%x apduRC=0x%x\n", status, -+ apduRC); -+ return status; -+ } -+ status = P15Applet_SelectFile(conn, p15odfAddr, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("EF(ODF) select failed 0x%x apduRC=0x%0x\n", status, -+ apduRC); -+ return status; -+ } -+ -+ CKYBuffer_Resize(&p15odf, 0); -+ status = P15Applet_ReadBinary(conn, 0, 0, 0, 0, &p15odf, &apduRC); -+ if (status != CKYSUCCESS) { -+ log->log("EF(ODF) Read binary failed 0x%x apduRC=0x%x\n", status, -+ apduRC); -+ return status; -+ } -+ -+ return CKYSUCCESS; -+} -+ -+CKYStatus -+Slot::readFromPath(const PK15ObjectPath &obj, CKYBuffer *file) -+{ -+ CKYStatus status; -+ CKYISOStatus apduRC; -+ CKYSize bufSize; -+ CKYOffset index = obj.getIndex(); -+ CKYSize length = obj.getLength(); -+ -+ CKYBuffer_Resize(file, 0); -+ status = selectPath(obj.getPath(), &apduRC); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ status = P15Applet_ReadBinary(conn, index, 0, 0, -+ (length >= 256)?0:length, file, &apduRC); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ -+ /* if we asked for a specific length and got it, or we asked for -+ * an indeterminate length and got less than 256 bytes, then we -+ * got everything. */ -+ bufSize = CKYBuffer_Size(file); -+ if ((length && (bufSize >= length)) || ((length == 0) && (bufSize < 256))) { -+ /* we've already got it all */ -+ return status; -+ } -+ if (bufSize < 0x82) { -+ /* make sure we have enough bytes to handle the worst case ANS.1 -+ * mistake */ -+ return CKYINVALIDDATA; -+ } -+ -+ if (length == 0) { -+ /* we don't yet know how long the length is, use the ASN.1 parser to -+ * find out. We lie to dataStart about actual size so that it won't -+ * fail since we know we don't have the whole buffer yet.*/ -+ (void) dataStart(CKYBuffer_Data(file), 65535, &length, true); -+ } -+ if (length > 65535) { -+ return CKYINVALIDDATA; -+ } -+ while ((bufSize =CKYBuffer_Size(file)) < length) { -+ CKYSize tmpLength = length - bufSize; -+ -+ if (tmpLength >= 256) tmpLength = 0; -+ -+ status = P15Applet_ReadBinary(conn, (unsigned short)(index+bufSize), -+ 0, 0, tmpLength, file, &apduRC); -+ if (status != CKYSUCCESS) { -+ return status; -+ } -+ } -+ -+ return CKYSUCCESS; -+} -+ -+void -+Slot::parseEF_TokenInfo(void) -+{ -+ DEREncodedTokenInfo derTokenInfo(&p15tokenInfo); -+ const CKYBuffer *serial=&derTokenInfo.serialNumber; -+ -+ if (derTokenInfo.version >= 0) { -+ tokenFWVersion.major = derTokenInfo.version; -+ tokenFWVersion.minor = 0; -+ } -+ -+ if (CKYSize(serial) != 0) { -+ CKYBuffer_Replace(&p15serialNumber, 0, CKYBuffer_Data(serial), -+ CKYBuffer_Size(serial)); -+ } -+ -+ if (derTokenInfo.manufacturer) { -+ if (tokenManufacturer) { -+ free(tokenManufacturer); -+ tokenManufacturer = NULL; -+ } -+ tokenManufacturer = derTokenInfo.manufacturer; -+ derTokenInfo.manufacturer = NULL; /* adopted */ -+ } -+ -+ if (derTokenInfo.tokenName) { -+ if (personName) { -+ free(personName); -+ personName = NULL; -+ } -+ personName = derTokenInfo.tokenName; -+ derTokenInfo.tokenName = NULL; /* adopted */ -+ fullTokenName = true; -+ } -+ return; -+} -+ -+void -+Slot::parseEF_ODF(void) -+{ -+ const CKYByte *current = CKYBuffer_Data(&p15odf); -+ CKYSize size = CKYBuffer_Size(&p15odf); -+ CKYBuffer files; -+ -+ CKYBuffer_InitEmpty(&files); -+ -+ while (size > 0) { -+ const CKYByte *entry; -+ CKYSize entrySize; -+ CKYSize tagSize; -+ CKYByte type, type1; -+ PK15ObjectPath objPath; -+ bool skip; -+ -+ type = current[0]; -+ entry = dataStart(current, size, &entrySize, false); -+ if (entry == NULL) { break; } -+ tagSize = entry-current; -+ current += entrySize + tagSize; -+ size -= (entrySize + tagSize); -+ -+ /* skip those entries we aren't going to parse */ -+ skip = false; -+ switch (type) { -+ case 0xa2: skip=true; break; /* skip EF(PuKDF-trusted) */ -+ case 0xa3: skip=true; break; /* skip EF(SKDF) */ -+ case 0xa7: skip=true; break; /* skip EF(DODF) */ -+ default: skip=true; break; -+ case 0xa0: /* EF(PvKDF) */ -+ case 0xa1: /* EF(PuKDF) */ -+ case 0xa4: /* EF(CDF) */ -+ case 0xa5: /* EF(CDF-trusted) */ -+ case 0xa6: /* EF(CDF-useful) */ -+ case 0xa8: break; /* EF(AODF) */ -+ } -+ if (skip) continue; -+ -+ type1 = entry[0]; -+ /* unwrap */ -+ entry = dataStart(entry, entrySize, &entrySize, false); -+ if (entry == NULL) continue; -+ if (type1 == ASN1_SEQUENCE) { -+ objPath.setObjectPath(entry, entrySize); -+ CKYBuffer_Resize(&files, 0); -+ readFromPath(objPath, &files); -+ entry = CKYBuffer_Data(&files); -+ entrySize = CKYBuffer_Size(&files); -+ } else if (type1 != ASN1_CHOICE_0) { -+ continue; -+ } -+ -+ switch (type) { -+ case 0xa0: parseEF_Directory(entry, entrySize, PK15PvKey); break; -+ case 0xa1: parseEF_Directory(entry, entrySize, PK15PuKey); break; -+ case 0xa4: parseEF_Directory(entry, entrySize, PK15Cert); break; -+ case 0xa5: parseEF_Directory(entry, entrySize, PK15Cert); break; -+ case 0xa6: parseEF_Directory(entry, entrySize, PK15Cert); break; -+ case 0xa8: parseEF_Directory(entry, entrySize, PK15AuthObj); break; -+ default: break; -+ } -+ } -+ CKYBuffer_FreeData(&files); -+ return; -+} -+ -+ -+class ObjectCertCKAIDMatch { -+ private: -+ const CKYBuffer *cka_id; -+ public: -+ ObjectCertCKAIDMatch(const CKYBuffer *cka_id_) : cka_id(cka_id_) {} -+ bool operator()(const PKCS11Object& obj) { -+ const CKYBuffer *id; -+ const CKYBuffer *objClass; -+ CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; -+ objClass = obj.getAttribute(CKA_CLASS); -+ if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, -+ (CKYByte *)&certClass, sizeof(certClass))) { -+ return false; -+ } -+ id = obj.getAttribute(CKA_ID); -+ return (id != NULL && CKYBuffer_IsEqual(id,cka_id)) ? true : false; -+ } -+}; -+ -+class ObjectKeyCKAIDMatch { -+ private: -+ const CKYBuffer *cka_id; -+ public: -+ ObjectKeyCKAIDMatch(const CKYBuffer *cka_id_) : cka_id(cka_id_) {} -+ bool operator()(const PKCS11Object& obj) { -+ const CKYBuffer *id; -+ const CKYBuffer *objClass; -+ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; -+ objClass = obj.getAttribute(CKA_CLASS); -+ if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, -+ (CKYByte *)&keyClass, sizeof(keyClass))) { -+ return false; -+ } -+ id = obj.getAttribute(CKA_ID); -+ return (id != NULL && CKYBuffer_IsEqual(id,cka_id)) ? true : false; -+ } -+}; -+ -+CKYStatus -+Slot::parseEF_Directory(const CKYByte *current, -+ CKYSize size, PK15ObjectType type) -+{ -+ CKYBuffer file; -+ CKYBuffer_InitEmpty(&file); -+ CKYStatus status; -+ -+ -+ while (size > 0) { -+ const CKYByte *entry; -+ CKYSize entrySize; -+ -+ if (current[0] != ASN1_SEQUENCE) { -+ /* no more */ -+ break; -+ } -+ -+ entry = dataStart(current, size, &entrySize, true); -+ if (entry == NULL) { break; } -+ current += entrySize; -+ size -= entrySize; -+ -+ do { -+ PK15Object obj(PK15Instance(), type, entry, entrySize); -+ -+ /* if state failed, then there is something wrong with this -+ * der, skip this object */ -+ if (obj.getState() == PK15StateInit) { -+ break; -+ } -+ status = CKYSUCCESS; -+ while (obj.getState() != PK15StateComplete) { -+ CKYBuffer_Resize(&file, 0); -+ readFromPath(obj.getObjectPath(), &file); -+ status = obj.completeObject(CKYBuffer_Data(&file), -+ CKYBuffer_Size(&file)); -+ if (status != CKYSUCCESS) { -+ break; -+ } -+ } -+ if (status != CKYSUCCESS) { -+ break; -+ } -+ assert(obj.getState() == PK15StateComplete); -+ /* handle type specific per object fixups */ -+ switch (type) { -+ case PK15AuthObj: -+ /* if we're an auth object, squirrel us away for future use */ -+ if (obj.isSO()) { -+ if (auth[CKU_SO] != 0) { -+ auth[CKU_SO] = new PK15Object(obj); -+ } -+ } else if (auth[CKU_USER] == NULL) { -+ auth[CKU_USER] = new PK15Object(obj); -+ } else if (auth[CKU_CONTEXT_SPECIFIC] == NULL) { -+ ObjectIter iter; -+ const CKYBuffer *authid = obj.getPinAuthId(); -+ -+ /* these should put on the individual keys */ -+ auth[CKU_CONTEXT_SPECIFIC] = new PK15Object(obj); -+ -+ for( iter = tokenObjects.begin(); -+ iter != tokenObjects.end(); ++iter) { -+ if( CKYBuffer_IsEqual(iter->getAuthId(),authid)) { -+ iter->setAttributeBool(CKA_ALWAYS_AUTHENTICATE, -+ TRUE); -+ } -+ } -+ } -+ /* drop unkown */ -+ break; -+ case PK15PvKey: -+ /* does the cert already exist? */ -+ { -+ ObjectConstIter iter; -+ const CKYBuffer *id; -+ -+ id = obj.getAttribute(CKA_ID); -+ if ((!id) || (CKYBuffer_Size(id) != 1)) { -+ break; -+ } -+ iter = find_if(tokenObjects.begin(), tokenObjects.end(), -+ ObjectCertCKAIDMatch(id)); -+ -+ if ( iter != tokenObjects.end() ) { -+ obj.completeKey(*iter); -+ } -+ } -+ break; -+ case PK15Cert: -+ /* does a corresponding key already exist? */ -+ { -+ ObjectIter iter; -+ const CKYBuffer *id; -+ -+ id = obj.getAttribute(CKA_ID); -+ if ((!id) || (CKYBuffer_Size(id) != 1)) { -+ break; -+ } -+ iter = find_if(tokenObjects.begin(), tokenObjects.end(), -+ ObjectKeyCKAIDMatch(id)); -+ -+ if ( iter != tokenObjects.end() ) { -+ iter->completeKey(obj); -+ } -+ } -+ break; -+ case PK15PuKey: -+ break; -+ } -+ tokenObjects.push_back(obj); -+ } while ( false ); -+ } -+ CKYBuffer_FreeData(&file); -+ return CKYSUCCESS; -+} -+ -+ -+CKYStatus -+Slot::selectPath(const CKYBuffer *path, CKYISOStatus *apduRC) -+{ -+ CKYSize size = CKYBuffer_Size(path); -+ CKYStatus status = CKYINVALIDARGS; -+ CKYOffset pos; -+ -+ for (pos=0; pos < size; pos +=2) { -+ unsigned short ef = CKYBuffer_GetShort(path, pos); -+ status = P15Applet_SelectFile(conn, ef, apduRC); -+ if (status != CKYSUCCESS) { -+ break; -+ } -+ } -+ return status; -+} -+ - void - Slot::refreshTokenState() - { -@@ -1132,8 +1581,20 @@ void - Slot::makeSerialString(char *serialNumber, int maxSize, - const unsigned char *cuid) - { -+ CKYSize ssize = CKYBuffer_Size(&p15serialNumber); - memset(serialNumber, ' ', maxSize); - -+ if (ssize != 0) { -+ CKYSize i; -+ ssize = MIN((CKYSize)maxSize/2, ssize); -+ for (i=0; i < ssize; i++) { -+ CKYByte c = CKYBuffer_GetChar(&p15serialNumber, i); -+ serialNumber[2*i] = hex((c >> 4) & 0xf); -+ serialNumber[2*i+1] = hex(c & 0xf); -+ } -+ } -+ -+ - // otherwise we use the eepromSerialNumber as a hex value - if (cuid) { - makeCUIDString(serialNumber, maxSize, cuid); -@@ -1204,7 +1665,8 @@ struct _manList { - static const struct _manList manList[] = { - { 0x4090, "Axalto" }, - { 0x2050, "Oberthur" }, -- { 0x4780, "RSA" } -+ { 0x4780, "RSA" }, -+ { 0x534e, "SafeNet" } - }; - - static int manListSize = sizeof(manList)/sizeof(manList[0]); -@@ -1213,8 +1675,15 @@ void - Slot::makeManufacturerString(char *man, int maxSize, const unsigned char *cuid) - { - char *cp = man; -+ int manLen; - memset(man, ' ', maxSize); - -+ if (tokenManufacturer) { -+ manLen = strlen(tokenManufacturer); -+ memcpy(man, tokenManufacturer, MIN(manLen, maxSize)); -+ // UTF8 Truncate fixup! don't drop halfway through a UTF8 character -+ return; -+ } - if (!cuid) { - return; - } -@@ -1633,26 +2102,6 @@ class KeyNumMatch { - } - }; - --class ObjectCertCKAIDMatch { -- private: -- CKYByte cka_id; -- public: -- ObjectCertCKAIDMatch(CKYByte cka_id_) : cka_id(cka_id_) {} -- bool operator()(const PKCS11Object& obj) { -- const CKYBuffer *id; -- const CKYBuffer *objClass; -- CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; -- objClass = obj.getAttribute(CKA_CLASS); -- if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, -- (CKYByte *)&certClass, sizeof(certClass))) { -- return false; -- } -- id = obj.getAttribute(CKA_ID); -- return (id != NULL && CKYBuffer_DataIsEqual(id,&cka_id, 1)) -- ? true : false; -- } --}; -- - CK_OBJECT_HANDLE - Slot::generateUnusedObjectHandle() - { -@@ -1706,7 +2155,7 @@ Slot::addKeyObject(list& o - "Missing or invalid CKA_ID value"); - } - iter = find_if(objectList.begin(), objectList.end(), -- ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0))); -+ ObjectCertCKAIDMatch(id)); - 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 -@@ -1758,6 +2207,11 @@ Slot::unloadObjects() - free(personName); - personName = NULL; - fullTokenName = false; -+ if (tokenManufacturer) { -+ free(tokenManufacturer); -+ tokenManufacturer = NULL; -+ } -+ CKYBuffer_Resize(&p15serialNumber,0); - } - - #ifdef USE_SHMEM -@@ -2956,6 +3410,17 @@ Slot::loadObjects() - loadReaderObject(); - return; - } -+ if (state & P15_CARD) { -+ parseEF_TokenInfo(); -+ parseEF_ODF(); -+ if (auth[CKU_USER] != NULL) { -+ /* set need login */ -+ needLogin = true; -+ } -+ status = trans.end(); -+ loadReaderObject(); -+ return; -+ } - - selectApplet(); - log->log("time load object: Select Applet (again) %d ms\n", -@@ -3123,15 +3588,15 @@ Slot::getSessionInfo(SessionHandleSuffix - } - - void --SlotList::login(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, -- CK_ULONG ulPinLen) -+SlotList::login(CK_SESSION_HANDLE hSession, CK_USER_TYPE user, -+ CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) - { - CK_SLOT_ID slotID; - SessionHandleSuffix suffix; - - decomposeSessionHandle(hSession, slotID, suffix); - -- slots[slotIDToIndex(slotID)]->login(suffix, pPin, ulPinLen); -+ slots[slotIDToIndex(slotID)]->login(suffix, user, pPin, ulPinLen); - } - - void -@@ -3181,8 +3646,8 @@ Slot::isLoggedIn() - } - - void --Slot::login(SessionHandleSuffix handleSuffix, CK_UTF8CHAR_PTR pPin, -- CK_ULONG ulPinLen) -+Slot::login(SessionHandleSuffix handleSuffix, CK_USER_TYPE user, -+ CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) - { - refreshTokenState(); - -@@ -3191,10 +3656,23 @@ Slot::login(SessionHandleSuffix handleSu - "Slot::login\n", (unsigned long) handleSuffix); - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } -+ /* only support CKU_USER for CAC, PIV, and coolkey... CKU_USER and -+ * CKU_CONTEX_SPECIFIC for P15Card */ -+ if (user != CKU_USER) { -+ if ((user != CKU_CONTEXT_SPECIFIC) || ((state & P15_CARD) == 0)) { -+ throw PKCS11Exception(CKR_USER_TYPE_INVALID); -+ } -+ } -+ - - if (!isVersion1Key) { -- pinCache.invalidate(); -- pinCache.set((const char *)pPin, ulPinLen); -+ if (user == CKU_USER) { -+ pinCache.invalidate(); -+ pinCache.set((const char *)pPin, ulPinLen); -+ } else { -+ contextPinCache.invalidate(); -+ contextPinCache.set((const char *)pPin, ulPinLen); -+ } - } else if (nonceValid) { - throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN); - } -@@ -3205,17 +3683,85 @@ Slot::login(SessionHandleSuffix handleSu - - if (state & GOV_CARD) { - selectCACApplet(0, true); -- } else { -+ } else if ((state & P15_CARD)== 0) { -+ /* p15 does the select in attemptLogin */ - selectApplet(); - } - - if (isVersion1Key) { -- attemptLogin((const char *)pPin); -- } else if (state & GOV_CARD) { -+ attemptCoolKeyLogin((const char *)pPin); -+ } else { -+ attemptLogin(user, false); -+ } -+} -+ -+void -+Slot::attemptLogin(CK_USER_TYPE user, bool flushPin) { -+ if (state & GOV_CARD) { - attemptCACLogin(); -+ } else if (state & P15_CARD) { -+ attemptP15Login(user); - } else { - oldAttemptLogin(); - } -+ if (flushPin && (user == CKU_CONTEXT_SPECIFIC)) { -+ contextPinCache.clearPin(); -+ } -+} -+void dump(const char *label, const CKYBuffer *buf); -+ -+void -+Slot::attemptP15Login(CK_USER_TYPE user) -+{ -+ PinCache *pinCachePtr = userPinCache(user); -+ const CKYBuffer *path; -+ -+ if (user == CKU_USER) { -+ loggedIn = false; -+ } -+ pinCachePtr->invalidate(); -+ -+ CKYStatus status; -+ CKYISOStatus result; -+ -+ if ((user >= MAX_AUTH_USERS) || (auth[user] == NULL)) { -+ throw PKCS11Exception(CKR_USER_TYPE_INVALID, -+ "No PKCS #15 auth object for user %d\n", user); -+ } -+ -+ path = auth[user]->getObjectPath().getPath(); -+ status = selectPath(auth[user]->getObjectPath().getPath(), &result); -+ if( status == CKYSCARDERR ) { -+ handleConnectionError(); -+ } -+ if (status != CKYSUCCESS) { -+ throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet select return 0x%04x", -+ result); -+ } -+ -+ status = P15Applet_VerifyPIN(conn, -+ (const char *)CKYBuffer_Data(pinCachePtr->get()), -+ auth[user]->getPinInfo(), &result); -+ if( status == CKYSCARDERR ) { -+ handleConnectionError(); -+ } -+ switch( result ) { -+ case CKYISO_SUCCESS: -+ break; -+ case 0x6983: -+ pinCachePtr->clearPin(); -+ throw PKCS11Exception(CKR_PIN_LOCKED); -+ default: -+ pinCachePtr->clearPin(); -+ if ((result & 0xff00) == 0x6300) { -+ throw PKCS11Exception(CKR_PIN_INCORRECT); -+ } -+ throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x", -+ result); -+ } -+ pinCachePtr->validate(); -+ if (user == CKU_USER) -+ loggedIn = true; - } - - void -@@ -3252,6 +3798,7 @@ Slot::attemptCACLogin() - loggedIn = true; - } - -+ - void - Slot::oldAttemptLogin() - { -@@ -3286,7 +3833,7 @@ Slot::oldAttemptLogin() - - // should already be in a transaction, and applet selected - void --Slot::attemptLogin(const char *pin) -+Slot::attemptCoolKeyLogin(const char *pin) - { - CKYStatus status; - CKYISOStatus result; -@@ -3362,7 +3909,7 @@ Slot::logout(SessionHandleSuffix suffix) - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } - -- if (state & GOV_CARD) { -+ if (state & (GOV_CARD|P15_CARD)) { - CACLogout(); - return; - } -@@ -3601,31 +4148,26 @@ Slot::ensureValidSession(SessionHandleSu - // from 0-9. - // - CKYByte --Slot::objectHandleToKeyNum(CK_OBJECT_HANDLE hKey) -+Slot::objectToKeyNum(const PKCS11Object *key) - { -- ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(), -- ObjectHandleMatch(hKey)); -- -- if( iter == tokenObjects.end() ) { -- // no such object -- throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); -- } -+ unsigned long id = key->getMuscleObjID(); - -- if( getObjectClass(iter->getMuscleObjID()) != 'k' ) { -+ if( getObjectClass(id) != 'k' ) { - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); - } -- unsigned short keyNum = getObjectIndex(iter->getMuscleObjID()); -+ unsigned short keyNum = getObjectIndex(id); - if( keyNum > 9 ) { - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); - } - return keyNum & 0xFF; - } - --PKCS11Object::KeyType --Slot::getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey) -+PKCS11Object * -+Slot::getKeyFromHandle(CK_OBJECT_HANDLE hKey) - { - ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(), - ObjectHandleMatch(hKey)); -+ PKCS11Object &obj = (PKCS11Object &)*iter; - - if( iter == tokenObjects.end() ) { - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); -@@ -3635,7 +4177,7 @@ Slot::getKeyTypeFromHandle(CK_OBJECT_HAN - throw PKCS11Exception(CKR_KEY_HANDLE_INVALID); - } - -- return iter->getKeyType(); -+ return &obj; - } - - void -@@ -3648,9 +4190,7 @@ Slot::signInit(SessionHandleSuffix suffi - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } - -- PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey); -- -- session->signatureState.initialize(objectHandleToKeyNum(hKey), keyType); -+ session->signatureState.initialize(getKeyFromHandle(hKey)); - } - - void -@@ -3663,9 +4203,7 @@ Slot::decryptInit(SessionHandleSuffix su - throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID); - } - -- PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey); -- -- session->decryptionState.initialize(objectHandleToKeyNum(hKey), keyType); -+ session->decryptionState.initialize(getKeyFromHandle(hKey)); - } - - /** -@@ -3935,7 +4473,7 @@ Slot::sign(SessionHandleSuffix suffix, C - - CryptOpState sigState = dummyParams.getOpState(*session); - -- PKCS11Object::KeyType keyType = sigState.keyType; -+ PKCS11Object::KeyType keyType = sigState.key->getKeyType(); - - if ( keyType == PKCS11Object::unknown) { - throw PKCS11Exception(CKR_DATA_INVALID); -@@ -3982,9 +4520,9 @@ Slot::cryptRSA(SessionHandleSuffix suffi - } - CryptOpState& opState = params.getOpState(*session); - CKYBuffer *result = &opState.result; -- CKYByte keyNum = opState.keyNum; -+ PKCS11Object *key = opState.key; - -- unsigned int keySize = getRSAKeySize(keyNum); -+ unsigned int keySize = getRSAKeySize(key); - - if (keySize != CryptParams::DEFAULT_KEY_SIZE) - params.setKeySize(keySize); -@@ -4008,8 +4546,8 @@ Slot::cryptRSA(SessionHandleSuffix suffi - } - try { - params.padInput(&inputPad, &input); -- performRSAOp(&output, &inputPad, params.getKeySize(), -- keyNum, params.getDirection()); -+ performRSAOp(&output, &inputPad, params.getKeySize(), key, -+ params.getDirection()); - params.unpadOutput(result, &output); - CKYBuffer_FreeData(&input); - CKYBuffer_FreeData(&inputPad); -@@ -4072,9 +4610,9 @@ void Slot::signECC(SessionHandleSuffix s - } - CryptOpState& opState = params.getOpState(*session); - CKYBuffer *result = &opState.result; -- CKYByte keyNum = opState.keyNum; -+ PKCS11Object *key = opState.key; - -- unsigned int keySize = getECCKeySize(keyNum); -+ unsigned int keySize = getECCKeySize(key); - - if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE) - params.setKeySize(keySize); -@@ -4100,7 +4638,7 @@ void Slot::signECC(SessionHandleSuffix s - throw PKCS11Exception(CKR_HOST_MEMORY); - } - try { -- performECCSignature(&output, &input, params.getKeySize(), keyNum); -+ performECCSignature(&output, &input, params.getKeySize(), key); - params.unpadOutput(result, &output); - CKYBuffer_FreeData(&input); - CKYBuffer_FreeData(&output); -@@ -4122,8 +4660,26 @@ void Slot::signECC(SessionHandleSuffix s - } - - void -+Slot::selectKey(const PKCS11Object *key, bool retry) -+{ -+ /* P15 cards need to be reselected on retry because P15 must select -+ * on authentication. PIV, CAC and Coolkeys do not */ -+ if (retry && ((state & GOV_CARD) || ((state & P15_CARD) == 0))) { -+ return; -+ } -+ if (state & GOV_CARD) { -+ selectCACApplet(objectToKeyNum(key), true); -+ } else if (state & P15_CARD) { -+ selectPath(key->getObjectPath().getPath(), NULL); -+ } else { -+ selectApplet(); -+ } -+ return; -+} -+ -+void - Slot::performECCSignature(CKYBuffer *output, const CKYBuffer *input, -- unsigned int keySize, CKYByte keyNum) -+ unsigned int keySize, const PKCS11Object *key) - { - - /* establish a transaction */ -@@ -4135,22 +4691,23 @@ Slot::performECCSignature(CKYBuffer *out - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); - } - -- if (state & GOV_CARD) { -- selectCACApplet(keyNum, true); -- } else { -- selectApplet(); -- } -- - CKYISOStatus result; -- int loginAttempted = 0; -+ bool loginAttempted = false; - - retry: -+ selectKey(key, loginAttempted); -+ - if (state & PIV_CARD) { -- status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result); -+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, -+ input, output, &result); - } else if (state & CAC_CARD) { - status = CACApplet_SignDecrypt(conn, input, output, &result); -+ } else if (state & P15_CARD) { -+ status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8, -+ CKY_DIR_ENCRYPT, input, output, &result); -+ - } else { -- status = CKYApplet_ComputeECCSignature(conn, keyNum, input, NULL, output, getNonce(), &result); -+ status = CKYApplet_ComputeECCSignature(conn, objectToKeyNum(key), input, NULL, output, getNonce(), &result); - } - /* map the ISO not logged in code to the coolkey one */ - if ((result == CKYISO_CONDITION_NOT_SATISFIED) || -@@ -4166,19 +4723,16 @@ retry: - 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. -- */ -+ /* keys could be logged out in the middle by someone else, -+ * reauthenticate... coolkey version 1 bypasses this issue by -+ * allowing multiple applications separate login states at once. -+ */ - if (!isVersion1Key && !loginAttempted && -+ userPinCache(key->getUser())->isValid() && - (result == CKYISO_UNAUTHORIZED)) { - /* try to reauthenticate */ - try { -- if (state & GOV_CARD) { -- attemptCACLogin(); -- } else { -- oldAttemptLogin(); -- } -+ attemptLogin(key->getUser(),true); - } catch(PKCS11Exception& ) { - /* attemptLogin can throw things like CKR_PIN_INCORRECT - that don't make sense from a crypto operation. This is -@@ -4199,8 +4753,9 @@ retry: - - - void --Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, unsigned int keySize, -- CKYByte keyNum, CKYByte direction) -+Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, -+ unsigned int keySize, const PKCS11Object *key, -+ CKYByte direction) - { - if ( mECC ) { - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); -@@ -4212,26 +4767,25 @@ Slot::performRSAOp(CKYBuffer *output, co - Transaction trans; - CKYStatus status = trans.begin(conn); - if( status != CKYSUCCESS ) handleConnectionError(); -- -- // -- // select the applet -- // -- if (state & GOV_CARD) { -- selectCACApplet(keyNum, true); -- } else { -- selectApplet(); -- } -- - CKYISOStatus result; -- int loginAttempted = 0; -+ bool loginAttempted = false; -+ - retry: -+ selectKey(key, loginAttempted); -+ -+ - if (state & PIV_CARD) { -- status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result); -+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, -+ input, output, &result); - } else if (state & CAC_CARD) { - status = CACApplet_SignDecrypt(conn, input, output, &result); -+ } else if (state & P15_CARD) { -+ status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8, -+ direction, input, output, &result); - } else { -- status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction, -- input, NULL, output, getNonce(), &result); -+ status = CKYApplet_ComputeCrypt(conn, objectToKeyNum(key), -+ CKY_RSA_NO_PAD, direction, input, NULL, output, -+ getNonce(), &result); - } - - /* map the ISO not logged in code to the coolkey one */ -@@ -4250,15 +4804,12 @@ 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 && pinCache.isValid() && -+ if (!isVersion1Key && !loginAttempted && -+ userPinCache(key->getUser())->isValid() && - (result == CKYISO_UNAUTHORIZED)) { - // try to reauthenticate - try { -- if (state & GOV_CARD) { -- attemptCACLogin(); -- } else { -- oldAttemptLogin(); -- } -+ attemptLogin(key->getUser(), true); - } catch(PKCS11Exception& ) { - // attemptLogin can throw things like CKR_PIN_INCORRECT - // that don't make sense from a crypto operation. This is -@@ -4278,7 +4829,7 @@ void - Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData, - CK_ULONG ulDataLen) - { -- if (state & GOV_CARD) { -+ if (state & (GOV_CARD|P15_CARD)) { - /* should throw unsupported */ - throw PKCS11Exception(CKR_DEVICE_ERROR); - } -@@ -4330,7 +4881,7 @@ void - Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData, - CK_ULONG ulDataLen) - { -- if (state & GOV_CARD) { -+ if (state & (GOV_CARD|P15_CARD)) { - /* should throw unsupported */ - throw PKCS11Exception(CKR_DEVICE_ERROR); - } -@@ -4364,61 +4915,44 @@ Slot::generateRandom(SessionHandleSuffix - - #define MAX_NUM_KEYS 8 - unsigned int --Slot::getRSAKeySize(CKYByte keyNum) -+Slot::getRSAKeySize(PKCS11Object *key) - { - unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE; - int modSize = 0; - -- 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; -+ modSize = key->getKeySize(); -+ if (modSize != 0) { -+ return modSize; - } - -- CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS); -+ CKYBuffer const *modulus = key->getAttribute(CKA_MODULUS); - - if(modulus) { - modSize = CKYBuffer_Size(modulus); - if(CKYBuffer_GetChar(modulus,0) == 0x0) { - modSize--; - } -- if(modSize > 0) -+ if(modSize > 0) { - keySize = modSize * 8; -+ key->setKeySize(keySize); -+ } - } - - return keySize; - } - - unsigned int --Slot::getECCKeySize(CKYByte keyNum) --{ -- return calcECCKeySize(keyNum); --} -- --unsigned int --Slot::calcECCKeySize(CKYByte keyNum) -+Slot::getECCKeySize(PKCS11Object *key) - { - unsigned int keySize = CryptParams::ECC_DEFAULT_KEY_SIZE; -+ unsigned int objKeySize = 0; - -- 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; -+ objKeySize = key->getKeySize(); -+ if (objKeySize != 0) { -+ return objKeySize; - } - -- CKYBuffer const *eccParams = iter->getAttribute(CKA_EC_PARAMS); -+ CKYBuffer const *eccParams = key->getAttribute(CKA_EC_PARAMS); - - if (eccParams == NULL) { - return keySize; -@@ -4457,6 +4991,7 @@ Slot::calcECCKeySize(CKYByte keyNum) - - if ( match == 1 ) { - keySize = curveBytesNamePair[i].length; -+ key->setKeySize(keySize); - return keySize; - } - -@@ -4476,10 +5011,9 @@ Slot::derive(SessionHandleSuffix suffix, - 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); -+ session->keyAgreementState.initialize(getKeyFromHandle(hBaseKey)); -+ deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, -+ phKey, params); - - } - -@@ -4515,9 +5049,8 @@ void Slot::deriveECC(SessionHandleSuffix - - CryptOpState& opState = params.getOpState(*session); - CKYBuffer *result = &opState.result; -- CKYByte keyNum = opState.keyNum; - -- unsigned int keySize = getECCKeySize(keyNum); -+ unsigned int keySize = getECCKeySize(opState.key); - - if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE) - params.setKeySize(keySize); -@@ -4542,10 +5075,11 @@ void Slot::deriveECC(SessionHandleSuffix - - if( CKYBuffer_Size(result) == 0 ) { - try { -- performECCKeyAgreement(deriveMech, &publicDataBuffer, &secretKeyBuffer, -- keyNum, params.getKeySize()); -+ performECCKeyAgreement(deriveMech, &publicDataBuffer, -+ &secretKeyBuffer, opState.key, params.getKeySize()); - CK_OBJECT_HANDLE keyObjectHandle = generateUnusedObjectHandle(); -- secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, pTemplate, ulAttributeCount); -+ secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, -+ pTemplate, ulAttributeCount); - } catch(PKCS11Exception& e) { - CKYBuffer_FreeData(&secretKeyBuffer); - CKYBuffer_FreeData(&publicDataBuffer); -@@ -4557,15 +5091,15 @@ void Slot::deriveECC(SessionHandleSuffix - 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) -+Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, -+ CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, -+ const PKCS11Object *key, unsigned int keySize) - { - if (!mECC) { - throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); -@@ -4575,25 +5109,26 @@ Slot::performECCKeyAgreement(CK_MECHANIS - CKYStatus status = trans.begin(conn); - if( status != CKYSUCCESS ) handleConnectionError(); - -- if (state & GOV_CARD) { -- selectCACApplet(keyNum, true); -- } else { -- selectApplet(); -- } -- - CKYISOStatus result; -- int loginAttempted = 0; -+ bool loginAttempted = false; - - retry: -+ selectKey(key, loginAttempted); - - if (state & PIV_CARD) { -- status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, publicDataBuffer, -- secretKeyBuffer, &result); -+ status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, -+ publicDataBuffer, secretKeyBuffer, &result); - } else if (state & CAC_CARD) { -- status = CACApplet_SignDecrypt(conn, publicDataBuffer, secretKeyBuffer, &result); -+ status = CACApplet_SignDecrypt(conn, publicDataBuffer, -+ secretKeyBuffer, &result); -+ } else if (state & P15_CARD) { -+ /*status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8, -+ publicDataBuffer, secretKeyBuffer, &result); */ -+ throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); - } else { -- status = CKYApplet_ComputeECCKeyAgreement(conn, keyNum, -- publicDataBuffer , NULL, secretKeyBuffer, getNonce(), &result); -+ status = CKYApplet_ComputeECCKeyAgreement(conn, objectToKeyNum(key), -+ publicDataBuffer , NULL, secretKeyBuffer, -+ getNonce(), &result); - } - /* map the ISO not logged in code to the coolkey one */ - if ((result == CKYISO_CONDITION_NOT_SATISFIED) || -@@ -4610,13 +5145,10 @@ retry: - throw PKCS11Exception(CKR_DATA_INVALID); - } - if (!isVersion1Key && !loginAttempted && -- (result == CKYISO_UNAUTHORIZED)) { -+ userPinCache(key->getUser())->isValid() && -+ (result == CKYISO_UNAUTHORIZED)) { - try { -- if (state & GOV_CARD) { -- attemptCACLogin(); -- } else { -- oldAttemptLogin(); -- } -+ attemptLogin(key->getUser(), true); - } catch(PKCS11Exception& ) { - throw PKCS11Exception(CKR_DEVICE_ERROR); - } -diff -up ./src/coolkey/slot.h.p15 ./src/coolkey/slot.h ---- ./src/coolkey/slot.h.p15 2015-07-06 10:27:55.772827229 -0700 -+++ ./src/coolkey/slot.h 2015-07-06 10:27:55.786826965 -0700 -@@ -183,7 +183,7 @@ struct PinCache { - CKYBuffer_Replace(&cachedPin, 0, (const CKYByte *)newPin, pinLen); - CKYBuffer_AppendChar(&cachedPin, 0); - } -- void clearPin() { CKYBuffer_Zero(&cachedPin); } -+ void clearPin() { CKYBuffer_Zero(&cachedPin); valid = false; } - void invalidate() { valid = false; } - void validate() { valid = true; } - const CKYBuffer *get() const { return &cachedPin; } -@@ -209,29 +209,26 @@ class CryptOpState { - public: - enum State { NOT_INITIALIZED, IN_PROCESS, FINALIZED }; - State state; -- CKYByte keyNum; - CKYBuffer result; -- PKCS11Object::KeyType keyType; -+ PKCS11Object *key; - -- CryptOpState() : state(NOT_INITIALIZED), keyNum(0), keyType(PKCS11Object::unknown) -+ CryptOpState() : state(NOT_INITIALIZED), key(NULL) - { CKYBuffer_InitEmpty(&result); } - CryptOpState(const CryptOpState &cpy) : -- state(cpy.state), keyNum(cpy.keyNum), keyType(cpy.keyType) { -+ state(cpy.state), key(cpy.key) { - CKYBuffer_InitFromCopy(&result, &cpy.result); - } - CryptOpState &operator=(const CryptOpState &cpy) { - state = cpy.state, -- keyNum = cpy.keyNum; -- keyType = cpy.keyType; -+ key = cpy.key; - CKYBuffer_Replace(&result, 0, CKYBuffer_Data(&cpy.result), - CKYBuffer_Size(&cpy.result)); - return *this; - } - ~CryptOpState() { CKYBuffer_FreeData(&result); } -- void initialize(CKYByte keyNum, PKCS11Object::KeyType theKeyType) { -+ void initialize(PKCS11Object *theKey) { - state = IN_PROCESS; -- this->keyNum = keyNum; -- this->keyType = theKeyType; -+ this->key = theKey; - CKYBuffer_Resize(&result, 0); - } - }; -@@ -298,6 +295,7 @@ class CryptParams { - }; - - #define MAX_CERT_SLOTS 3 -+#define MAX_AUTH_USERS 3 - class Slot { - - public: -@@ -308,7 +306,8 @@ class Slot { - APPLET_SELECTABLE = 0x08, - APPLET_PERSONALIZED = 0x10, - CAC_CARD = 0x20, -- PIV_CARD = 0x40 -+ PIV_CARD = 0x40, -+ P15_CARD = 0x80 - }; - enum { - NONCE_SIZE = 8 -@@ -321,6 +320,7 @@ class Slot { - char *readerName; - char *personName; - char *manufacturer; -+ char *tokenManufacturer; - //char *model; - CK_VERSION hwVersion; - CK_VERSION tokenFWVersion; -@@ -329,6 +329,7 @@ class Slot { - CKYCardConnection* conn; - unsigned long state; // = UNKNOWN - PinCache pinCache; -+ PinCache contextPinCache; - bool loggedIn; - bool reverify; - bool nonceValid; -@@ -349,6 +350,14 @@ class Slot { - int pivContainer; - int pivKey; - bool mECC; -+ unsigned short p15aid; -+ unsigned short p15odfAddr; -+ unsigned short p15tokenInfoAddr; -+ unsigned int p15Instance; -+ CKYBuffer p15AID; -+ CKYBuffer p15tokenInfo; -+ CKYBuffer p15odf; -+ CKYBuffer p15serialNumber; - //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 }; - - #ifdef USE_SHMEM -@@ -367,6 +376,7 @@ class Slot { - - void closeAllSessions(); - SessionHandleSuffix generateNewSession(Session::Type type); -+ PK15Object *auth[MAX_AUTH_USERS]; - - bool cardStateMayHaveChanged(); - void connectToToken(); -@@ -418,48 +428,63 @@ class Slot { - bool throwException); - CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); - -+ CKYStatus getP15Params(); - void selectApplet(); - void selectCACApplet(CKYByte instance,bool do_disconnect); -+ void selectKey(const PKCS11Object *key, bool retry); -+ CKYStatus selectPath(const CKYBuffer *path, CKYISOStatus *adpurc); -+ CKYStatus readFromPath(const PK15ObjectPath &obj, CKYBuffer *file); - void unloadObjects(); - void loadCACObjects(); - void loadCACCert(CKYByte instance); - void loadObjects(); - void loadReaderObject(); - -- void attemptLogin(const char *pin); -+ void attemptCoolKeyLogin(const char *pin); -+ void attemptLogin(CK_USER_TYPE user, bool flushPin); -+ void attemptP15Login(CK_USER_TYPE user); - void attemptCACLogin(); - void oldAttemptLogin(); - void oldLogout(void); - void CACLogout(void); -+ PinCache *userPinCache(CK_USER_TYPE user) { -+ return ((user == CKU_CONTEXT_SPECIFIC) && (state & P15_CARD)) ? -+ &contextPinCache : &pinCache; } -+ -+ void parseEF_ODF(void); -+ void parseEF_TokenInfo(void); -+ CKYStatus parseEF_Directory(const CKYByte *data, CKYSize size, -+ PK15ObjectType type); -+ unsigned int PK15Instance(void) { return p15Instance++; } - - void readMuscleObject(CKYBuffer *obj, unsigned long objID, - unsigned int objSize); - - void performSignature(CKYBuffer *sig, const CKYBuffer *unpaddedInput, -- CKYByte keyNum); -- void performDecryption(CKYBuffer *data, const CKYBuffer *input, CKYByte keyNum); -+ const PKCS11Object *key); -+ void performDecryption(CKYBuffer *data, const CKYBuffer *input, -+ const PKCS11Object *key); - - void cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput, - CK_ULONG ulInputLen, CK_BYTE_PTR pOutput, - CK_ULONG_PTR pulOutputLen, CryptParams& params); - -- void performRSAOp(CKYBuffer *out, const CKYBuffer *input, unsigned int keySize, -- CKYByte keyNum, CKYByte direction); -+ void performRSAOp(CKYBuffer *out, const CKYBuffer *input, -+ unsigned int keySize, const PKCS11Object *key, 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); -+ unsigned int keySize, const PKCS11Object *key); - void performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, -- CKYBuffer *publicDataBuffer, -- CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize); -+ CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, -+ const PKCS11Object *key, unsigned int keySize); - - void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu); - -- CKYByte objectHandleToKeyNum(CK_OBJECT_HANDLE hKey); -- unsigned int calcECCKeySize(CKYByte keyNum); -+ CKYByte objectToKeyNum(const PKCS11Object *key); - Slot(const Slot &cpy) - #ifdef USE_SHMEM - : shmem(readerName) -@@ -491,10 +516,10 @@ class Slot { - } - - // actually get the size of a key in bits from the card -- unsigned int getRSAKeySize(CKYByte keyNum); -- unsigned int getECCKeySize(CKYByte keyNum); -+ unsigned int getRSAKeySize(PKCS11Object *key); -+ unsigned int getECCKeySize(PKCS11Object *key); - -- PKCS11Object::KeyType getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey); -+ PKCS11Object *getKeyFromHandle(CK_OBJECT_HANDLE hKey); - - SessionHandleSuffix openSession(Session::Type type); - void closeSession(SessionHandleSuffix handleSuffix); -@@ -504,8 +529,8 @@ class Slot { - void getSessionInfo(SessionHandleSuffix handleSuffix, - CK_SESSION_INFO_PTR pInfo); - -- void login(SessionHandleSuffix handleSuffix, CK_UTF8CHAR_PTR pPin, -- CK_ULONG ulPinLen); -+ void login(SessionHandleSuffix handleSuffix, CK_USER_TYPE user, -+ CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); - - void logout(SessionHandleSuffix suffix); - -@@ -604,8 +629,8 @@ class SlotList { - void getSessionInfo(CK_SESSION_HANDLE sessionHandle, - CK_SESSION_INFO_PTR pInfo); - -- void login(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, -- CK_ULONG ulPinLen); -+ void login(CK_SESSION_HANDLE hSession, CK_USER_TYPE user, -+ CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); - - void logout(CK_SESSION_HANDLE hSession); - -diff -up ./src/libckyapplet/cky_applet.c.p15 ./src/libckyapplet/cky_applet.c ---- ./src/libckyapplet/cky_applet.c.p15 2015-07-06 10:27:55.775827172 -0700 -+++ ./src/libckyapplet/cky_applet.c 2015-07-06 10:27:55.787826946 -0700 -@@ -19,6 +19,7 @@ - - #include - #include "cky_applet.h" -+#include - - #define MIN(x, y) ((x) < (y) ? (x) : (y)) - -@@ -51,6 +52,12 @@ CACAppletFactory_SelectFile(CKYAPDU *apd - } - - CKYStatus -+P15AppletFactory_SelectFile(CKYAPDU *apdu, const void *param) -+{ -+ return CKYAPDUFactory_SelectFile(apdu, 0, 0, (const CKYBuffer *)param); -+} -+ -+CKYStatus - CKYAppletFactory_SelectCardManager(CKYAPDU *apdu, const void *param) - { - return CKYAPDUFactory_SelectCardManager(apdu); -@@ -269,17 +276,10 @@ PIVAppletFactory_SignDecrypt(CKYAPDU *ap - } - - CKYStatus --CACAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param) -+P15AppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param) - { -- const char *pin=(const char *)param; -- 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); -+ const P15AppletArgVerifyPIN *vps = (const P15AppletArgVerifyPIN *)param; -+ return P15APDUFactory_VerifyPIN(apdu, vps->pinRef, vps->pinVal); - } - - CKYStatus -@@ -323,6 +323,39 @@ CKYAppletFactory_LogoutAllV0(CKYAPDU *ap - return CKYAPDU_SetSendData(apdu, data, sizeof(data)); - } - -+CKYStatus -+P15AppletFactory_ReadRecord(CKYAPDU *apdu, const void *param) -+{ -+ const P15AppletArgReadRecord *rrs = (const P15AppletArgReadRecord *)param; -+ return P15APDUFactory_ReadRecord(apdu, rrs->record, -+ rrs->short_ef, rrs->flags, rrs->size); -+} -+ -+CKYStatus -+P15AppletFactory_ReadBinary(CKYAPDU *apdu, const void *param) -+{ -+ const P15AppletArgReadBinary *res = (const P15AppletArgReadBinary *)param; -+ return P15APDUFactory_ReadBinary(apdu, res->offset, -+ res->short_ef, res->flags, res->size); -+} -+ -+CKYStatus -+P15AppletFactory_ManageSecurityEnvironment(CKYAPDU *apdu, const void *param) -+{ -+ const P15AppletArgManageSecurityEnvironment *mse = -+ (const P15AppletArgManageSecurityEnvironment *)param; -+ return P15APDUFactory_ManageSecurityEnvironment(apdu, mse->p1, -+ mse->p2, mse->keyRef); -+} -+ -+CKYStatus -+P15AppletFactory_PerformSecurityOperation(CKYAPDU *apdu, const void *param) -+{ -+ const P15AppletArgPerformSecurityOperation *pso = -+ (const P15AppletArgPerformSecurityOperation *)param; -+ return P15APDUFactory_PerformSecurityOperation(apdu, pso->dir, pso->chain, -+ pso->retLen, pso->data); -+} - /***************************************************************** - * - * Generic Fill routines used by several calls in common -@@ -975,9 +1008,6 @@ CKYApplet_ComputeECCSignature(CKYCardCon - 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; -@@ -1052,6 +1082,11 @@ done: - return ret; - } - -+const P15PinInfo CACPinInfo = -+ { P15PinInitialized|P15PinNeedsPadding, P15PinUTF8, 0, 8, 8, 0, 0xff }; -+const P15PinInfo PIVPinInfo = -+ { P15PinLocal|P15PinInitialized|P15PinNeedsPadding, -+ P15PinUTF8, 0, 8, 8, 0, 0xff }; - /* - * do a CAC VerifyPIN - */ -@@ -1059,23 +1094,8 @@ CKYStatus - CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, int local, - CKYISOStatus *apduRC) - { -- CKYStatus ret; -- CKYISOStatus status; -- if (apduRC == NULL) { -- apduRC = &status; -- } -- -- ret = CKYApplet_HandleAPDU(conn, local ? PIVAppletFactory_VerifyPIN : -- CACAppletFactory_VerifyPIN, pin, NULL, -- 0, CKYAppletFill_Null, -- NULL, apduRC); -- /* it's unfortunate that the same code that means 'more data to follow' for -- * GetCertificate also means, auth failure, you only have N more attempts -- * left in the verify PIN call */ -- if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) { -- ret = CKYAPDUFAIL; -- } -- return ret; -+ return P15Applet_VerifyPIN(conn, pin, -+ local ? &PIVPinInfo: &CACPinInfo, apduRC); - } - - -@@ -1165,6 +1185,214 @@ CACApplet_ReadFile(CKYCardConnection *co - return ret; - } - -+/* -+ * Select a EF -+ */ -+CKYStatus -+P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef, -+ CKYISOStatus *apduRC) -+{ -+ CKYStatus ret; -+ CKYBuffer efBuf; -+ CKYBuffer_InitEmpty(&efBuf); -+ CKYBuffer_AppendShort(&efBuf, ef); -+ ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_SelectFile, &efBuf, -+ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); -+ CKYBuffer_FreeData(&efBuf); -+ return ret; -+} -+ -+CKYStatus -+P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef, -+ CKYISOStatus *apduRC) -+{ -+ CKYStatus ret; -+ CKYBuffer efBuf; -+ CKYBuffer_InitEmpty(&efBuf); -+ CKYBuffer_AppendShort(&efBuf, ef); -+ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &efBuf, -+ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); -+ CKYBuffer_FreeData(&efBuf); -+ return ret; -+} -+ -+CKYStatus -+P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin, -+ const P15PinInfo *pinInfo, CKYISOStatus *apduRC) -+{ -+ CKYStatus ret; -+ CKYISOStatus status; -+ CKYSize size; -+ CKYBuffer encodedPin; -+ P15AppletArgVerifyPIN vps; -+ -+ CKYBuffer_InitEmpty(&encodedPin); -+ -+ if (apduRC == NULL) { -+ apduRC = &status; -+ } -+ -+ size = strlen(pin); -+ if (pinInfo->pinFlags & P15PinNeedsPadding) { -+ if (size > pinInfo->storedLength) { -+ size = pinInfo->storedLength; -+ } -+ ret=CKYBuffer_Reserve(&encodedPin, pinInfo->storedLength); -+ if (ret != CKYSUCCESS) { goto fail; } -+ } -+ /* This is where we would do upcase processing for the case insensitive -+ * flag. It's also where we would do mapping for bcd pins */ -+ ret = CKYBuffer_Replace(&encodedPin, 0, (const CKYByte *)pin, size); -+ if (ret != CKYSUCCESS) { goto fail; } -+ if (pinInfo->pinFlags & P15PinNeedsPadding) { -+ int i; -+ int padSize = pinInfo->storedLength - size; -+ for (i=0; i < padSize; i++) { -+ CKYBuffer_AppendChar(&encodedPin, pinInfo->padChar); -+ } -+ } -+ -+ vps.pinRef = pinInfo->pinRef | -+ ((pinInfo->pinFlags & P15PinLocal) ? ISO_LOGIN_LOCAL : ISO_LOGIN_GLOBAL); -+ vps.pinVal = &encodedPin; -+ ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_VerifyPIN, &vps, NULL, -+ 0, CKYAppletFill_Null, -+ NULL, apduRC); -+ /* it's unfortunate that the same code that means 'more data to follow' for -+ * GetCertificate also means, auth failure, you only have N more attempts -+ * left in the verify PIN call */ -+ if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) { -+ ret = CKYAPDUFAIL; -+ } -+fail: -+ CKYBuffer_FreeData(&encodedPin); -+ return ret; -+} -+ -+ -+/* -+ * Read Record -+ */ -+CKYStatus -+P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record, CKYByte short_ef, -+ CKYByte flags, CKYByte size, CKYBuffer *data, CKYISOStatus *apduRC) -+{ -+ P15AppletArgReadRecord rrd; -+ -+ rrd.record = record; -+ rrd.short_ef = short_ef; -+ rrd.flags = flags; -+ rrd.size = size; -+ return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadRecord, &rrd, NULL, -+ CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, data, apduRC); -+} -+ -+static CKYStatus -+P15Applet_ManageSecurityEnvironment(CKYCardConnection *conn, CKYByte key, -+ CKYByte direction, CKYByte p1, -+ CKYISOStatus *apduRC) -+{ -+ P15AppletArgManageSecurityEnvironment mse; -+ -+ mse.p1 = p1; /* this appears to be where most cards disagree */ -+ mse.p2 = (direction == CKY_DIR_DECRYPT) ? ISO_MSE_KEA : ISO_MSE_SIGN; -+ mse.keyRef = key; /* should be CKYBuffer in the future? */ -+ return CKYApplet_HandleAPDU(conn, -+ P15AppletFactory_ManageSecurityEnvironment, &mse, NULL, -+ CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); -+} -+ -+CKYStatus -+P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key, -+ unsigned int keySize, CKYByte direction, -+ const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC) -+{ -+ CKYStatus ret; -+ P15AppletArgPerformSecurityOperation pso; -+ CKYSize dataSize = CKYBuffer_Size(data); -+ CKYOffset offset = 0; -+ CKYBuffer tmp; -+ int length = dataSize; -+ int appendLength = length; -+ int hasPad = 0; -+ -+ /* Hack, lie and say we are always doing encipherment */ -+ direction = CKY_DIR_DECRYPT; -+ CKYBuffer_Resize(result,0); -+ /* -+ * first set the security environment -+ */ -+ ret = P15Applet_ManageSecurityEnvironment(conn, key, direction, -+ ISO_MSE_SET|ISO_MSE_QUAL_COMPUTE, apduRC); -+ if (ret != CKYSUCCESS) { -+ return ret; -+ } -+ -+ CKYBuffer_InitEmpty(&tmp); -+ -+ pso.data = &tmp; -+ pso.dir = direction; -+ if (direction == CKY_DIR_DECRYPT) { -+ length++; -+ CKYBuffer_AppendChar(&tmp, 0x00); /* pad byte */ -+ hasPad = 1; -+ } -+ if (CKYCardConnection_GetProtocol(conn) == SCARD_PROTOCOL_T0) { -+ ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE); -+ if (ret != CKYSUCCESS) { -+ goto done; -+ } -+ for(offset = 0; length > CKY_MAX_WRITE_CHUNK_SIZE; -+ hasPad = 0, -+ offset += CKY_MAX_WRITE_CHUNK_SIZE, -+ length -= CKY_MAX_WRITE_CHUNK_SIZE) { -+ pso.chain = 1; -+ pso.retLen = 0; -+ CKYBuffer_AppendBuffer(&tmp, data, offset, -+ hasPad ? (CKY_MAX_WRITE_CHUNK_SIZE-1) : CKY_MAX_WRITE_CHUNK_SIZE); -+ ret = CKYApplet_HandleAPDU(conn, -+ P15AppletFactory_PerformSecurityOperation, &pso, NULL, -+ CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC); -+ if (ret != CKYSUCCESS) { -+ goto done; -+ } -+ CKYBuffer_Resize(&tmp, 0); -+ } -+ appendLength = length; -+ } else { -+ ret = CKYBuffer_Reserve(&tmp, length); -+ } -+ CKYBuffer_AppendBuffer(&tmp, data, offset, appendLength); -+ pso.chain = 0; -+ pso.retLen = dataSize; -+ -+ ret = CKYApplet_HandleAPDU(conn, -+ P15AppletFactory_PerformSecurityOperation, &pso, NULL, -+ CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, result, apduRC); -+ -+done: -+ CKYBuffer_FreeData(&tmp); -+ return ret; -+} -+ -+/* -+ * Read Binary -+ */ -+CKYStatus -+P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset, -+ CKYByte short_ef, CKYByte flags, CKYByte size, -+ CKYBuffer *data, CKYISOStatus *apduRC) -+{ -+ P15AppletArgReadBinary red; -+ -+ red.offset = offset; -+ red.short_ef = short_ef; -+ red.flags = flags; -+ red.size = size; -+ return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadBinary, &red, NULL, -+ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, data, apduRC); -+} -+ - CKYStatus - CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, - CKYSize *nextSize, CKYISOStatus *apduRC) -@@ -1632,6 +1860,7 @@ CKYApplet_ReadObjectFull(CKYCardConnecti - return ret; - } - -+ - /* - * Write Object - * This makes multiple APDU calls to write the entire object. -diff -up ./src/libckyapplet/cky_applet.h.p15 ./src/libckyapplet/cky_applet.h ---- ./src/libckyapplet/cky_applet.h.p15 2015-07-06 10:27:55.776827153 -0700 -+++ ./src/libckyapplet/cky_applet.h 2015-07-06 10:27:55.788826927 -0700 -@@ -204,6 +204,7 @@ typedef struct _CKYAppletArgReadObject { - CKYByte size; - } CKYAppletArgReadObject; - -+ - typedef struct _CKYAppletArgWriteObject { - unsigned long objectID; - CKYOffset offset; -@@ -262,6 +263,39 @@ typedef struct _PIVAppletRespSignDecrypt - CKYBuffer *buf; - } PIVAppletRespSignDecrypt; - -+typedef struct _P15AppletArgReadRecord { -+ CKYByte record; -+ CKYByte short_ef; -+ CKYByte flags; -+ CKYByte size; -+} P15AppletArgReadRecord; -+ -+typedef struct _P15AppletArgReadBinary { -+ unsigned short offset; -+ CKYByte short_ef; -+ CKYByte flags; -+ CKYByte size; -+} P15AppletArgReadBinary; -+ -+typedef struct _P15AppletArgVerifyPIN { -+ const CKYBuffer *pinVal; -+ CKYByte pinRef; -+} P15AppletArgVerifyPIN; -+ -+typedef struct _P15AppletArgManageSecurityEnvironment { -+ CKYByte p1; -+ CKYByte p2; -+ CKYByte keyRef; -+} -+ P15AppletArgManageSecurityEnvironment; -+ -+typedef struct _P15AppletArgPerformSecurityOperation { -+ CKYByte dir; -+ int chain; -+ CKYSize retLen; -+ const CKYBuffer *data; -+} P15AppletArgPerformSecurityOperation; -+ - /* 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*/ -@@ -514,6 +548,7 @@ CKYStatus CACApplet_ReadFile(CKYCardConn - CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef, - CKYISOStatus *apduRC); - -+ - /* must happen with PKI applet selected */ - CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data, - CKYBuffer *result, CKYISOStatus *apduRC); -@@ -539,6 +574,26 @@ CKYStatus PIVApplet_SignDecrypt(CKYCardC - unsigned int keySize, int derive, - const CKYBuffer *data, CKYBuffer *result, - CKYISOStatus *apduRC); -+ -+/* PKCS Commands 15 */ -+CKYStatus P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef, -+ CKYISOStatus *apduRC); -+CKYStatus P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef, -+ CKYISOStatus *apduRC); -+CKYStatus P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record, -+ CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data, -+ CKYISOStatus *apduRC); -+CKYStatus P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset, -+ CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data, -+ CKYISOStatus *apduRC); -+CKYStatus P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin, -+ const P15PinInfo *pinInfo, CKYISOStatus *apduRC); -+ -+CKYStatus P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key, -+ unsigned int keySize, CKYByte direction, -+ const CKYBuffer *data, CKYBuffer *result, -+ CKYISOStatus *apduRC); -+ - /* - * There are 3 read commands: - * -diff -up ./src/libckyapplet/cky_base.c.p15 ./src/libckyapplet/cky_base.c ---- ./src/libckyapplet/cky_base.c.p15 2015-07-06 10:27:55.776827153 -0700 -+++ ./src/libckyapplet/cky_base.c 2015-07-06 10:27:55.788826927 -0700 -@@ -651,21 +651,38 @@ CKYStatus - CKYAPDU_SetSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len) - { - CKYStatus ret; -+ CKYOffset offset = 0; - -- if (len > CKYAPDU_MAX_DATA_LEN) { -- return CKYDATATOOLONG; -- } -+ /* Encode with T1 if necessary */ - -- ret = CKYBuffer_Resize(&apdu->apduBuf, len + CKYAPDU_HEADER_LEN); -- if (ret != CKYSUCCESS) { -- return ret; -+ if (len < CKYAPDU_MAX_DATA_LEN) { -+ offset = 0; -+ ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN); -+ if (ret != CKYSUCCESS ) { -+ return ret; -+ } -+ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) len); -+ } else if (len < CKYAPDU_MAX_T1_DATA_LEN) { -+ offset = 2; -+ ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN); -+ if (ret != CKYSUCCESS ) { -+ return ret; -+ } -+ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) 0); -+ if (ret != CKYSUCCESS) { -+ return ret; -+ } -+ ret = CKYBuffer_SetShort(&apdu->apduBuf,CKY_LC_OFFSET+1, -+ (unsigned short)len); -+ } else { -+ return CKYDATATOOLONG; - } -- ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, -- len == CKYAPDU_MAX_DATA_LEN ? 0: (CKYByte) len); -+ - if (ret != CKYSUCCESS) { - return ret; - } -- return CKYBuffer_Replace(&apdu->apduBuf, CKYAPDU_HEADER_LEN, data, len); -+ return CKYBuffer_Replace(&apdu->apduBuf, -+ CKYAPDU_HEADER_LEN + offset , data, len); - } - - CKYStatus -@@ -685,15 +702,15 @@ CKYAPDU_AppendSendData(CKYAPDU *apdu, co - } - - dataLen = CKYBuffer_Size(&apdu->apduBuf) + len - CKYAPDU_HEADER_LEN; -- if (dataLen > CKYAPDU_MAX_DATA_LEN) { -+ /* only handles T0 encoding, not T1 encoding */ -+ if (dataLen >= CKYAPDU_MAX_DATA_LEN) { - return CKYDATATOOLONG; - } - ret = CKYBuffer_AppendData(&apdu->apduBuf, data, len); - if (ret != CKYSUCCESS) { - return ret; - } -- return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, -- dataLen == CKYAPDU_MAX_DATA_LEN ? 0 : (CKYByte) dataLen); -+ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) dataLen); - } - - CKYStatus -@@ -714,11 +731,100 @@ CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKY - } - - CKYStatus -+CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen) -+{ -+ CKYStatus ret; -+ -+ if (recvlen <= CKYAPDU_MAX_DATA_LEN) { -+ return APDU_SetReceiveLen(apdu, (CKYByte)(recvlen & 0xff)); -+ } -+ ret = CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_HEADER_LEN+2); -+ if (ret != CKYSUCCESS) { -+ return ret; -+ } -+ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, 0); -+ if (ret != CKYSUCCESS) { -+ return ret; -+ } -+ return CKYBuffer_SetShort(&apdu->apduBuf, CKY_LE_OFFSET+1, recvlen); -+} -+ -+CKYStatus -+CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen) -+{ -+ if (recvlen <= CKYAPDU_MAX_T1_DATA_LEN) { -+ return CKYAPDU_SetShortReceiveLen(apdu, (unsigned short) -+ (recvlen & 0xffff)); -+ } -+ return CKYDATATOOLONG; -+} -+ -+/* -+ * Append Le, If Le=0, treat it as 256 (CKYAPD_MAX_DATA_LEN) -+ */ -+CKYStatus - CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen) - { -+ /* If we already have a data buffer, make sure that we aren't already -+ * using T1 encoding */ -+ if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) { -+ if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) == 0) { -+ /* we are using T1 encoding, use AppendShort*/ -+ return CKYBuffer_AppendShort(&apdu->apduBuf, -+ recvlen ? (unsigned short) recvlen: CKYAPDU_MAX_DATA_LEN); -+ } -+ } - return CKYBuffer_AppendChar(&apdu->apduBuf, recvlen); - } - -+/* -+ * Append a short Le. If Le be encoded with just T0, do so. If Le=0 treat -+ * it as 65536 (CKYAPDU_MAX_T1_DATA_LEN) -+ */ -+CKYStatus -+CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen) -+{ -+ CKYStatus ret; -+ /* If we already have a data buffer, it's encoding affects ours */ -+ if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) { -+ /* CKY_LC_OFFSET == 0 means T1, otherwise it's T0 */ -+ if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) != 0) { -+ /* remember 0 is 65536 here */ -+ if ((recvlen == 0) || (recvlen > CKYAPDU_MAX_DATA_LEN)) { -+ /* we can't a encode T1 receive length if we already have a -+ * T0 encoded buffer data */ -+ return CKYDATATOOLONG; -+ } -+ /* T0 encoding */ -+ return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff); -+ } -+ /* T1 encoding */ -+ return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen); -+ } -+ /* if length fits in a bit and we aren't forced into T1 encoding, use -+ * T0 */ -+ if ((recvlen != 0) && (recvlen <= CKYAPDU_MAX_DATA_LEN)) { -+ return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff); -+ } -+ /* write the T1 encoding marker */ -+ ret = CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)0); -+ if (ret != CKYSUCCESS) { -+ return ret; -+ } -+ /* T1 encoded length */ -+ return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen); -+} -+ -+CKYStatus -+CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen) -+{ -+ if (recvlen > CKYAPDU_MAX_T1_DATA_LEN) { -+ return CKYDATATOOLONG; -+ } -+ return CKYAPDU_AppendShortReceiveLen(apdu, -+ (unsigned short)(recvlen & 0xffff)); -+} -+ - - void - CKY_SetName(const char *p) -diff -up ./src/libckyapplet/cky_base.h.p15 ./src/libckyapplet/cky_base.h ---- ./src/libckyapplet/cky_base.h.p15 2015-07-06 10:27:55.777827135 -0700 -+++ ./src/libckyapplet/cky_base.h 2015-07-06 10:27:55.789826908 -0700 -@@ -32,6 +32,8 @@ typedef unsigned char CKYByte; - /* Bool type */ - typedef unsigned char CKYBool; - -+typedef unsigned long CKYBitFlags; -+ - #define CKYBUFFER_PUBLIC \ - unsigned long reserved1;\ - unsigned long reserved2;\ -@@ -93,6 +95,8 @@ typedef enum { - * (command) sent. ADPUIOStatus has more info on - * why the APDU failed */ - CKYINVALIDARGS, /* Caller passed in bad args */ -+ CKYINVALIDDATA, /* Data supplied was invalid */ -+ CKYUNSUPPORTED, /* Requested Operation or feature is not supported */ - } CKYStatus; - - /* -@@ -107,12 +111,56 @@ typedef enum { - #define CKY_LE_OFFSET 4 - - #define CKYAPDU_MAX_DATA_LEN 256 -+#define CKYAPDU_MAX_T1_DATA_LEN 65536 - #define CKYAPDU_MIN_LEN 4 - #define CKYAPDU_HEADER_LEN 5 - #define CKYAPDU_MAX_LEN (CKYAPDU_HEADER_LEN+CKYAPDU_MAX_DATA_LEN) - #define CKY_MAX_ATR_LEN 32 - #define CKY_OUTRAGEOUS_MALLOC_SIZE (1024*1024) - -+#define P15FlagsPrivate 0x00000001 -+#define P15FlagsModifiable 0x00000002 -+ -+#define P15UsageEncrypt 0x00000001 -+#define P15UsageDecrypt 0x00000002 -+#define P15UsageSign 0x00000004 -+#define P15UsageSignRecover 0x00000008 -+#define P15UsageWrap 0x00000010 -+#define P15UsageUnwrap 0x00000020 -+#define P15UsageVerify 0x00000040 -+#define P15UsageVerifyRecover 0x00000080 -+#define P15UsageDerive 0x00000100 -+#define P15UsageNonRepudiation 0x00000200 -+ -+#define P15AccessSensitive 0x00000001 -+#define P15AccessExtractable 0x00000002 -+#define P15AccessAlwaysSenstive 0x00000004 -+#define P15AccessNeverExtractable 0x00000008 -+#define P15AccessLocal 0x00000010 -+ -+#define P15PinCaseSensitive 0x00000001 -+#define P15PinLocal 0x00000002 -+#define P15PinChangeDisabled 0x00000004 -+#define P15PinUnblockDisabled 0x00000008 -+#define P15PinInitialized 0x00000010 -+#define P15PinNeedsPadding 0x00000020 -+#define P15PinUnblockingPin 0x00000040 -+#define P15PinSOPin 0x00000080 -+#define P15PinDisableAllowed 0x00000100 -+ -+typedef enum {P15PinBCD=0, P15PinASCIINum=1, P15PinUTF8=2} P15PinType; -+ -+typedef struct _P15PinInfo { -+ CKYBitFlags pinFlags; -+ P15PinType pinType; -+ CKYByte minLength; -+ CKYByte storedLength; -+ unsigned long maxLength; -+ CKYByte pinRef; -+ CKYByte padChar; -+} P15PinInfo; -+ -+ - /* - * allow direct inclusion in C++ files - */ -@@ -278,7 +326,11 @@ 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_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen); -+CKYStatus CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen); - CKYStatus CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen); -+CKYStatus CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen); -+CKYStatus CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen); - - /* set the parent loadmodule name */ - void CKY_SetName(const char *name); -diff -up ./src/libckyapplet/cky_card.c.p15 ./src/libckyapplet/cky_card.c ---- ./src/libckyapplet/cky_card.c.p15 2015-07-06 10:27:55.778827116 -0700 -+++ ./src/libckyapplet/cky_card.c 2015-07-06 10:27:55.790826889 -0700 -@@ -910,6 +910,7 @@ ckyCardConnection_init(CKYCardConnection - conn->protocol = SCARD_PROTOCOL_T0; - } - -+ - CKYCardConnection * - CKYCardConnection_Create(const CKYCardContext *ctx) - { -@@ -984,6 +985,12 @@ CKYCardConnection_IsConnected(const CKYC - return (conn->cardHandle != 0); - } - -+unsigned long -+CKYCardConnection_GetProtocol(const CKYCardConnection *conn) -+{ -+ return conn->protocol; -+} -+ - CKYStatus - ckyCardConnection_reconnectRaw(CKYCardConnection *conn, unsigned long init) - { -@@ -996,6 +1003,7 @@ ckyCardConnection_reconnectRaw(CKYCardCo - conn->lastError = rv; - return CKYSCARDERR; - } -+ conn->protocol = protocol; - return CKYSUCCESS; - } - -diff -up ./src/libckyapplet/cky_card.h.p15 ./src/libckyapplet/cky_card.h ---- ./src/libckyapplet/cky_card.h.p15 2015-07-06 10:27:55.766827342 -0700 -+++ ./src/libckyapplet/cky_card.h 2015-07-06 10:27:55.790826889 -0700 -@@ -116,6 +116,7 @@ CKYStatus CKYCardConnection_ExchangeAPDU - CKYStatus CKYCardConnection_Connect(CKYCardConnection *connection, - const char *readerName); - CKYStatus CKYCardConnection_Disconnect(CKYCardConnection *connection); -+unsigned long CKYCardConnection_GetProtocol(const CKYCardConnection *conn); - CKYBool CKYCardConnection_IsConnected(const CKYCardConnection *connection); - CKYStatus CKYCardConnection_Reconnect(CKYCardConnection *connection); - CKYStatus CKYCardConnection_GetStatus(CKYCardConnection *connection, -diff -up ./src/libckyapplet/cky_factory.c.p15 ./src/libckyapplet/cky_factory.c ---- ./src/libckyapplet/cky_factory.c.p15 2015-07-06 10:27:55.778827116 -0700 -+++ ./src/libckyapplet/cky_factory.c 2015-07-06 10:27:55.791826870 -0700 -@@ -29,7 +29,7 @@ CKYAPDUFactory_SelectFile(CKYAPDU *apdu, - const CKYBuffer *AID) - { - CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -- CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE); -+ CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE); - CKYAPDU_SetP1(apdu, p1); - CKYAPDU_SetP2(apdu, p2); - return CKYAPDU_SetSendDataBuffer(apdu, AID); -@@ -40,7 +40,7 @@ CKYAPDUFactory_SelectCardManager(CKYAPDU - { - CKYByte c = 0; - CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -- CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE); -+ CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE); - CKYAPDU_SetP1(apdu, 0x04); - CKYAPDU_SetP2(apdu, 0x00); - /* I can't find the documentation for this, but if you pass an empty -@@ -57,7 +57,7 @@ CKYStatus - CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu) - { - CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM); -- CKYAPDU_SetINS(apdu, CKY_INS_GET_DATA); -+ CKYAPDU_SetINS(apdu, ISO_INS_GET_DATA); - CKYAPDU_SetP1(apdu, 0x9f); - CKYAPDU_SetP2(apdu, 0x7f); - return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_CPLCDATA); -@@ -707,6 +707,7 @@ fail: - CKYBuffer_FreeData(&buf); - return ret; - } -+ - CKYStatus - CACAPDUFactory_GetProperties(CKYAPDU *apdu) - { -@@ -718,37 +719,6 @@ CACAPDUFactory_GetProperties(CKYAPDU *ap - } - - CKYStatus --CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const char *pin) --{ -- CKYStatus ret; -- CKYSize size; -- -- CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -- CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN); -- CKYAPDU_SetP1(apdu, 0x00); -- CKYAPDU_SetP2(apdu, keyRef); -- /* no pin, send an empty buffer */ -- if (!pin) { -- return CKYAPDU_SetReceiveLen(apdu, 0); -- } -- -- /* all CAC pins are 8 bytes exactly. If to long, truncate it */ -- size = strlen(pin); -- if (size > 8) { -- size = 8; -- } -- ret = CKYAPDU_SetSendData(apdu, (unsigned char *) pin, size); -- /* if too short, pad it */ -- if ((ret == CKYSUCCESS) && (size < 8)) { -- static const unsigned char pad[]= { 0xff , 0xff, 0xff ,0xff, -- 0xff, 0xff, 0xff, 0xff }; -- return CKYAPDU_AppendSendData(apdu, pad, 8-size); -- } -- return ret; -- --} -- --CKYStatus - PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg, - CKYByte key, int len, const CKYBuffer *data) - { -@@ -807,3 +777,109 @@ fail: - return ret; - } - -+CKYStatus -+P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const CKYBuffer *pin) -+{ -+ CKYStatus ret; -+ -+ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -+ CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN); -+ CKYAPDU_SetP1(apdu, 0x00); -+ CKYAPDU_SetP2(apdu, keyRef); -+ /* no pin, send an empty buffer */ -+ if (CKYBuffer_Size(pin) == 0) { -+ return CKYAPDU_SetReceiveLen(apdu, 0); -+ } -+ -+ /* all CAC pins are 8 bytes exactly. If to long, truncate it */ -+ ret = CKYAPDU_SetSendDataBuffer(apdu, pin); -+ return ret; -+ -+} -+ -+CKYStatus -+P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record, CKYByte short_ef, -+ CKYByte flags, CKYByte count) -+{ -+ CKYByte control; -+ -+ control = (short_ef << 3) & 0xf8; -+ control |= flags & 0x07; -+ -+ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -+ CKYAPDU_SetINS(apdu, ISO_INS_READ_RECORD); -+ CKYAPDU_SetP1(apdu, record); -+ CKYAPDU_SetP2(apdu, control); -+ return CKYAPDU_SetReceiveLen(apdu, count); -+} -+ -+CKYStatus -+P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset, -+ CKYByte short_ef, CKYByte flags, CKYByte count) -+{ -+ CKYByte p1 = 0,p2 = 0; -+ unsigned short max_offset = 0; -+ -+ if (flags & P15_USE_SHORT_EF) { -+ max_offset = 0xff; -+ p1 = P15_USE_SHORT_EF | (short_ef & 0x7); -+ p2 = offset & 0xff; -+ } else { -+ max_offset = 0x7fff; -+ p1 = (offset >> 8) & 0x7f; -+ p2 = offset & 0xff; -+ } -+ if (offset > max_offset) { -+ return CKYINVALIDARGS; -+ } -+ -+ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -+ CKYAPDU_SetINS(apdu, ISO_INS_READ_BINARY); -+ CKYAPDU_SetP1(apdu, p1); -+ CKYAPDU_SetP2(apdu, p2); -+ return CKYAPDU_SetReceiveLen(apdu, count); -+} -+ -+CKYStatus -+P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu, CKYByte p1, CKYByte p2, -+ CKYByte keyRef) -+{ -+ CKYByte param[3]; -+ -+ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816); -+ CKYAPDU_SetINS(apdu, ISO_INS_MANAGE_SECURITY_ENVIRONMENT); -+ CKYAPDU_SetP1(apdu, p1); -+ CKYAPDU_SetP2(apdu, p2); -+ param[0] = 0x83; -+ param[1] = 1; -+ param[2] = keyRef; -+ return CKYAPDU_SetSendData(apdu, param, sizeof param); -+} -+ -+CKYStatus -+P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir, -+ int chain, CKYSize retLen, const CKYBuffer *data) -+{ -+ CKYByte p1,p2; -+ CKYStatus ret; -+ -+ CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN : -+ CKY_CLASS_ISO7816); -+ CKYAPDU_SetINS(apdu, ISO_INS_PERFORM_SECURITY_OPERATION); -+ if (dir == CKY_DIR_DECRYPT) { -+ p1 = ISO_PSO_DECRYPT_P1; -+ p2 = ISO_PSO_DECRYPT_P2; -+ } else { -+ p1 = ISO_PSO_SIGN_P1; -+ p2 = ISO_PSO_SIGN_P2; -+ } -+ CKYAPDU_SetP1(apdu, p1); -+ CKYAPDU_SetP2(apdu, p2); -+ ret = CKYAPDU_SetSendDataBuffer(apdu, data); -+ if (ret == CKYSUCCESS && (chain == 0) && retLen != 0) { -+ ret = CKYAPDU_AppendReceiveLength(apdu, retLen); -+ } -+ return ret; -+} -+ -+ -diff -up ./src/libckyapplet/cky_factory.h.p15 ./src/libckyapplet/cky_factory.h ---- ./src/libckyapplet/cky_factory.h.p15 2015-07-06 10:27:55.779827097 -0700 -+++ ./src/libckyapplet/cky_factory.h 2015-07-06 10:27:55.791826870 -0700 -@@ -35,8 +35,31 @@ - * Applet Instruction Bytes - */ - /* Card Manager */ --#define CKY_INS_SELECT_FILE 0xa4 --#define CKY_INS_GET_DATA 0xca -+#define ISO_INS_SELECT_FILE 0xa4 -+#define ISO_INS_GET_DATA 0xca -+#define ISO_INS_READ_BINARY 0xb0 -+#define ISO_INS_READ_RECORD 0xb2 -+#define ISO_INS_MANAGE_SECURITY_ENVIRONMENT 0x22 -+#define ISO_INS_PERFORM_SECURITY_OPERATION 0x2a -+ -+/* ISO Parameters: */ -+#define ISO_LOGIN_LOCAL 0x80 -+#define ISO_LOGIN_GLOBAL 0x00 -+#define ISO_MSE_SET 0x01 -+#define ISO_MSE_STORE 0xf2 -+#define ISO_MSE_RESTORE 0xf3 -+#define ISO_MSE_ERASE 0xf4 -+#define ISO_MSE_QUAL_VERIFY 0x80 -+#define ISO_MSE_QUAL_COMPUTE 0x40 -+#define ISO_MSE_AUTH 0xa4 -+#define ISO_MSE_SIGN 0xb6 -+#define ISO_MSE_KEA 0xb8 -+#define ISO_PSO_SIGN_P1 0x9e -+#define ISO_PSO_SIGN_P2 0x9a -+#define ISO_PSO_ENCRYPT_P1 0x86 -+#define ISO_PSO_ENCRYPT_P2 0x80 -+#define ISO_PSO_DECRYPT_P1 0x80 -+#define ISO_PSO_DECRYPT_P2 0x86 - - /* deprecated */ - #define CKY_INS_SETUP 0x2A -@@ -84,6 +107,7 @@ - #define CKY_INS_SEC_READ_IOBUF 0x08 - #define CKY_INS_SEC_START_ENROLLMENT 0x0C - -+ - /* CAC */ - #define CAC_INS_GET_CERTIFICATE 0x36 - #define CAC_INS_SIGN_DECRYPT 0x42 -@@ -94,11 +118,8 @@ - #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 - - /* -@@ -121,7 +142,7 @@ - /* functions */ - #define CKY_CIPHER_INIT 1 - #define CKY_CIPHER_PROCESS 2 --#define CKY_CIPHER_FINAL 3 -+#define CKY_CIPHER_FINAL 3 - #define CKY_CIPHER_ONE_STEP 4 /* init and final in one APDU */ - - /* modes */ -@@ -173,6 +194,18 @@ - #define CKY_CARDM_MANAGER_LOCKED 0x7f - #define CKY_CARDM_MANAGER_TERMINATED 0xff - -+/* Read Record Flags */ -+#define P15_READ_P1 0x4 -+#define P15_READ_P1_TO_LAST 0x5 -+#define P15_READ_LAST_TO_P1 0x6 -+#define P15_READ_FIRST 0x0 -+#define P15_READ_LAST 0x1 -+#define P15_READ_NEXT 0x2 -+#define P15_READ_PREV 0x3 -+ -+/* Read Binary Flags */ -+#define P15_USE_SHORT_EF 0x80 -+ - /* - * The following factories 'Fill in' APDUs for each of the - * functions described below. Nonces are not automatically added. -@@ -234,17 +267,28 @@ CKYStatus CKYAPDUFactory_GetBuiltinACL(C - - CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, - const CKYBuffer *data); --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); - -+CKYStatus P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, -+ const CKYBuffer *pin); -+CKYStatus P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record, -+ CKYByte short_ef, CKYByte flags, CKYByte count); -+CKYStatus P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset, -+ CKYByte short_ef, CKYByte flags, CKYByte count); -+CKYStatus P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu, -+ CKYByte p1, CKYByte p2, CKYByte key); -+CKYStatus P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir, -+ int chain, CKYSize retLen, const CKYBuffer *data); -+ -+ - CKY_END_PROTOS - - #endif /* CKY_FACTORY_H */ diff --git a/coolkey-1.1.0-rhel7-alt-cac.patch b/coolkey-1.1.0-rhel7-alt-cac.patch deleted file mode 100644 index d43a7eb..0000000 --- a/coolkey-1.1.0-rhel7-alt-cac.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff -up ./src/coolkey/coolkey.cpp.alt-cac ./src/coolkey/coolkey.cpp ---- ./src/coolkey/coolkey.cpp.alt-cac 2016-12-01 15:37:49.106167768 -0800 -+++ ./src/coolkey/coolkey.cpp 2016-12-01 15:37:49.113167892 -0800 -@@ -80,9 +80,16 @@ ecMechanismList[] = { - {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, - {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } - }; -+static const MechInfo -+allMechanismList[] = { -+ {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }, -+ {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, -+ {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } -+}; - - unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo); - unsigned int numECMechanisms = sizeof(ecMechanismList)/sizeof(MechInfo); -+unsigned int numAllMechanisms = sizeof(allMechanismList)/sizeof(MechInfo); - - /* ------------------------------------------------------------ */ - -@@ -382,13 +389,22 @@ C_GetMechanismList(CK_SLOT_ID slotID, CK - return CKR_TOKEN_NOT_PRESENT; - } - -- if ( slot->getIsECC()) { -+ switch (slot->getAlgs()) { -+ case ALG_ECC|ALG_RSA: -+ mechanismList = allMechanismList; -+ numMechanisms = numAllMechanisms; -+ break; -+ case ALG_ECC: - mechanismList = ecMechanismList; - numMechanisms = numECMechanisms; -- } else { -+ break; -+ case ALG_NONE: -+ case ALG_RSA: -+ default: - mechanismList = rsaMechanismList; - numMechanisms = numRSAMechanisms; -- } -+ break; -+ } - - if( pMechanismList != NULL ) { - if( *pulCount < numMechanisms ) { -@@ -438,13 +454,22 @@ C_GetMechanismInfo(CK_SLOT_ID slotID, CK - return CKR_TOKEN_NOT_PRESENT; - } - -- if ( slot->getIsECC()) { -+ switch (slot->getAlgs()) { -+ case ALG_ECC|ALG_RSA: -+ mechanismList = allMechanismList; -+ numMechanisms = numAllMechanisms; -+ break; -+ case ALG_ECC: - mechanismList = ecMechanismList; - numMechanisms = numECMechanisms; -- } else { -+ break; -+ case ALG_NONE: -+ case ALG_RSA: -+ default: - mechanismList = rsaMechanismList; - numMechanisms = numRSAMechanisms; -- } -+ break; -+ } - - for(unsigned int i=0; i < numMechanisms; ++i ) { - if( mechanismList[i].mech == type ) { -diff -up ./src/coolkey/object.cpp.alt-cac ./src/coolkey/object.cpp ---- ./src/coolkey/object.cpp.alt-cac 2016-12-01 15:37:49.097167608 -0800 -+++ ./src/coolkey/object.cpp 2016-12-01 15:37:49.114167910 -0800 -@@ -1232,7 +1232,7 @@ Reader::Reader(unsigned long muscleObjID - } - - --CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : -+CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : - PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16, - instance | 0x400) - { -@@ -1242,7 +1242,9 @@ CACPrivKey::CACPrivKey(CKYByte instance, - - /* So we know what the key is supposed to be used for based on - * the instance */ -- if (instance == 2) { -+ /* instance 2 is usually a decryption cert. >2 are usually old decryption -+ * certs */ -+ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { - decrypt = TRUE; - } - -@@ -1305,8 +1307,8 @@ CACPrivKey::CACPrivKey(CKYByte instance, - CKYBuffer_FreeData(¶m2); - } - --CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : -- PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16, -+CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : -+ PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16, - instance | 0x500) - { - CKYBuffer id; -@@ -1315,7 +1317,7 @@ CACPubKey::CACPubKey(CKYByte instance, c - - /* So we know what the key is supposed to be used for based on - * the instance */ -- if (instance == 2) { -+ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { - encrypt = TRUE; - } - -@@ -1359,6 +1361,9 @@ CACPubKey::CACPubKey(CKYByte instance, c - setAttribute(CKA_EC_POINT, ¶m1); - setAttribute(CKA_EC_PARAMS, ¶m2); - setAttributeULong(CKA_KEY_TYPE, CKK_EC); -+ setAttributeBool(CKA_VERIFY_RECOVER, FALSE); -+ setAttributeBool(CKA_ENCRYPT, FALSE); -+ setAttributeBool(CKA_DERIVE, encrypt); - break; - default: - break; -@@ -1376,6 +1381,26 @@ static const char *CAC_Label[] = { - "CAC ID Certificate", - "CAC Email Signature Certificate", - "CAC Email Encryption Certificate", -+ "CAC Cert 3", -+ "CAC Cert 4", -+ "CAC Cert 5", -+ "CAC Cert 6", -+ "CAC Cert 7", -+ "CAC Cert 8", -+ "CAC Cert 9", -+}; -+ -+static const char *PIV_Label[] = { -+ "PIV ID Certificate", -+ "PIV Email Signature Certificate", -+ "PIV Email Encryption Certificate", -+ "PIV Card Authentication Certificate", -+ "PIV Cert 4", -+ "PIV Cert 5", -+ "PIV Cert 6", -+ "PIV Cert 7", -+ "PIV Cert 8", -+ "PIV Cert 9", - }; - - static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 }; -@@ -1454,7 +1479,7 @@ GetUserName(const CKYBuffer *dn) - return string; - } - --CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : -+CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : - PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, - instance | 0x600) - { -@@ -1471,7 +1496,7 @@ CACCert::CACCert(CKYByte instance, const - setAttribute(CKA_ID, &id); - CKYBuffer_FreeData(&id); - setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509); -- setAttribute(CKA_LABEL, CAC_Label[instance]); -+ setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]); - - CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial); - CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject); -diff -up ./src/coolkey/object.h.alt-cac ./src/coolkey/object.h ---- ./src/coolkey/object.h.alt-cac 2016-12-01 15:37:49.087167430 -0800 -+++ ./src/coolkey/object.h 2016-12-01 15:37:49.115167928 -0800 -@@ -219,17 +219,17 @@ class Cert : public PKCS11Object { - - class CACPrivKey : public PKCS11Object { - public: -- CACPrivKey(CKYByte instance, const PKCS11Object &cert); -+ CACPrivKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); - }; - - class CACPubKey : public PKCS11Object { - public: -- CACPubKey(CKYByte instance, const PKCS11Object &cert); -+ CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); - }; - - class CACCert : public PKCS11Object { - public: -- CACCert(CKYByte instance, const CKYBuffer *derCert); -+ CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV); - }; - - typedef enum { PK15StateInit, PK15StateNeedObject, -diff -up ./src/coolkey/slot.cpp.alt-cac ./src/coolkey/slot.cpp ---- ./src/coolkey/slot.cpp.alt-cac 2016-12-01 15:37:49.110167839 -0800 -+++ ./src/coolkey/slot.cpp 2016-12-01 15:57:37.307994776 -0800 -@@ -415,8 +415,9 @@ Slot::Slot(const char *readerName_, Log - slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), - isVersion1Key(false), needLogin(false), fullTokenName(false), - mCoolkey(false), mOldCAC(false), mCACLocalLogin(false), -- pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0), -- p15tokenInfoAddr(0), p15Instance(0), -+ pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS), -+ algs(ALG_NONE), p15aid(0), p15odfAddr(0), p15tokenInfoAddr(0), -+ p15Instance(0), - #ifdef USE_SHMEM - shmem(readerName_), - #endif -@@ -776,6 +777,7 @@ Slot::connectToToken() - state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; - isVersion1Key = 0; - needLogin = true; -+ maxCacCerts = MAX_CERT_SLOTS; - mCoolkey = 0; - mOldCAC = 0; - mCACLocalLogin = getPIVLoginType(); -@@ -927,8 +929,12 @@ Slot::getCACAid() - } - /* yes, fill in the old applets */ - mOldCAC = true; -+ maxCacCerts = 1; - for (i=1; i< MAX_CERT_SLOTS; i++) { -- CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); -+ status = CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); -+ if (status == CKYSUCCESS) { -+ maxCacCerts = i+1; -+ } - } - return CKYSUCCESS; - } -@@ -986,6 +992,7 @@ Slot::getCACAid() - if (certSlot == 0) { - status = CKYAPDUFAIL; /* probably neeed a beter error code */ - } -+ maxCacCerts = certSlot; - - done: - CKYBuffer_FreeData(&tBuf); -@@ -2168,12 +2175,11 @@ Slot::addKeyObject(list& o - } - keyObj.completeKey(*iter); - -- /* For now this is how we determine what type of key. -- Also for now, allow only one or the other */ -+ /* use key object to determine what algorithms we support */ - if ( keyObj.getKeyType() == PKCS11Object::ecc) { -- mECC = true; -+ algs = (SlotAlgs) (algs | ALG_ECC); - } else { -- mECC = false; -+ algs = (SlotAlgs) (algs | ALG_RSA); - } - - } -@@ -2205,7 +2211,7 @@ Slot::addCertObject(list& - void - Slot::unloadObjects() - { -- mECC = false; -+ algs = ALG_NONE; - tokenObjects.clear(); - free(personName); - personName = NULL; -@@ -2269,29 +2275,42 @@ Slot::unloadObjects() - // Shared memory segments are fixed size (equal to the object memory size of - // the token). - // -+// -+// -+ -+struct SlotDataPair { -+ unsigned long dataOffset; -+ unsigned long dataSize; -+}; - - struct SlotSegmentHeader { - unsigned short version; - unsigned short headerSize; - unsigned char valid; -- unsigned char reserved; -+ unsigned char firstCacCert; - unsigned char cuid[10]; -- unsigned short reserved2; -+ -+ unsigned short reserved; - unsigned short dataVersion; - unsigned short dataHeaderOffset; - unsigned short dataOffset; - unsigned long dataHeaderSize; - unsigned long dataSize; -- unsigned long cert2Offset; -- unsigned long cert2Size; -+ unsigned long nextDataOffset; -+ SlotDataPair cacCerts[MAX_CERT_SLOTS]; - }; - -+const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */ -+const unsigned short CAC_DATA_VERSION=2; -+ -+ - #define MAX_OBJECT_STORE_SIZE 15000 - // - // previous development versions used a segment prefix of - // "coolkeypk11s" - // --#define SEGMENT_PREFIX "coolkeypk11s" -+#define SEGMENT_PREFIX "coolkeypk11t" // update segment since the old cache was -+ // incompatible - #define CAC_FAKE_CUID "CAC Certs" - SlotMemSegment::SlotMemSegment(const char *readerName): - segmentAddr(NULL), segmentSize(0), segment(NULL) -@@ -2320,9 +2339,8 @@ SlotMemSegment::SlotMemSegment(const cha - return; - } - -- SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; - if (needInit) { -- segmentHeader->valid = 0; -+ clearValid(0); - } - segmentSize = segment->getSHMemSize(); - } -@@ -2396,6 +2414,18 @@ SlotMemSegment::getDataVersion() const - return segmentHeader->dataVersion; - } - -+unsigned char -+SlotMemSegment::getFirstCacCert() const -+{ -+ if (!segment) { -+ return NOT_A_CAC; -+ } -+ -+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; -+ -+ return segmentHeader->firstCacCert; -+} -+ - void - SlotMemSegment::setVersion(unsigned short version) - { -@@ -2419,6 +2449,18 @@ SlotMemSegment::setDataVersion(unsigned - segmentHeader->dataVersion = version; - } - -+void -+SlotMemSegment::setFirstCacCert(unsigned char firstCacCert) -+{ -+ if (!segment) { -+ return; -+ } -+ -+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; -+ -+ segmentHeader->firstCacCert = firstCacCert; -+} -+ - bool - SlotMemSegment::isValid() const - { -@@ -2493,23 +2535,13 @@ SlotMemSegment::readCACCert(CKYBuffer *o - int size; - CKYByte *data; - -- switch (instance) { -- case 0: -- data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; -- size = segmentHeader->dataHeaderSize; -- break; -- case 1: -- data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; -- size = segmentHeader->dataSize; -- break; -- case 2: -- data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; -- size = segmentHeader->cert2Size; -- break; -- default: -+ if (instance >= MAX_CERT_SLOTS) { - CKYBuffer_Resize(objData, 0); - return; - } -+ data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance] -+ .dataOffset]; -+ size = segmentHeader->cacCerts[instance].dataSize; - CKYBuffer_Replace(objData, 0, data, size); - } - -@@ -2523,30 +2555,20 @@ SlotMemSegment::writeCACCert(const CKYBu - SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; - int size = CKYBuffer_Size(data); - CKYByte *shmData; -- switch (instance) { -- case 0: -- segmentHeader->headerSize = sizeof *segmentHeader; -- segmentHeader->dataHeaderOffset = sizeof *segmentHeader; -- segmentHeader->dataHeaderSize = size; -- segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size; -- segmentHeader->dataSize = 0; -- segmentHeader->cert2Offset = segmentHeader->dataOffset; -- segmentHeader->cert2Size = 0; -- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; -- break; -- case 1: -- segmentHeader->dataSize = size; -- segmentHeader->cert2Offset = segmentHeader->dataOffset + size; -- segmentHeader->cert2Size = 0; -- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; -- break; -- case 2: -- segmentHeader->cert2Size = size; -- shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; -- break; -- default: -+ -+ if (instance >= MAX_CERT_SLOTS) { - return; - } -+ -+ if (segmentHeader->firstCacCert == NOT_A_CAC) { -+ segmentHeader->firstCacCert = instance; -+ } -+ unsigned long dataOffset = segmentHeader->nextDataOffset; -+ segmentHeader->cacCerts[instance].dataOffset = dataOffset; -+ segmentHeader->nextDataOffset += size; -+ segmentHeader->cacCerts[instance].dataSize = size; -+ shmData = (CKYByte *) &segmentAddr[dataOffset]; -+ - memcpy(shmData, CKYBuffer_Data(data), size); - } - -@@ -2558,15 +2580,18 @@ SlotMemSegment::clearValid(CKYByte insta - return; - } - SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; -- switch (instance) { -- case 0: -- segmentHeader->headerSize = 0; -- segmentHeader->dataHeaderSize = 0; -- /* fall through */ -- case 1: -- segmentHeader->dataSize = 0; -+ -+ segmentHeader->headerSize = sizeof *segmentHeader; -+ segmentHeader->dataHeaderOffset = sizeof *segmentHeader; -+ segmentHeader->dataHeaderSize = 0; -+ segmentHeader->dataSize = 0; -+ for (int i=0; i < MAX_CERT_SLOTS; i++) { -+ segmentHeader->cacCerts[i].dataSize = 0; - } -+ segmentHeader->dataOffset = sizeof *segmentHeader; -+ segmentHeader->nextDataOffset = sizeof *segmentHeader; - segmentHeader->valid = 0; -+ segmentHeader->firstCacCert = NOT_A_CAC; - } - - void -@@ -2882,8 +2907,7 @@ berProcess(CKYBuffer *buf, int matchTag, - - - CKYStatus --Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, -- bool throwException) -+Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize) - { - CKYStatus status; - CKYISOStatus apduRC; -@@ -2897,9 +2921,6 @@ Slot::readCACCertificateFirst(CKYBuffer - CKYBuffer_InitEmpty(&certInfo); - CKYBuffer_Resize(cert, 0); - status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC); -- if (throwException && (status != CKYSUCCESS)) { -- handleConnectionError(); -- } - /* actually, on success, we need to parse the certificate and find the - * propper tag */ - if (status == CKYSUCCESS) { -@@ -2940,10 +2961,10 @@ Slot::readCACCertificateFirst(CKYBuffer - if (mOldCAC) { - /* get the first 100 bytes of the cert */ - status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); -- if (throwException && (status != CKYSUCCESS)) { -- handleConnectionError(); -+ if (status == CKYSUCCESS) { -+ return status; - } -- return status; -+ /* try to use CACApplet_ReadFile before we give up */ - } - - CKYBuffer tBuf; -@@ -2959,11 +2980,11 @@ Slot::readCACCertificateFirst(CKYBuffer - - /* handle the new CAC card read */ - /* read the TLV */ -- status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); -+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, &apduRC); - if (status != CKYSUCCESS) { - goto done; - } -- status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); -+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, &apduRC); - if (status != CKYSUCCESS) { - goto done; - } -@@ -3199,14 +3220,12 @@ Slot::loadCACCert(CKYByte instance) - CKYStatus status = CKYSUCCESS; - CKYBuffer cert; - CKYBuffer rawCert; -- CKYBuffer shmCert; - CKYSize nextSize; - - OSTime time = OSTimeNow(); - - CKYBuffer_InitEmpty(&cert); - CKYBuffer_InitEmpty(&rawCert); -- CKYBuffer_InitEmpty(&shmCert); - - // - // not all CAC cards have all the PKI instances -@@ -3215,78 +3234,24 @@ Slot::loadCACCert(CKYByte instance) - try { - selectCACApplet(instance, false); - } catch(PKCS11Exception& e) { -- // all CAC's must have instance '0', throw the error it -- // they don't. -- if (instance == 0) throw e; -- // If the CAC doesn't have instance '2', and we were updating -- // the shared memory, set it to valid now. -- if ((instance == 2) && !shmem.isValid()) { -- shmem.setValid(); -- } - return; - } - - log->log("CAC Cert %d: select CAC applet: %d ms\n", - instance, OSTimeNow() - time); - -- if (instance == 0) { -- readCACCertificateFirst(&rawCert, &nextSize, true); -- -- if(CKYBuffer_Size(&rawCert) <= 1) { -- handleConnectionError(); -- } -- log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", -- instance, OSTimeNow() - time); -- } -- -- unsigned short dataVersion = 1; -- CKYBool needRead = 1; -- - /* see if it matches the shared memory */ -- if (shmem.isValid() && shmem.getDataVersion() == dataVersion) { -- shmem.readCACCert(&shmCert, instance); -- CKYSize certSize = CKYBuffer_Size(&rawCert); -- CKYSize shmCertSize = CKYBuffer_Size(&shmCert); -- const CKYByte *shmData = CKYBuffer_Data(&shmCert); -- -- if (instance != 0) { -- needRead = 0; -- } -- -- if (shmCertSize >= certSize) { -- if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { -- /* yes it does, no need to read the rest of the cert, use -- * the cache */ -- CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize); -- needRead = 0; -- } -- } -- if (!needRead && (shmCertSize == 0)) { -+ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION) { -+ shmem.readCACCert(&rawCert, instance); -+ if (CKYBuffer_Size(&rawCert) == 0) { - /* no cert of this type, just return */ - return; - } -- } -- CKYBuffer_FreeData(&shmCert); -- -- if (needRead) { -- /* it doesn't, read the new cert and update the cache */ -- if (instance == 0) { -- shmem.clearValid(0); -- shmem.setVersion(SHMEM_VERSION); -- shmem.setDataVersion(dataVersion); -- } else { -- status = readCACCertificateFirst(&rawCert, &nextSize, false); -- -- if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { -- /* CAC only requires the Certificate in pki '0' */ -- /* if pki '1' or '2' are empty, treat it as a non-fatal error*/ -- if (instance == 2) { -- /* we've attempted to read all the certs, shared memory -- * is now valid */ -- shmem.setValid(); -- } -- return; -- } -+ } else { -+ status = readCACCertificateFirst(&rawCert, &nextSize); -+ if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { -+ /*this cert doesn't exist, go to the next one */ -+ return; - } - - if (nextSize) { -@@ -3298,9 +3263,6 @@ Slot::loadCACCert(CKYByte instance) - handleConnectionError(); - } - shmem.writeCACCert(&rawCert, instance); -- if (instance == 2) { -- shmem.setValid(); -- } - } - - -@@ -3368,14 +3330,17 @@ Slot::loadCACCert(CKYByte instance) - log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n", - instance, OSTimeNow() - time); - -- CACCert certObj(instance, &cert); -- CACPrivKey privKey(instance, certObj); -- CACPubKey pubKey(instance, certObj); -+ bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD); -+ CACCert certObj(instance, &cert, isPIV); -+ CACPrivKey privKey(instance, certObj, isPIV); -+ CACPubKey pubKey(instance, certObj, isPIV); - tokenObjects.push_back(privKey); - tokenObjects.push_back(pubKey); - tokenObjects.push_back(certObj); - if ( pubKey.getKeyType() == PKCS11Object::ecc) { -- mECC = 1; -+ algs = (SlotAlgs) (algs | ALG_ECC); -+ } else { -+ algs = (SlotAlgs) (algs | ALG_RSA); - } - - if (personName == NULL) { -@@ -3388,6 +3353,94 @@ Slot::loadCACCert(CKYByte instance) - } - - void -+Slot::initCACShMem(void) -+{ -+ bool failed = false; -+ -+ unsigned char firstCert = shmem.getFirstCacCert(); -+ -+ log->log("init CACShMem: \n"); -+ /* check to make sure the shared memory is initialized with a CAC card */ -+ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION -+ && firstCert != NOT_A_CAC) { -+ CKYBuffer rawCert; -+ CKYBuffer shmCert; -+ CKYSize nextSize; -+ -+ log->log("init CACShMem: valid CAC cache found firstCert = %d\n", -+ firstCert); -+ CKYBuffer_InitEmpty(&rawCert); -+ CKYBuffer_InitEmpty(&shmCert); -+ -+ -+ /* yes, see if it's this cac card by comparing the first cert -+ * in the chain */ -+ -+ /* see if the first cert is in the expected slot */ -+ try { -+ selectCACApplet(firstCert, false); -+ } catch(PKCS11Exception& e) { -+ failed = true; -+ log->log("init CACShMem: applet select failed firstCert = %d\n", -+ firstCert); -+ } -+ if (!failed) { -+ CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize); -+ if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) { -+ failed = true; -+ log->log("init CACShMem: read Cert failed firstCert = %d\n", -+ firstCert); -+ } -+ } -+ if (!failed) { -+ shmem.readCACCert(&shmCert, firstCert); -+ CKYSize certSize = CKYBuffer_Size(&rawCert); -+ CKYSize shmCertSize = CKYBuffer_Size(&shmCert); -+ const CKYByte *shmData = CKYBuffer_Data(&shmCert); -+ -+ if (shmCertSize >= certSize) { -+ if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { -+ /* this card is cached, go on and use the cache */ -+ log->log("init CACShMem: entries match, using cache\n"); -+ CKYBuffer_FreeData(&rawCert); -+ CKYBuffer_FreeData(&shmCert); -+ return; -+ } -+ } -+ log->log("init CACShMem: no entry match certSize=%d" -+ " shmCertSize=%d\n",certSize, shmCertSize); -+ } -+ CKYBuffer_FreeData(&rawCert); -+ CKYBuffer_FreeData(&shmCert); -+ } -+ -+ log->log("init CACShMem: starting new cache valid=%d version=%d " -+ " firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(), -+ firstCert); -+ /* cache is either invalid or for another card, start initializing it */ -+ shmem.clearValid(0); -+ shmem.setVersion(SHMEM_VERSION); -+ shmem.setDataVersion(CAC_DATA_VERSION); -+} -+ -+void -+Slot::verifyCACShMem(void) -+{ -+ /* if the memory is valid, then nothing to do */ -+ if (shmem.isValid()) { -+ return; -+ } -+ /* if we didn't find any cert fail */ -+ if (shmem.getFirstCacCert() == NOT_A_CAC) { -+ shmem.clearValid(0); -+ disconnect(); -+ throw PKCS11Exception(CKR_DEVICE_REMOVED); -+ } -+ /* we're all set, let others see our results */ -+ shmem.setValid(); -+} -+ -+void - Slot::loadObjects() - { - // throw away all token objects! -@@ -3406,9 +3459,11 @@ Slot::loadObjects() - std::list::iterator iter; - - if (state & GOV_CARD) { -- loadCACCert(0); -- loadCACCert(1); -- loadCACCert(2); -+ initCACShMem(); -+ for (int i=0; i < maxCacCerts; i++) { -+ loadCACCert(i); -+ } -+ verifyCACShMem(); - status = trans.end(); - loadReaderObject(); - return; -@@ -4720,10 +4775,6 @@ Slot::performECCSignature(CKYBuffer *out - CKYStatus status = trans.begin(conn); - if( status != CKYSUCCESS ) handleConnectionError(); - -- if (!mECC) { -- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); -- } -- - CKYISOStatus result; - bool loginAttempted = false; - -@@ -4790,9 +4841,6 @@ Slot::performRSAOp(CKYBuffer *output, co - unsigned int keySize, const PKCS11Object *key, - CKYByte direction) - { -- if ( mECC ) { -- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); -- } - - // - // establish a transaction -@@ -5145,10 +5193,6 @@ Slot::performECCKeyAgreement(CK_MECHANIS - CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, - const PKCS11Object *key, unsigned int keySize) - { -- if (!mECC) { -- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); -- } -- - Transaction trans; - CKYStatus status = trans.begin(conn); - if( status != CKYSUCCESS ) handleConnectionError(); -diff -up ./src/coolkey/slot.h.alt-cac ./src/coolkey/slot.h ---- ./src/coolkey/slot.h.alt-cac 2016-12-01 15:37:49.104167732 -0800 -+++ ./src/coolkey/slot.h 2016-12-01 15:37:49.117167964 -0800 -@@ -79,9 +79,11 @@ public: - bool CUIDIsEqual(const CKYBuffer *cuid) const; - unsigned short getVersion() const; - unsigned short getDataVersion() const; -+ unsigned char getFirstCacCert() const; - void setCUID(const CKYBuffer *cuid); - void setVersion(unsigned short version); - void setDataVersion(unsigned short version); -+ void setFirstCacCert(unsigned char firstCacCert); - bool isValid() const; - int size() const; - const unsigned char *getCUID() const; -@@ -90,6 +92,7 @@ public: - void setSize(int size); - void readData(CKYBuffer *data) const; - void writeData(const CKYBuffer *data); -+ void initCACHeaders(void); - void readCACCert(CKYBuffer *data, CKYByte instance) const; - void writeCACCert(const CKYBuffer *data, CKYByte instance); - void clearValid(CKYByte instance); -@@ -294,7 +297,13 @@ class CryptParams { - const CKYBuffer *paddedOutput) const = 0; - }; - --#define MAX_CERT_SLOTS 3 -+#define MAX_CERT_SLOTS 10 -+typedef enum { -+ ALG_NONE= 0x0, -+ ALG_ECC = 0x1, -+ ALG_RSA = 0x2 -+} SlotAlgs; -+ - #define MAX_AUTH_USERS 3 - class Slot { - -@@ -349,7 +358,8 @@ class Slot { - bool mCACLocalLogin; - int pivContainer; - int pivKey; -- bool mECC; -+ int maxCacCerts; -+ SlotAlgs algs; - unsigned short p15aid; - unsigned short p15odfAddr; - unsigned short p15tokenInfoAddr; -@@ -424,8 +434,7 @@ class Slot { - list fetchSeparateObjects(); - - CKYStatus getCACAid(); -- CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, -- bool throwException); -+ CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize); - CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); - - CKYStatus getP15Params(); -@@ -485,6 +494,8 @@ class Slot { - void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu); - - CKYByte objectToKeyNum(const PKCS11Object *key); -+ void initCACShMem(void); -+ void verifyCACShMem(void); - Slot(const Slot &cpy) - #ifdef USE_SHMEM - : shmem(readerName) -@@ -580,7 +591,7 @@ class Slot { - CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, - CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params); - -- bool getIsECC() { return mECC; } -+ SlotAlgs getAlgs() { return algs; } - }; - - class SlotList { diff --git a/coolkey-1.3.0.tar.gz b/coolkey-1.3.0.tar.gz deleted file mode 100644 index a82c44a..0000000 --- a/coolkey-1.3.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:75b74597b0941d19bf813d70346cdae84f43a96c08ea2dd87597f09769ced268 -size 462821 diff --git a/coolkey-fix-token-removal-failure.patch b/coolkey-fix-token-removal-failure.patch deleted file mode 100644 index 5faecb5..0000000 --- a/coolkey-fix-token-removal-failure.patch +++ /dev/null @@ -1,86 +0,0 @@ -Fix insertion/removal detection - -pcsc now errors out of the SCardGetStatusChange call with -SCARD_E_UNKNOWN_READER if any of the passed readers aren't known. -This includes readers that were very recently forgotton about because -a user just disconnected them. - -(See - http://anonscm.debian.org/viewvc/pcsclite/trunk/PCSC/src/winscard_clnt.c?r1=5858&r2=5881 -for the change to pcsc) - -Unfortunately, this means SECMOD_WaitForAnyTokenEvent will fail with a -SC_NO_EVENT error if a user removes their smartcard at the wrong time. - -This patch changes coolkey to detect removed readers before calling -SCardGetStatusChange, so that it can handle the removal itself. - -diff -up coolkey-1.1.0/src/coolkey/slot.cpp.fix coolkey-1.1.0/src/coolkey/slot.cpp ---- coolkey-1.1.0/src/coolkey/slot.cpp.fix 2013-05-22 16:23:41.728846957 -0400 -+++ coolkey-1.1.0/src/coolkey/slot.cpp 2013-05-22 17:09:59.813958927 -0400 -@@ -279,24 +279,22 @@ SlotList::updateReaderList() - * don't recognize. - */ - -- /* first though, let's check to see if any previously removed readers have -- * come back from the dead. If the ignored bit has been set, we do not need -- * it any more. -- */ -+ /* Iterate through all the readers to see if we need to make unavailable any -+ * freshly removed readers. Also, see if any previously removed -+ * readers have come back from the dead and don't need to be ignored. -+ */ - - const char *curReaderName = NULL; - unsigned long knownState = 0; - for(int ri = 0 ; ri < numReaders; ri ++) { -- - knownState = CKYReader_GetKnownState(&readerStates[ri]); -- if( !(knownState & SCARD_STATE_IGNORE)) { -- continue; -- } -- -+ - curReaderName = CKYReader_GetReaderName(&readerStates[ri]); - if(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); - } - } - -@@ -1238,6 +1236,32 @@ SlotList::waitForSlotEvent(CK_FLAGS flag - throw; - } - -+ /* Before round-tripping to the daemon for the duration of the -+ * timeout, first see if we lost any readers, and pick a slot -+ * from that set to return -+ */ -+ for (i=0; i < numReaders; 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); -+ readerListLock.releaseLock(); -+ *slotp = slotIndexToID(i); -+ found = TRUE; -+ break; -+ } -+ } -+ -+ if (found) { -+ break; -+ } -+ -+ if (shuttingDown) { -+ readerListLock.releaseLock(); -+ break; -+ } -+ - if (myNumReaders != numReaders) { - if (myReaderStates) { - delete [] myReaderStates; diff --git a/coolkey-piv-ecc-el7.patch b/coolkey-piv-ecc-el7.patch deleted file mode 100644 index b47b80c..0000000 --- a/coolkey-piv-ecc-el7.patch +++ /dev/null @@ -1,4792 +0,0 @@ -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 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& objectList, const ListObjectInfo& info, - CK_OBJECT_HANDLE handle, bool isCombined) -@@ -1530,24 +1703,32 @@ Slot::addKeyObject(list& 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& - 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 objInfoList; - std::list::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 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& objectList, -@@ -395,6 +405,7 @@ class Slot { - const CKYBuffer *derCert, CK_OBJECT_HANDLE handle); - void addObject(list& 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 - diff --git a/coolkey.spec b/coolkey.spec index fba7441..8c62a64 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -27,7 +27,6 @@ Source: %{name}-%{version}.tar.bz2 Source1: %{name}-rpmlintrc Source2: baselibs.conf # Patches imported from Fedora: -#Patch1: coolkey-cache-dir-move.patch # PATCH-FIX-FEDORA coolkey-gcc43.patch bnc661643 sbrabec@suse.cz -- Fix for gcc-4.3. Patch2: coolkey-gcc43.patch # PATCH-FEATURE-FEDORA coolkey-latest.patch bnc661643 sbrabec@suse.cz -- The head branch patch. @@ -42,16 +41,6 @@ Patch6: coolkey-cac.patch Patch7: coolkey-cac-1.patch # PATCH-FIX-FEDORA coolkey-pcsc-lite-fix.patch bnc661643 sbrabec@suse.cz -- Port to the latest pcsc-lite. Patch8: coolkey-pcsc-lite-fix.patch -Patch9: coolkey-fix-token-removal-failure.patch -Patch10: coolkey-piv-ecc-el7.patch -Patch20: coolkey-1.1.0-noapplet.patch -Patch21: coolkey-1.1.0-fix-spurious-event.patch -Patch22: coolkey-1.1.0-p15.patch -Patch23: coolkey-1.1.0-p15-coverity.patch -Patch24: coolkey-1.1.0-more-keys.patch -Patch25: coolkey-1.1.0-fail-on-bad-mechanisms.patch -Patch26: coolkey-1.1.0-max-cpu-bug.patch -Patch27: coolkey-1.1.0-rhel7-alt-cac.patch # SUSE specific patches: # PATCH-FEATURE-SLES coolkey-1.1.0-evoandooo.patch jberkman@novell.com -- Teach pk11install about evolution and openoffice. Patch53: coolkey-1.1.0-evoandooo.patch @@ -59,7 +48,6 @@ Patch53: coolkey-1.1.0-evoandooo.patch Patch54: coolkey-cache-dir-move.patch # PATCH-FIX-UPSTREAM coolkey-null.patch redhat356971 sbrabec@suse.cz -- Fix invalid NULL declaration. Patch55: coolkey-null.patch -#Patch100: typo.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: gcc-c++ BuildRequires: libtool @@ -121,7 +109,6 @@ card and USB Fob form factors. %prep %setup -q -#%patch1 %patch2 %patch3 %patch4 @@ -129,20 +116,9 @@ card and USB Fob form factors. %patch6 %patch7 %patch8 -%patch9 -p1 -%patch10 -%patch20 -%patch21 -%patch22 -%patch23 -%patch24 -%patch25 -%patch26 -%patch27 %patch53 -p1 %patch54 -#%patch55 -#%patch100 -p1 +%patch55 %build autoreconf -f -i diff --git a/typo.patch b/typo.patch deleted file mode 100644 index 63c2ab7..0000000 --- a/typo.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: coolkey-1.3.0/src/coolkey/slot.cpp -=================================================================== ---- coolkey-1.3.0.orig/src/coolkey/slot.cpp -+++ coolkey-1.3.0/src/coolkey/slot.cpp -@@ -4492,7 +4492,7 @@ Slot::cryptRSA(SessionHandleSuffix suffi - throw PKCS11Exception(CKR_DATA_LEN_RANGE); - } - if (ulInputLen > maxSize) { -- ulInputlen = maxSize; -+ ulInputLen = maxSize; - } - // OK, this is gross. We should get our own C++ like buffer - // management at this point. This code has nothing to do with