From c7c94ab052664a2d9b4733d86ff4e80e4ffefd9cad27d1dda96e0c484b8e15e2 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 12 Jul 2017 19:16:46 +0000 Subject: [PATCH 1/6] Add all Centos 7 patches. OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=14 --- coolkey-1.1.0-fail-on-bad-mechanisms.patch | 109 + coolkey-1.1.0-fix-spurious-event.patch | 11 + coolkey-1.1.0-max-cpu-bug.patch | 12 + coolkey-1.1.0-more-keys.patch | 61 + coolkey-1.1.0-noapplet.patch | 18 + coolkey-1.1.0-p15-coverity.patch | 210 + coolkey-1.1.0-p15.patch | 4379 ++++++++++++++++++ coolkey-1.1.0-rhel7-alt-cac.patch | 858 ++++ coolkey-1.3.0.tar.gz | 3 + coolkey-fix-token-removal-failure.patch | 86 + coolkey-piv-ecc-el7.patch | 4792 ++++++++++++++++++++ coolkey.spec | 28 +- typo.patch | 13 + 13 files changed, 10578 insertions(+), 2 deletions(-) create mode 100644 coolkey-1.1.0-fail-on-bad-mechanisms.patch create mode 100644 coolkey-1.1.0-fix-spurious-event.patch create mode 100644 coolkey-1.1.0-max-cpu-bug.patch create mode 100644 coolkey-1.1.0-more-keys.patch create mode 100644 coolkey-1.1.0-noapplet.patch create mode 100644 coolkey-1.1.0-p15-coverity.patch create mode 100644 coolkey-1.1.0-p15.patch create mode 100644 coolkey-1.1.0-rhel7-alt-cac.patch create mode 100644 coolkey-1.3.0.tar.gz create mode 100644 coolkey-fix-token-removal-failure.patch create mode 100644 coolkey-piv-ecc-el7.patch create mode 100644 typo.patch diff --git a/coolkey-1.1.0-fail-on-bad-mechanisms.patch b/coolkey-1.1.0-fail-on-bad-mechanisms.patch new file mode 100644 index 0000000..1a113c6 --- /dev/null +++ b/coolkey-1.1.0-fail-on-bad-mechanisms.patch @@ -0,0 +1,109 @@ +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 new file mode 100644 index 0000000..6e4114c --- /dev/null +++ b/coolkey-1.1.0-fix-spurious-event.patch @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..cf90313 --- /dev/null +++ b/coolkey-1.1.0-max-cpu-bug.patch @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..94dceb9 --- /dev/null +++ b/coolkey-1.1.0-more-keys.patch @@ -0,0 +1,61 @@ +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 new file mode 100644 index 0000000..45f2760 --- /dev/null +++ b/coolkey-1.1.0-noapplet.patch @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..4ae1092 --- /dev/null +++ b/coolkey-1.1.0-p15-coverity.patch @@ -0,0 +1,210 @@ +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 new file mode 100644 index 0000000..75724ea --- /dev/null +++ b/coolkey-1.1.0-p15.patch @@ -0,0 +1,4379 @@ +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 new file mode 100644 index 0000000..d43a7eb --- /dev/null +++ b/coolkey-1.1.0-rhel7-alt-cac.patch @@ -0,0 +1,858 @@ +diff -up ./src/coolkey/coolkey.cpp.alt-cac ./src/coolkey/coolkey.cpp +--- ./src/coolkey/coolkey.cpp.alt-cac 2016-12-01 15:37:49.106167768 -0800 ++++ ./src/coolkey/coolkey.cpp 2016-12-01 15:37:49.113167892 -0800 +@@ -80,9 +80,16 @@ ecMechanismList[] = { + {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, + {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } + }; ++static const MechInfo ++allMechanismList[] = { ++ {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }, ++ {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, ++ {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } ++}; + + unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo); + unsigned int numECMechanisms = sizeof(ecMechanismList)/sizeof(MechInfo); ++unsigned int numAllMechanisms = sizeof(allMechanismList)/sizeof(MechInfo); + + /* ------------------------------------------------------------ */ + +@@ -382,13 +389,22 @@ C_GetMechanismList(CK_SLOT_ID slotID, CK + return CKR_TOKEN_NOT_PRESENT; + } + +- if ( slot->getIsECC()) { ++ switch (slot->getAlgs()) { ++ case ALG_ECC|ALG_RSA: ++ mechanismList = allMechanismList; ++ numMechanisms = numAllMechanisms; ++ break; ++ case ALG_ECC: + mechanismList = ecMechanismList; + numMechanisms = numECMechanisms; +- } else { ++ break; ++ case ALG_NONE: ++ case ALG_RSA: ++ default: + mechanismList = rsaMechanismList; + numMechanisms = numRSAMechanisms; +- } ++ break; ++ } + + if( pMechanismList != NULL ) { + if( *pulCount < numMechanisms ) { +@@ -438,13 +454,22 @@ C_GetMechanismInfo(CK_SLOT_ID slotID, CK + return CKR_TOKEN_NOT_PRESENT; + } + +- if ( slot->getIsECC()) { ++ switch (slot->getAlgs()) { ++ case ALG_ECC|ALG_RSA: ++ mechanismList = allMechanismList; ++ numMechanisms = numAllMechanisms; ++ break; ++ case ALG_ECC: + mechanismList = ecMechanismList; + numMechanisms = numECMechanisms; +- } else { ++ break; ++ case ALG_NONE: ++ case ALG_RSA: ++ default: + mechanismList = rsaMechanismList; + numMechanisms = numRSAMechanisms; +- } ++ break; ++ } + + for(unsigned int i=0; i < numMechanisms; ++i ) { + if( mechanismList[i].mech == type ) { +diff -up ./src/coolkey/object.cpp.alt-cac ./src/coolkey/object.cpp +--- ./src/coolkey/object.cpp.alt-cac 2016-12-01 15:37:49.097167608 -0800 ++++ ./src/coolkey/object.cpp 2016-12-01 15:37:49.114167910 -0800 +@@ -1232,7 +1232,7 @@ Reader::Reader(unsigned long muscleObjID + } + + +-CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : ++CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : + PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16, + instance | 0x400) + { +@@ -1242,7 +1242,9 @@ CACPrivKey::CACPrivKey(CKYByte instance, + + /* So we know what the key is supposed to be used for based on + * the instance */ +- if (instance == 2) { ++ /* instance 2 is usually a decryption cert. >2 are usually old decryption ++ * certs */ ++ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { + decrypt = TRUE; + } + +@@ -1305,8 +1307,8 @@ CACPrivKey::CACPrivKey(CKYByte instance, + CKYBuffer_FreeData(¶m2); + } + +-CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : +- PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16, ++CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : ++ PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16, + instance | 0x500) + { + CKYBuffer id; +@@ -1315,7 +1317,7 @@ CACPubKey::CACPubKey(CKYByte instance, c + + /* So we know what the key is supposed to be used for based on + * the instance */ +- if (instance == 2) { ++ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { + encrypt = TRUE; + } + +@@ -1359,6 +1361,9 @@ CACPubKey::CACPubKey(CKYByte instance, c + setAttribute(CKA_EC_POINT, ¶m1); + setAttribute(CKA_EC_PARAMS, ¶m2); + setAttributeULong(CKA_KEY_TYPE, CKK_EC); ++ setAttributeBool(CKA_VERIFY_RECOVER, FALSE); ++ setAttributeBool(CKA_ENCRYPT, FALSE); ++ setAttributeBool(CKA_DERIVE, encrypt); + break; + default: + break; +@@ -1376,6 +1381,26 @@ static const char *CAC_Label[] = { + "CAC ID Certificate", + "CAC Email Signature Certificate", + "CAC Email Encryption Certificate", ++ "CAC Cert 3", ++ "CAC Cert 4", ++ "CAC Cert 5", ++ "CAC Cert 6", ++ "CAC Cert 7", ++ "CAC Cert 8", ++ "CAC Cert 9", ++}; ++ ++static const char *PIV_Label[] = { ++ "PIV ID Certificate", ++ "PIV Email Signature Certificate", ++ "PIV Email Encryption Certificate", ++ "PIV Card Authentication Certificate", ++ "PIV Cert 4", ++ "PIV Cert 5", ++ "PIV Cert 6", ++ "PIV Cert 7", ++ "PIV Cert 8", ++ "PIV Cert 9", + }; + + static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 }; +@@ -1454,7 +1479,7 @@ GetUserName(const CKYBuffer *dn) + return string; + } + +-CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : ++CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : + PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, + instance | 0x600) + { +@@ -1471,7 +1496,7 @@ CACCert::CACCert(CKYByte instance, const + setAttribute(CKA_ID, &id); + CKYBuffer_FreeData(&id); + setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509); +- setAttribute(CKA_LABEL, CAC_Label[instance]); ++ setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]); + + CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial); + CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject); +diff -up ./src/coolkey/object.h.alt-cac ./src/coolkey/object.h +--- ./src/coolkey/object.h.alt-cac 2016-12-01 15:37:49.087167430 -0800 ++++ ./src/coolkey/object.h 2016-12-01 15:37:49.115167928 -0800 +@@ -219,17 +219,17 @@ class Cert : public PKCS11Object { + + class CACPrivKey : public PKCS11Object { + public: +- CACPrivKey(CKYByte instance, const PKCS11Object &cert); ++ CACPrivKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); + }; + + class CACPubKey : public PKCS11Object { + public: +- CACPubKey(CKYByte instance, const PKCS11Object &cert); ++ CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); + }; + + class CACCert : public PKCS11Object { + public: +- CACCert(CKYByte instance, const CKYBuffer *derCert); ++ CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV); + }; + + typedef enum { PK15StateInit, PK15StateNeedObject, +diff -up ./src/coolkey/slot.cpp.alt-cac ./src/coolkey/slot.cpp +--- ./src/coolkey/slot.cpp.alt-cac 2016-12-01 15:37:49.110167839 -0800 ++++ ./src/coolkey/slot.cpp 2016-12-01 15:57:37.307994776 -0800 +@@ -415,8 +415,9 @@ Slot::Slot(const char *readerName_, Log + slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), + isVersion1Key(false), needLogin(false), fullTokenName(false), + mCoolkey(false), mOldCAC(false), mCACLocalLogin(false), +- pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0), +- p15tokenInfoAddr(0), p15Instance(0), ++ pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS), ++ algs(ALG_NONE), p15aid(0), p15odfAddr(0), p15tokenInfoAddr(0), ++ p15Instance(0), + #ifdef USE_SHMEM + shmem(readerName_), + #endif +@@ -776,6 +777,7 @@ Slot::connectToToken() + state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; + isVersion1Key = 0; + needLogin = true; ++ maxCacCerts = MAX_CERT_SLOTS; + mCoolkey = 0; + mOldCAC = 0; + mCACLocalLogin = getPIVLoginType(); +@@ -927,8 +929,12 @@ Slot::getCACAid() + } + /* yes, fill in the old applets */ + mOldCAC = true; ++ maxCacCerts = 1; + for (i=1; i< MAX_CERT_SLOTS; i++) { +- CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); ++ status = CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); ++ if (status == CKYSUCCESS) { ++ maxCacCerts = i+1; ++ } + } + return CKYSUCCESS; + } +@@ -986,6 +992,7 @@ Slot::getCACAid() + if (certSlot == 0) { + status = CKYAPDUFAIL; /* probably neeed a beter error code */ + } ++ maxCacCerts = certSlot; + + done: + CKYBuffer_FreeData(&tBuf); +@@ -2168,12 +2175,11 @@ Slot::addKeyObject(list& o + } + keyObj.completeKey(*iter); + +- /* For now this is how we determine what type of key. +- Also for now, allow only one or the other */ ++ /* use key object to determine what algorithms we support */ + if ( keyObj.getKeyType() == PKCS11Object::ecc) { +- mECC = true; ++ algs = (SlotAlgs) (algs | ALG_ECC); + } else { +- mECC = false; ++ algs = (SlotAlgs) (algs | ALG_RSA); + } + + } +@@ -2205,7 +2211,7 @@ Slot::addCertObject(list& + void + Slot::unloadObjects() + { +- mECC = false; ++ algs = ALG_NONE; + tokenObjects.clear(); + free(personName); + personName = NULL; +@@ -2269,29 +2275,42 @@ Slot::unloadObjects() + // Shared memory segments are fixed size (equal to the object memory size of + // the token). + // ++// ++// ++ ++struct SlotDataPair { ++ unsigned long dataOffset; ++ unsigned long dataSize; ++}; + + struct SlotSegmentHeader { + unsigned short version; + unsigned short headerSize; + unsigned char valid; +- unsigned char reserved; ++ unsigned char firstCacCert; + unsigned char cuid[10]; +- unsigned short reserved2; ++ ++ unsigned short reserved; + unsigned short dataVersion; + unsigned short dataHeaderOffset; + unsigned short dataOffset; + unsigned long dataHeaderSize; + unsigned long dataSize; +- unsigned long cert2Offset; +- unsigned long cert2Size; ++ unsigned long nextDataOffset; ++ SlotDataPair cacCerts[MAX_CERT_SLOTS]; + }; + ++const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */ ++const unsigned short CAC_DATA_VERSION=2; ++ ++ + #define MAX_OBJECT_STORE_SIZE 15000 + // + // previous development versions used a segment prefix of + // "coolkeypk11s" + // +-#define SEGMENT_PREFIX "coolkeypk11s" ++#define SEGMENT_PREFIX "coolkeypk11t" // update segment since the old cache was ++ // incompatible + #define CAC_FAKE_CUID "CAC Certs" + SlotMemSegment::SlotMemSegment(const char *readerName): + segmentAddr(NULL), segmentSize(0), segment(NULL) +@@ -2320,9 +2339,8 @@ SlotMemSegment::SlotMemSegment(const cha + return; + } + +- SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + if (needInit) { +- segmentHeader->valid = 0; ++ clearValid(0); + } + segmentSize = segment->getSHMemSize(); + } +@@ -2396,6 +2414,18 @@ SlotMemSegment::getDataVersion() const + return segmentHeader->dataVersion; + } + ++unsigned char ++SlotMemSegment::getFirstCacCert() const ++{ ++ if (!segment) { ++ return NOT_A_CAC; ++ } ++ ++ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; ++ ++ return segmentHeader->firstCacCert; ++} ++ + void + SlotMemSegment::setVersion(unsigned short version) + { +@@ -2419,6 +2449,18 @@ SlotMemSegment::setDataVersion(unsigned + segmentHeader->dataVersion = version; + } + ++void ++SlotMemSegment::setFirstCacCert(unsigned char firstCacCert) ++{ ++ if (!segment) { ++ return; ++ } ++ ++ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; ++ ++ segmentHeader->firstCacCert = firstCacCert; ++} ++ + bool + SlotMemSegment::isValid() const + { +@@ -2493,23 +2535,13 @@ SlotMemSegment::readCACCert(CKYBuffer *o + int size; + CKYByte *data; + +- switch (instance) { +- case 0: +- data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; +- size = segmentHeader->dataHeaderSize; +- break; +- case 1: +- data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; +- size = segmentHeader->dataSize; +- break; +- case 2: +- data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; +- size = segmentHeader->cert2Size; +- break; +- default: ++ if (instance >= MAX_CERT_SLOTS) { + CKYBuffer_Resize(objData, 0); + return; + } ++ data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance] ++ .dataOffset]; ++ size = segmentHeader->cacCerts[instance].dataSize; + CKYBuffer_Replace(objData, 0, data, size); + } + +@@ -2523,30 +2555,20 @@ SlotMemSegment::writeCACCert(const CKYBu + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + int size = CKYBuffer_Size(data); + CKYByte *shmData; +- switch (instance) { +- case 0: +- segmentHeader->headerSize = sizeof *segmentHeader; +- segmentHeader->dataHeaderOffset = sizeof *segmentHeader; +- segmentHeader->dataHeaderSize = size; +- segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size; +- segmentHeader->dataSize = 0; +- segmentHeader->cert2Offset = segmentHeader->dataOffset; +- segmentHeader->cert2Size = 0; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; +- break; +- case 1: +- segmentHeader->dataSize = size; +- segmentHeader->cert2Offset = segmentHeader->dataOffset + size; +- segmentHeader->cert2Size = 0; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; +- break; +- case 2: +- segmentHeader->cert2Size = size; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; +- break; +- default: ++ ++ if (instance >= MAX_CERT_SLOTS) { + return; + } ++ ++ if (segmentHeader->firstCacCert == NOT_A_CAC) { ++ segmentHeader->firstCacCert = instance; ++ } ++ unsigned long dataOffset = segmentHeader->nextDataOffset; ++ segmentHeader->cacCerts[instance].dataOffset = dataOffset; ++ segmentHeader->nextDataOffset += size; ++ segmentHeader->cacCerts[instance].dataSize = size; ++ shmData = (CKYByte *) &segmentAddr[dataOffset]; ++ + memcpy(shmData, CKYBuffer_Data(data), size); + } + +@@ -2558,15 +2580,18 @@ SlotMemSegment::clearValid(CKYByte insta + return; + } + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; +- switch (instance) { +- case 0: +- segmentHeader->headerSize = 0; +- segmentHeader->dataHeaderSize = 0; +- /* fall through */ +- case 1: +- segmentHeader->dataSize = 0; ++ ++ segmentHeader->headerSize = sizeof *segmentHeader; ++ segmentHeader->dataHeaderOffset = sizeof *segmentHeader; ++ segmentHeader->dataHeaderSize = 0; ++ segmentHeader->dataSize = 0; ++ for (int i=0; i < MAX_CERT_SLOTS; i++) { ++ segmentHeader->cacCerts[i].dataSize = 0; + } ++ segmentHeader->dataOffset = sizeof *segmentHeader; ++ segmentHeader->nextDataOffset = sizeof *segmentHeader; + segmentHeader->valid = 0; ++ segmentHeader->firstCacCert = NOT_A_CAC; + } + + void +@@ -2882,8 +2907,7 @@ berProcess(CKYBuffer *buf, int matchTag, + + + CKYStatus +-Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, +- bool throwException) ++Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize) + { + CKYStatus status; + CKYISOStatus apduRC; +@@ -2897,9 +2921,6 @@ Slot::readCACCertificateFirst(CKYBuffer + CKYBuffer_InitEmpty(&certInfo); + CKYBuffer_Resize(cert, 0); + status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC); +- if (throwException && (status != CKYSUCCESS)) { +- handleConnectionError(); +- } + /* actually, on success, we need to parse the certificate and find the + * propper tag */ + if (status == CKYSUCCESS) { +@@ -2940,10 +2961,10 @@ Slot::readCACCertificateFirst(CKYBuffer + if (mOldCAC) { + /* get the first 100 bytes of the cert */ + status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); +- if (throwException && (status != CKYSUCCESS)) { +- handleConnectionError(); ++ if (status == CKYSUCCESS) { ++ return status; + } +- return status; ++ /* try to use CACApplet_ReadFile before we give up */ + } + + CKYBuffer tBuf; +@@ -2959,11 +2980,11 @@ Slot::readCACCertificateFirst(CKYBuffer + + /* handle the new CAC card read */ + /* read the TLV */ +- status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); ++ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, &apduRC); + if (status != CKYSUCCESS) { + goto done; + } +- status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); ++ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, &apduRC); + if (status != CKYSUCCESS) { + goto done; + } +@@ -3199,14 +3220,12 @@ Slot::loadCACCert(CKYByte instance) + CKYStatus status = CKYSUCCESS; + CKYBuffer cert; + CKYBuffer rawCert; +- CKYBuffer shmCert; + CKYSize nextSize; + + OSTime time = OSTimeNow(); + + CKYBuffer_InitEmpty(&cert); + CKYBuffer_InitEmpty(&rawCert); +- CKYBuffer_InitEmpty(&shmCert); + + // + // not all CAC cards have all the PKI instances +@@ -3215,78 +3234,24 @@ Slot::loadCACCert(CKYByte instance) + try { + selectCACApplet(instance, false); + } catch(PKCS11Exception& e) { +- // all CAC's must have instance '0', throw the error it +- // they don't. +- if (instance == 0) throw e; +- // If the CAC doesn't have instance '2', and we were updating +- // the shared memory, set it to valid now. +- if ((instance == 2) && !shmem.isValid()) { +- shmem.setValid(); +- } + return; + } + + log->log("CAC Cert %d: select CAC applet: %d ms\n", + instance, OSTimeNow() - time); + +- if (instance == 0) { +- readCACCertificateFirst(&rawCert, &nextSize, true); +- +- if(CKYBuffer_Size(&rawCert) <= 1) { +- handleConnectionError(); +- } +- log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", +- instance, OSTimeNow() - time); +- } +- +- unsigned short dataVersion = 1; +- CKYBool needRead = 1; +- + /* see if it matches the shared memory */ +- if (shmem.isValid() && shmem.getDataVersion() == dataVersion) { +- shmem.readCACCert(&shmCert, instance); +- CKYSize certSize = CKYBuffer_Size(&rawCert); +- CKYSize shmCertSize = CKYBuffer_Size(&shmCert); +- const CKYByte *shmData = CKYBuffer_Data(&shmCert); +- +- if (instance != 0) { +- needRead = 0; +- } +- +- if (shmCertSize >= certSize) { +- if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { +- /* yes it does, no need to read the rest of the cert, use +- * the cache */ +- CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize); +- needRead = 0; +- } +- } +- if (!needRead && (shmCertSize == 0)) { ++ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION) { ++ shmem.readCACCert(&rawCert, instance); ++ if (CKYBuffer_Size(&rawCert) == 0) { + /* no cert of this type, just return */ + return; + } +- } +- CKYBuffer_FreeData(&shmCert); +- +- if (needRead) { +- /* it doesn't, read the new cert and update the cache */ +- if (instance == 0) { +- shmem.clearValid(0); +- shmem.setVersion(SHMEM_VERSION); +- shmem.setDataVersion(dataVersion); +- } else { +- status = readCACCertificateFirst(&rawCert, &nextSize, false); +- +- if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { +- /* CAC only requires the Certificate in pki '0' */ +- /* if pki '1' or '2' are empty, treat it as a non-fatal error*/ +- if (instance == 2) { +- /* we've attempted to read all the certs, shared memory +- * is now valid */ +- shmem.setValid(); +- } +- return; +- } ++ } else { ++ status = readCACCertificateFirst(&rawCert, &nextSize); ++ if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { ++ /*this cert doesn't exist, go to the next one */ ++ return; + } + + if (nextSize) { +@@ -3298,9 +3263,6 @@ Slot::loadCACCert(CKYByte instance) + handleConnectionError(); + } + shmem.writeCACCert(&rawCert, instance); +- if (instance == 2) { +- shmem.setValid(); +- } + } + + +@@ -3368,14 +3330,17 @@ Slot::loadCACCert(CKYByte instance) + log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n", + instance, OSTimeNow() - time); + +- CACCert certObj(instance, &cert); +- CACPrivKey privKey(instance, certObj); +- CACPubKey pubKey(instance, certObj); ++ bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD); ++ CACCert certObj(instance, &cert, isPIV); ++ CACPrivKey privKey(instance, certObj, isPIV); ++ CACPubKey pubKey(instance, certObj, isPIV); + tokenObjects.push_back(privKey); + tokenObjects.push_back(pubKey); + tokenObjects.push_back(certObj); + if ( pubKey.getKeyType() == PKCS11Object::ecc) { +- mECC = 1; ++ algs = (SlotAlgs) (algs | ALG_ECC); ++ } else { ++ algs = (SlotAlgs) (algs | ALG_RSA); + } + + if (personName == NULL) { +@@ -3388,6 +3353,94 @@ Slot::loadCACCert(CKYByte instance) + } + + void ++Slot::initCACShMem(void) ++{ ++ bool failed = false; ++ ++ unsigned char firstCert = shmem.getFirstCacCert(); ++ ++ log->log("init CACShMem: \n"); ++ /* check to make sure the shared memory is initialized with a CAC card */ ++ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION ++ && firstCert != NOT_A_CAC) { ++ CKYBuffer rawCert; ++ CKYBuffer shmCert; ++ CKYSize nextSize; ++ ++ log->log("init CACShMem: valid CAC cache found firstCert = %d\n", ++ firstCert); ++ CKYBuffer_InitEmpty(&rawCert); ++ CKYBuffer_InitEmpty(&shmCert); ++ ++ ++ /* yes, see if it's this cac card by comparing the first cert ++ * in the chain */ ++ ++ /* see if the first cert is in the expected slot */ ++ try { ++ selectCACApplet(firstCert, false); ++ } catch(PKCS11Exception& e) { ++ failed = true; ++ log->log("init CACShMem: applet select failed firstCert = %d\n", ++ firstCert); ++ } ++ if (!failed) { ++ CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize); ++ if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) { ++ failed = true; ++ log->log("init CACShMem: read Cert failed firstCert = %d\n", ++ firstCert); ++ } ++ } ++ if (!failed) { ++ shmem.readCACCert(&shmCert, firstCert); ++ CKYSize certSize = CKYBuffer_Size(&rawCert); ++ CKYSize shmCertSize = CKYBuffer_Size(&shmCert); ++ const CKYByte *shmData = CKYBuffer_Data(&shmCert); ++ ++ if (shmCertSize >= certSize) { ++ if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { ++ /* this card is cached, go on and use the cache */ ++ log->log("init CACShMem: entries match, using cache\n"); ++ CKYBuffer_FreeData(&rawCert); ++ CKYBuffer_FreeData(&shmCert); ++ return; ++ } ++ } ++ log->log("init CACShMem: no entry match certSize=%d" ++ " shmCertSize=%d\n",certSize, shmCertSize); ++ } ++ CKYBuffer_FreeData(&rawCert); ++ CKYBuffer_FreeData(&shmCert); ++ } ++ ++ log->log("init CACShMem: starting new cache valid=%d version=%d " ++ " firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(), ++ firstCert); ++ /* cache is either invalid or for another card, start initializing it */ ++ shmem.clearValid(0); ++ shmem.setVersion(SHMEM_VERSION); ++ shmem.setDataVersion(CAC_DATA_VERSION); ++} ++ ++void ++Slot::verifyCACShMem(void) ++{ ++ /* if the memory is valid, then nothing to do */ ++ if (shmem.isValid()) { ++ return; ++ } ++ /* if we didn't find any cert fail */ ++ if (shmem.getFirstCacCert() == NOT_A_CAC) { ++ shmem.clearValid(0); ++ disconnect(); ++ throw PKCS11Exception(CKR_DEVICE_REMOVED); ++ } ++ /* we're all set, let others see our results */ ++ shmem.setValid(); ++} ++ ++void + Slot::loadObjects() + { + // throw away all token objects! +@@ -3406,9 +3459,11 @@ Slot::loadObjects() + std::list::iterator iter; + + if (state & GOV_CARD) { +- loadCACCert(0); +- loadCACCert(1); +- loadCACCert(2); ++ initCACShMem(); ++ for (int i=0; i < maxCacCerts; i++) { ++ loadCACCert(i); ++ } ++ verifyCACShMem(); + status = trans.end(); + loadReaderObject(); + return; +@@ -4720,10 +4775,6 @@ Slot::performECCSignature(CKYBuffer *out + CKYStatus status = trans.begin(conn); + if( status != CKYSUCCESS ) handleConnectionError(); + +- if (!mECC) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } +- + CKYISOStatus result; + bool loginAttempted = false; + +@@ -4790,9 +4841,6 @@ Slot::performRSAOp(CKYBuffer *output, co + unsigned int keySize, const PKCS11Object *key, + CKYByte direction) + { +- if ( mECC ) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } + + // + // establish a transaction +@@ -5145,10 +5193,6 @@ Slot::performECCKeyAgreement(CK_MECHANIS + CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, + const PKCS11Object *key, unsigned int keySize) + { +- if (!mECC) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } +- + Transaction trans; + CKYStatus status = trans.begin(conn); + if( status != CKYSUCCESS ) handleConnectionError(); +diff -up ./src/coolkey/slot.h.alt-cac ./src/coolkey/slot.h +--- ./src/coolkey/slot.h.alt-cac 2016-12-01 15:37:49.104167732 -0800 ++++ ./src/coolkey/slot.h 2016-12-01 15:37:49.117167964 -0800 +@@ -79,9 +79,11 @@ public: + bool CUIDIsEqual(const CKYBuffer *cuid) const; + unsigned short getVersion() const; + unsigned short getDataVersion() const; ++ unsigned char getFirstCacCert() const; + void setCUID(const CKYBuffer *cuid); + void setVersion(unsigned short version); + void setDataVersion(unsigned short version); ++ void setFirstCacCert(unsigned char firstCacCert); + bool isValid() const; + int size() const; + const unsigned char *getCUID() const; +@@ -90,6 +92,7 @@ public: + void setSize(int size); + void readData(CKYBuffer *data) const; + void writeData(const CKYBuffer *data); ++ void initCACHeaders(void); + void readCACCert(CKYBuffer *data, CKYByte instance) const; + void writeCACCert(const CKYBuffer *data, CKYByte instance); + void clearValid(CKYByte instance); +@@ -294,7 +297,13 @@ class CryptParams { + const CKYBuffer *paddedOutput) const = 0; + }; + +-#define MAX_CERT_SLOTS 3 ++#define MAX_CERT_SLOTS 10 ++typedef enum { ++ ALG_NONE= 0x0, ++ ALG_ECC = 0x1, ++ ALG_RSA = 0x2 ++} SlotAlgs; ++ + #define MAX_AUTH_USERS 3 + class Slot { + +@@ -349,7 +358,8 @@ class Slot { + bool mCACLocalLogin; + int pivContainer; + int pivKey; +- bool mECC; ++ int maxCacCerts; ++ SlotAlgs algs; + unsigned short p15aid; + unsigned short p15odfAddr; + unsigned short p15tokenInfoAddr; +@@ -424,8 +434,7 @@ class Slot { + list fetchSeparateObjects(); + + CKYStatus getCACAid(); +- CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, +- bool throwException); ++ CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize); + CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); + + CKYStatus getP15Params(); +@@ -485,6 +494,8 @@ class Slot { + void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu); + + CKYByte objectToKeyNum(const PKCS11Object *key); ++ void initCACShMem(void); ++ void verifyCACShMem(void); + Slot(const Slot &cpy) + #ifdef USE_SHMEM + : shmem(readerName) +@@ -580,7 +591,7 @@ class Slot { + CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params); + +- bool getIsECC() { return mECC; } ++ SlotAlgs getAlgs() { return algs; } + }; + + class SlotList { diff --git a/coolkey-1.3.0.tar.gz b/coolkey-1.3.0.tar.gz new file mode 100644 index 0000000..a82c44a --- /dev/null +++ b/coolkey-1.3.0.tar.gz @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..5faecb5 --- /dev/null +++ b/coolkey-fix-token-removal-failure.patch @@ -0,0 +1,86 @@ +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 new file mode 100644 index 0000000..b47b80c --- /dev/null +++ b/coolkey-piv-ecc-el7.patch @@ -0,0 +1,4792 @@ +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 f649625..fba7441 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -1,7 +1,7 @@ # # spec file for package coolkey # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -27,6 +27,7 @@ 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. @@ -41,6 +42,16 @@ 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 @@ -48,6 +59,7 @@ 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 @@ -109,6 +121,7 @@ card and USB Fob form factors. %prep %setup -q +#%patch1 %patch2 %patch3 %patch4 @@ -116,9 +129,20 @@ card and USB Fob form factors. %patch6 %patch7 %patch8 +%patch9 -p1 +%patch10 +%patch20 +%patch21 +%patch22 +%patch23 +%patch24 +%patch25 +%patch26 +%patch27 %patch53 -p1 %patch54 -%patch55 +#%patch55 +#%patch100 -p1 %build autoreconf -f -i diff --git a/typo.patch b/typo.patch new file mode 100644 index 0000000..63c2ab7 --- /dev/null +++ b/typo.patch @@ -0,0 +1,13 @@ +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 From 9132e89fdf4ec3002231f2cdc13ab21217ccbad33bfa3fb310bd08a4a1033865 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 12 Jul 2017 19:24:05 +0000 Subject: [PATCH 2/6] Revert experimental changes submitted by mistake. OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=15 --- coolkey-1.1.0-fail-on-bad-mechanisms.patch | 109 - coolkey-1.1.0-fix-spurious-event.patch | 11 - coolkey-1.1.0-max-cpu-bug.patch | 12 - coolkey-1.1.0-more-keys.patch | 61 - coolkey-1.1.0-noapplet.patch | 18 - coolkey-1.1.0-p15-coverity.patch | 210 - coolkey-1.1.0-p15.patch | 4379 ------------------ coolkey-1.1.0-rhel7-alt-cac.patch | 858 ---- coolkey-1.3.0.tar.gz | 3 - coolkey-fix-token-removal-failure.patch | 86 - coolkey-piv-ecc-el7.patch | 4792 -------------------- coolkey.spec | 26 +- typo.patch | 13 - 13 files changed, 1 insertion(+), 10577 deletions(-) delete mode 100644 coolkey-1.1.0-fail-on-bad-mechanisms.patch delete mode 100644 coolkey-1.1.0-fix-spurious-event.patch delete mode 100644 coolkey-1.1.0-max-cpu-bug.patch delete mode 100644 coolkey-1.1.0-more-keys.patch delete mode 100644 coolkey-1.1.0-noapplet.patch delete mode 100644 coolkey-1.1.0-p15-coverity.patch delete mode 100644 coolkey-1.1.0-p15.patch delete mode 100644 coolkey-1.1.0-rhel7-alt-cac.patch delete mode 100644 coolkey-1.3.0.tar.gz delete mode 100644 coolkey-fix-token-removal-failure.patch delete mode 100644 coolkey-piv-ecc-el7.patch delete mode 100644 typo.patch 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 From 2ca229c8ce367812f074f81d6c29338e0b6244a9b1c46cd187a16a4b745c11d4 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 12 Jul 2017 19:25:23 +0000 Subject: [PATCH 3/6] Finish the revert. OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=16 --- coolkey.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coolkey.spec b/coolkey.spec index 8c62a64..f649625 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -1,7 +1,7 @@ # # spec file for package coolkey # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed From 7fbf4fb2e0ef56a132fa80a4412806832219e647c4b7fec3eee25a92809a15ec Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Fri, 21 Jul 2017 11:25:57 +0000 Subject: [PATCH 4/6] Accepting request 511246 from home:AndreasStieger:branches:security:chipcard bsc#1049213 OBS-URL: https://build.opensuse.org/request/show/511246 OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=17 --- coolkey-1.1.0-fail-on-bad-mechanisms.patch | 109 + coolkey-1.1.0-fix-spurious-event.patch | 11 + coolkey-1.1.0-max-cpu-bug.patch | 12 + coolkey-1.1.0-more-keys.patch | 61 + coolkey-1.1.0-noapplet.patch | 18 + coolkey-1.1.0-p15-coverity.patch | 210 + coolkey-1.1.0-p15.patch | 4379 ++++++++++++++++++ coolkey-1.1.0-rhel7-alt-cac.patch | 858 ++++ coolkey-1.1.0.tar.bz2 | 3 - coolkey-1.1.0.tar.gz | 3 + coolkey-fix-token-removal-failure.patch | 86 + coolkey-null.patch | 22 - coolkey-piv-ecc-el7.patch | 4792 ++++++++++++++++++++ coolkey.changes | 20 + coolkey-rpmlintrc => coolkey.rpmlintrc | 0 coolkey.spec | 44 +- 16 files changed, 10588 insertions(+), 40 deletions(-) create mode 100644 coolkey-1.1.0-fail-on-bad-mechanisms.patch create mode 100644 coolkey-1.1.0-fix-spurious-event.patch create mode 100644 coolkey-1.1.0-max-cpu-bug.patch create mode 100644 coolkey-1.1.0-more-keys.patch create mode 100644 coolkey-1.1.0-noapplet.patch create mode 100644 coolkey-1.1.0-p15-coverity.patch create mode 100644 coolkey-1.1.0-p15.patch create mode 100644 coolkey-1.1.0-rhel7-alt-cac.patch delete mode 100644 coolkey-1.1.0.tar.bz2 create mode 100644 coolkey-1.1.0.tar.gz create mode 100644 coolkey-fix-token-removal-failure.patch delete mode 100644 coolkey-null.patch create mode 100644 coolkey-piv-ecc-el7.patch rename coolkey-rpmlintrc => coolkey.rpmlintrc (100%) diff --git a/coolkey-1.1.0-fail-on-bad-mechanisms.patch b/coolkey-1.1.0-fail-on-bad-mechanisms.patch new file mode 100644 index 0000000..1a113c6 --- /dev/null +++ b/coolkey-1.1.0-fail-on-bad-mechanisms.patch @@ -0,0 +1,109 @@ +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 new file mode 100644 index 0000000..6e4114c --- /dev/null +++ b/coolkey-1.1.0-fix-spurious-event.patch @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..cf90313 --- /dev/null +++ b/coolkey-1.1.0-max-cpu-bug.patch @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..94dceb9 --- /dev/null +++ b/coolkey-1.1.0-more-keys.patch @@ -0,0 +1,61 @@ +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 new file mode 100644 index 0000000..45f2760 --- /dev/null +++ b/coolkey-1.1.0-noapplet.patch @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..4ae1092 --- /dev/null +++ b/coolkey-1.1.0-p15-coverity.patch @@ -0,0 +1,210 @@ +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 new file mode 100644 index 0000000..75724ea --- /dev/null +++ b/coolkey-1.1.0-p15.patch @@ -0,0 +1,4379 @@ +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 new file mode 100644 index 0000000..d43a7eb --- /dev/null +++ b/coolkey-1.1.0-rhel7-alt-cac.patch @@ -0,0 +1,858 @@ +diff -up ./src/coolkey/coolkey.cpp.alt-cac ./src/coolkey/coolkey.cpp +--- ./src/coolkey/coolkey.cpp.alt-cac 2016-12-01 15:37:49.106167768 -0800 ++++ ./src/coolkey/coolkey.cpp 2016-12-01 15:37:49.113167892 -0800 +@@ -80,9 +80,16 @@ ecMechanismList[] = { + {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, + {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } + }; ++static const MechInfo ++allMechanismList[] = { ++ {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }, ++ {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}}, ++ {CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} } ++}; + + unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo); + unsigned int numECMechanisms = sizeof(ecMechanismList)/sizeof(MechInfo); ++unsigned int numAllMechanisms = sizeof(allMechanismList)/sizeof(MechInfo); + + /* ------------------------------------------------------------ */ + +@@ -382,13 +389,22 @@ C_GetMechanismList(CK_SLOT_ID slotID, CK + return CKR_TOKEN_NOT_PRESENT; + } + +- if ( slot->getIsECC()) { ++ switch (slot->getAlgs()) { ++ case ALG_ECC|ALG_RSA: ++ mechanismList = allMechanismList; ++ numMechanisms = numAllMechanisms; ++ break; ++ case ALG_ECC: + mechanismList = ecMechanismList; + numMechanisms = numECMechanisms; +- } else { ++ break; ++ case ALG_NONE: ++ case ALG_RSA: ++ default: + mechanismList = rsaMechanismList; + numMechanisms = numRSAMechanisms; +- } ++ break; ++ } + + if( pMechanismList != NULL ) { + if( *pulCount < numMechanisms ) { +@@ -438,13 +454,22 @@ C_GetMechanismInfo(CK_SLOT_ID slotID, CK + return CKR_TOKEN_NOT_PRESENT; + } + +- if ( slot->getIsECC()) { ++ switch (slot->getAlgs()) { ++ case ALG_ECC|ALG_RSA: ++ mechanismList = allMechanismList; ++ numMechanisms = numAllMechanisms; ++ break; ++ case ALG_ECC: + mechanismList = ecMechanismList; + numMechanisms = numECMechanisms; +- } else { ++ break; ++ case ALG_NONE: ++ case ALG_RSA: ++ default: + mechanismList = rsaMechanismList; + numMechanisms = numRSAMechanisms; +- } ++ break; ++ } + + for(unsigned int i=0; i < numMechanisms; ++i ) { + if( mechanismList[i].mech == type ) { +diff -up ./src/coolkey/object.cpp.alt-cac ./src/coolkey/object.cpp +--- ./src/coolkey/object.cpp.alt-cac 2016-12-01 15:37:49.097167608 -0800 ++++ ./src/coolkey/object.cpp 2016-12-01 15:37:49.114167910 -0800 +@@ -1232,7 +1232,7 @@ Reader::Reader(unsigned long muscleObjID + } + + +-CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : ++CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : + PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16, + instance | 0x400) + { +@@ -1242,7 +1242,9 @@ CACPrivKey::CACPrivKey(CKYByte instance, + + /* So we know what the key is supposed to be used for based on + * the instance */ +- if (instance == 2) { ++ /* instance 2 is usually a decryption cert. >2 are usually old decryption ++ * certs */ ++ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { + decrypt = TRUE; + } + +@@ -1305,8 +1307,8 @@ CACPrivKey::CACPrivKey(CKYByte instance, + CKYBuffer_FreeData(¶m2); + } + +-CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : +- PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16, ++CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : ++ PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16, + instance | 0x500) + { + CKYBuffer id; +@@ -1315,7 +1317,7 @@ CACPubKey::CACPubKey(CKYByte instance, c + + /* So we know what the key is supposed to be used for based on + * the instance */ +- if (instance == 2) { ++ if (instance == 2 || (instance > (isPIV ? 3 : 2))) { + encrypt = TRUE; + } + +@@ -1359,6 +1361,9 @@ CACPubKey::CACPubKey(CKYByte instance, c + setAttribute(CKA_EC_POINT, ¶m1); + setAttribute(CKA_EC_PARAMS, ¶m2); + setAttributeULong(CKA_KEY_TYPE, CKK_EC); ++ setAttributeBool(CKA_VERIFY_RECOVER, FALSE); ++ setAttributeBool(CKA_ENCRYPT, FALSE); ++ setAttributeBool(CKA_DERIVE, encrypt); + break; + default: + break; +@@ -1376,6 +1381,26 @@ static const char *CAC_Label[] = { + "CAC ID Certificate", + "CAC Email Signature Certificate", + "CAC Email Encryption Certificate", ++ "CAC Cert 3", ++ "CAC Cert 4", ++ "CAC Cert 5", ++ "CAC Cert 6", ++ "CAC Cert 7", ++ "CAC Cert 8", ++ "CAC Cert 9", ++}; ++ ++static const char *PIV_Label[] = { ++ "PIV ID Certificate", ++ "PIV Email Signature Certificate", ++ "PIV Email Encryption Certificate", ++ "PIV Card Authentication Certificate", ++ "PIV Cert 4", ++ "PIV Cert 5", ++ "PIV Cert 6", ++ "PIV Cert 7", ++ "PIV Cert 8", ++ "PIV Cert 9", + }; + + static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 }; +@@ -1454,7 +1479,7 @@ GetUserName(const CKYBuffer *dn) + return string; + } + +-CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : ++CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : + PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, + instance | 0x600) + { +@@ -1471,7 +1496,7 @@ CACCert::CACCert(CKYByte instance, const + setAttribute(CKA_ID, &id); + CKYBuffer_FreeData(&id); + setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509); +- setAttribute(CKA_LABEL, CAC_Label[instance]); ++ setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]); + + CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial); + CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject); +diff -up ./src/coolkey/object.h.alt-cac ./src/coolkey/object.h +--- ./src/coolkey/object.h.alt-cac 2016-12-01 15:37:49.087167430 -0800 ++++ ./src/coolkey/object.h 2016-12-01 15:37:49.115167928 -0800 +@@ -219,17 +219,17 @@ class Cert : public PKCS11Object { + + class CACPrivKey : public PKCS11Object { + public: +- CACPrivKey(CKYByte instance, const PKCS11Object &cert); ++ CACPrivKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); + }; + + class CACPubKey : public PKCS11Object { + public: +- CACPubKey(CKYByte instance, const PKCS11Object &cert); ++ CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV); + }; + + class CACCert : public PKCS11Object { + public: +- CACCert(CKYByte instance, const CKYBuffer *derCert); ++ CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV); + }; + + typedef enum { PK15StateInit, PK15StateNeedObject, +diff -up ./src/coolkey/slot.cpp.alt-cac ./src/coolkey/slot.cpp +--- ./src/coolkey/slot.cpp.alt-cac 2016-12-01 15:37:49.110167839 -0800 ++++ ./src/coolkey/slot.cpp 2016-12-01 15:57:37.307994776 -0800 +@@ -415,8 +415,9 @@ Slot::Slot(const char *readerName_, Log + slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), + isVersion1Key(false), needLogin(false), fullTokenName(false), + mCoolkey(false), mOldCAC(false), mCACLocalLogin(false), +- pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0), +- p15tokenInfoAddr(0), p15Instance(0), ++ pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS), ++ algs(ALG_NONE), p15aid(0), p15odfAddr(0), p15tokenInfoAddr(0), ++ p15Instance(0), + #ifdef USE_SHMEM + shmem(readerName_), + #endif +@@ -776,6 +777,7 @@ Slot::connectToToken() + state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED; + isVersion1Key = 0; + needLogin = true; ++ maxCacCerts = MAX_CERT_SLOTS; + mCoolkey = 0; + mOldCAC = 0; + mCACLocalLogin = getPIVLoginType(); +@@ -927,8 +929,12 @@ Slot::getCACAid() + } + /* yes, fill in the old applets */ + mOldCAC = true; ++ maxCacCerts = 1; + for (i=1; i< MAX_CERT_SLOTS; i++) { +- CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); ++ status = CACApplet_SelectPKI(conn, &cardAID[i], i, NULL); ++ if (status == CKYSUCCESS) { ++ maxCacCerts = i+1; ++ } + } + return CKYSUCCESS; + } +@@ -986,6 +992,7 @@ Slot::getCACAid() + if (certSlot == 0) { + status = CKYAPDUFAIL; /* probably neeed a beter error code */ + } ++ maxCacCerts = certSlot; + + done: + CKYBuffer_FreeData(&tBuf); +@@ -2168,12 +2175,11 @@ Slot::addKeyObject(list& o + } + keyObj.completeKey(*iter); + +- /* For now this is how we determine what type of key. +- Also for now, allow only one or the other */ ++ /* use key object to determine what algorithms we support */ + if ( keyObj.getKeyType() == PKCS11Object::ecc) { +- mECC = true; ++ algs = (SlotAlgs) (algs | ALG_ECC); + } else { +- mECC = false; ++ algs = (SlotAlgs) (algs | ALG_RSA); + } + + } +@@ -2205,7 +2211,7 @@ Slot::addCertObject(list& + void + Slot::unloadObjects() + { +- mECC = false; ++ algs = ALG_NONE; + tokenObjects.clear(); + free(personName); + personName = NULL; +@@ -2269,29 +2275,42 @@ Slot::unloadObjects() + // Shared memory segments are fixed size (equal to the object memory size of + // the token). + // ++// ++// ++ ++struct SlotDataPair { ++ unsigned long dataOffset; ++ unsigned long dataSize; ++}; + + struct SlotSegmentHeader { + unsigned short version; + unsigned short headerSize; + unsigned char valid; +- unsigned char reserved; ++ unsigned char firstCacCert; + unsigned char cuid[10]; +- unsigned short reserved2; ++ ++ unsigned short reserved; + unsigned short dataVersion; + unsigned short dataHeaderOffset; + unsigned short dataOffset; + unsigned long dataHeaderSize; + unsigned long dataSize; +- unsigned long cert2Offset; +- unsigned long cert2Size; ++ unsigned long nextDataOffset; ++ SlotDataPair cacCerts[MAX_CERT_SLOTS]; + }; + ++const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */ ++const unsigned short CAC_DATA_VERSION=2; ++ ++ + #define MAX_OBJECT_STORE_SIZE 15000 + // + // previous development versions used a segment prefix of + // "coolkeypk11s" + // +-#define SEGMENT_PREFIX "coolkeypk11s" ++#define SEGMENT_PREFIX "coolkeypk11t" // update segment since the old cache was ++ // incompatible + #define CAC_FAKE_CUID "CAC Certs" + SlotMemSegment::SlotMemSegment(const char *readerName): + segmentAddr(NULL), segmentSize(0), segment(NULL) +@@ -2320,9 +2339,8 @@ SlotMemSegment::SlotMemSegment(const cha + return; + } + +- SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + if (needInit) { +- segmentHeader->valid = 0; ++ clearValid(0); + } + segmentSize = segment->getSHMemSize(); + } +@@ -2396,6 +2414,18 @@ SlotMemSegment::getDataVersion() const + return segmentHeader->dataVersion; + } + ++unsigned char ++SlotMemSegment::getFirstCacCert() const ++{ ++ if (!segment) { ++ return NOT_A_CAC; ++ } ++ ++ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; ++ ++ return segmentHeader->firstCacCert; ++} ++ + void + SlotMemSegment::setVersion(unsigned short version) + { +@@ -2419,6 +2449,18 @@ SlotMemSegment::setDataVersion(unsigned + segmentHeader->dataVersion = version; + } + ++void ++SlotMemSegment::setFirstCacCert(unsigned char firstCacCert) ++{ ++ if (!segment) { ++ return; ++ } ++ ++ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; ++ ++ segmentHeader->firstCacCert = firstCacCert; ++} ++ + bool + SlotMemSegment::isValid() const + { +@@ -2493,23 +2535,13 @@ SlotMemSegment::readCACCert(CKYBuffer *o + int size; + CKYByte *data; + +- switch (instance) { +- case 0: +- data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; +- size = segmentHeader->dataHeaderSize; +- break; +- case 1: +- data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; +- size = segmentHeader->dataSize; +- break; +- case 2: +- data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; +- size = segmentHeader->cert2Size; +- break; +- default: ++ if (instance >= MAX_CERT_SLOTS) { + CKYBuffer_Resize(objData, 0); + return; + } ++ data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance] ++ .dataOffset]; ++ size = segmentHeader->cacCerts[instance].dataSize; + CKYBuffer_Replace(objData, 0, data, size); + } + +@@ -2523,30 +2555,20 @@ SlotMemSegment::writeCACCert(const CKYBu + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; + int size = CKYBuffer_Size(data); + CKYByte *shmData; +- switch (instance) { +- case 0: +- segmentHeader->headerSize = sizeof *segmentHeader; +- segmentHeader->dataHeaderOffset = sizeof *segmentHeader; +- segmentHeader->dataHeaderSize = size; +- segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size; +- segmentHeader->dataSize = 0; +- segmentHeader->cert2Offset = segmentHeader->dataOffset; +- segmentHeader->cert2Size = 0; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset]; +- break; +- case 1: +- segmentHeader->dataSize = size; +- segmentHeader->cert2Offset = segmentHeader->dataOffset + size; +- segmentHeader->cert2Size = 0; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset]; +- break; +- case 2: +- segmentHeader->cert2Size = size; +- shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset]; +- break; +- default: ++ ++ if (instance >= MAX_CERT_SLOTS) { + return; + } ++ ++ if (segmentHeader->firstCacCert == NOT_A_CAC) { ++ segmentHeader->firstCacCert = instance; ++ } ++ unsigned long dataOffset = segmentHeader->nextDataOffset; ++ segmentHeader->cacCerts[instance].dataOffset = dataOffset; ++ segmentHeader->nextDataOffset += size; ++ segmentHeader->cacCerts[instance].dataSize = size; ++ shmData = (CKYByte *) &segmentAddr[dataOffset]; ++ + memcpy(shmData, CKYBuffer_Data(data), size); + } + +@@ -2558,15 +2580,18 @@ SlotMemSegment::clearValid(CKYByte insta + return; + } + SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr; +- switch (instance) { +- case 0: +- segmentHeader->headerSize = 0; +- segmentHeader->dataHeaderSize = 0; +- /* fall through */ +- case 1: +- segmentHeader->dataSize = 0; ++ ++ segmentHeader->headerSize = sizeof *segmentHeader; ++ segmentHeader->dataHeaderOffset = sizeof *segmentHeader; ++ segmentHeader->dataHeaderSize = 0; ++ segmentHeader->dataSize = 0; ++ for (int i=0; i < MAX_CERT_SLOTS; i++) { ++ segmentHeader->cacCerts[i].dataSize = 0; + } ++ segmentHeader->dataOffset = sizeof *segmentHeader; ++ segmentHeader->nextDataOffset = sizeof *segmentHeader; + segmentHeader->valid = 0; ++ segmentHeader->firstCacCert = NOT_A_CAC; + } + + void +@@ -2882,8 +2907,7 @@ berProcess(CKYBuffer *buf, int matchTag, + + + CKYStatus +-Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, +- bool throwException) ++Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize) + { + CKYStatus status; + CKYISOStatus apduRC; +@@ -2897,9 +2921,6 @@ Slot::readCACCertificateFirst(CKYBuffer + CKYBuffer_InitEmpty(&certInfo); + CKYBuffer_Resize(cert, 0); + status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC); +- if (throwException && (status != CKYSUCCESS)) { +- handleConnectionError(); +- } + /* actually, on success, we need to parse the certificate and find the + * propper tag */ + if (status == CKYSUCCESS) { +@@ -2940,10 +2961,10 @@ Slot::readCACCertificateFirst(CKYBuffer + if (mOldCAC) { + /* get the first 100 bytes of the cert */ + status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC); +- if (throwException && (status != CKYSUCCESS)) { +- handleConnectionError(); ++ if (status == CKYSUCCESS) { ++ return status; + } +- return status; ++ /* try to use CACApplet_ReadFile before we give up */ + } + + CKYBuffer tBuf; +@@ -2959,11 +2980,11 @@ Slot::readCACCertificateFirst(CKYBuffer + + /* handle the new CAC card read */ + /* read the TLV */ +- status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL); ++ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, &apduRC); + if (status != CKYSUCCESS) { + goto done; + } +- status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL); ++ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, &apduRC); + if (status != CKYSUCCESS) { + goto done; + } +@@ -3199,14 +3220,12 @@ Slot::loadCACCert(CKYByte instance) + CKYStatus status = CKYSUCCESS; + CKYBuffer cert; + CKYBuffer rawCert; +- CKYBuffer shmCert; + CKYSize nextSize; + + OSTime time = OSTimeNow(); + + CKYBuffer_InitEmpty(&cert); + CKYBuffer_InitEmpty(&rawCert); +- CKYBuffer_InitEmpty(&shmCert); + + // + // not all CAC cards have all the PKI instances +@@ -3215,78 +3234,24 @@ Slot::loadCACCert(CKYByte instance) + try { + selectCACApplet(instance, false); + } catch(PKCS11Exception& e) { +- // all CAC's must have instance '0', throw the error it +- // they don't. +- if (instance == 0) throw e; +- // If the CAC doesn't have instance '2', and we were updating +- // the shared memory, set it to valid now. +- if ((instance == 2) && !shmem.isValid()) { +- shmem.setValid(); +- } + return; + } + + log->log("CAC Cert %d: select CAC applet: %d ms\n", + instance, OSTimeNow() - time); + +- if (instance == 0) { +- readCACCertificateFirst(&rawCert, &nextSize, true); +- +- if(CKYBuffer_Size(&rawCert) <= 1) { +- handleConnectionError(); +- } +- log->log("CAC Cert %d: fetch CAC Cert: %d ms\n", +- instance, OSTimeNow() - time); +- } +- +- unsigned short dataVersion = 1; +- CKYBool needRead = 1; +- + /* see if it matches the shared memory */ +- if (shmem.isValid() && shmem.getDataVersion() == dataVersion) { +- shmem.readCACCert(&shmCert, instance); +- CKYSize certSize = CKYBuffer_Size(&rawCert); +- CKYSize shmCertSize = CKYBuffer_Size(&shmCert); +- const CKYByte *shmData = CKYBuffer_Data(&shmCert); +- +- if (instance != 0) { +- needRead = 0; +- } +- +- if (shmCertSize >= certSize) { +- if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { +- /* yes it does, no need to read the rest of the cert, use +- * the cache */ +- CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize); +- needRead = 0; +- } +- } +- if (!needRead && (shmCertSize == 0)) { ++ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION) { ++ shmem.readCACCert(&rawCert, instance); ++ if (CKYBuffer_Size(&rawCert) == 0) { + /* no cert of this type, just return */ + return; + } +- } +- CKYBuffer_FreeData(&shmCert); +- +- if (needRead) { +- /* it doesn't, read the new cert and update the cache */ +- if (instance == 0) { +- shmem.clearValid(0); +- shmem.setVersion(SHMEM_VERSION); +- shmem.setDataVersion(dataVersion); +- } else { +- status = readCACCertificateFirst(&rawCert, &nextSize, false); +- +- if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { +- /* CAC only requires the Certificate in pki '0' */ +- /* if pki '1' or '2' are empty, treat it as a non-fatal error*/ +- if (instance == 2) { +- /* we've attempted to read all the certs, shared memory +- * is now valid */ +- shmem.setValid(); +- } +- return; +- } ++ } else { ++ status = readCACCertificateFirst(&rawCert, &nextSize); ++ if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) { ++ /*this cert doesn't exist, go to the next one */ ++ return; + } + + if (nextSize) { +@@ -3298,9 +3263,6 @@ Slot::loadCACCert(CKYByte instance) + handleConnectionError(); + } + shmem.writeCACCert(&rawCert, instance); +- if (instance == 2) { +- shmem.setValid(); +- } + } + + +@@ -3368,14 +3330,17 @@ Slot::loadCACCert(CKYByte instance) + log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n", + instance, OSTimeNow() - time); + +- CACCert certObj(instance, &cert); +- CACPrivKey privKey(instance, certObj); +- CACPubKey pubKey(instance, certObj); ++ bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD); ++ CACCert certObj(instance, &cert, isPIV); ++ CACPrivKey privKey(instance, certObj, isPIV); ++ CACPubKey pubKey(instance, certObj, isPIV); + tokenObjects.push_back(privKey); + tokenObjects.push_back(pubKey); + tokenObjects.push_back(certObj); + if ( pubKey.getKeyType() == PKCS11Object::ecc) { +- mECC = 1; ++ algs = (SlotAlgs) (algs | ALG_ECC); ++ } else { ++ algs = (SlotAlgs) (algs | ALG_RSA); + } + + if (personName == NULL) { +@@ -3388,6 +3353,94 @@ Slot::loadCACCert(CKYByte instance) + } + + void ++Slot::initCACShMem(void) ++{ ++ bool failed = false; ++ ++ unsigned char firstCert = shmem.getFirstCacCert(); ++ ++ log->log("init CACShMem: \n"); ++ /* check to make sure the shared memory is initialized with a CAC card */ ++ if (shmem.isValid() && shmem.getDataVersion() == CAC_DATA_VERSION ++ && firstCert != NOT_A_CAC) { ++ CKYBuffer rawCert; ++ CKYBuffer shmCert; ++ CKYSize nextSize; ++ ++ log->log("init CACShMem: valid CAC cache found firstCert = %d\n", ++ firstCert); ++ CKYBuffer_InitEmpty(&rawCert); ++ CKYBuffer_InitEmpty(&shmCert); ++ ++ ++ /* yes, see if it's this cac card by comparing the first cert ++ * in the chain */ ++ ++ /* see if the first cert is in the expected slot */ ++ try { ++ selectCACApplet(firstCert, false); ++ } catch(PKCS11Exception& e) { ++ failed = true; ++ log->log("init CACShMem: applet select failed firstCert = %d\n", ++ firstCert); ++ } ++ if (!failed) { ++ CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize); ++ if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) { ++ failed = true; ++ log->log("init CACShMem: read Cert failed firstCert = %d\n", ++ firstCert); ++ } ++ } ++ if (!failed) { ++ shmem.readCACCert(&shmCert, firstCert); ++ CKYSize certSize = CKYBuffer_Size(&rawCert); ++ CKYSize shmCertSize = CKYBuffer_Size(&shmCert); ++ const CKYByte *shmData = CKYBuffer_Data(&shmCert); ++ ++ if (shmCertSize >= certSize) { ++ if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) { ++ /* this card is cached, go on and use the cache */ ++ log->log("init CACShMem: entries match, using cache\n"); ++ CKYBuffer_FreeData(&rawCert); ++ CKYBuffer_FreeData(&shmCert); ++ return; ++ } ++ } ++ log->log("init CACShMem: no entry match certSize=%d" ++ " shmCertSize=%d\n",certSize, shmCertSize); ++ } ++ CKYBuffer_FreeData(&rawCert); ++ CKYBuffer_FreeData(&shmCert); ++ } ++ ++ log->log("init CACShMem: starting new cache valid=%d version=%d " ++ " firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(), ++ firstCert); ++ /* cache is either invalid or for another card, start initializing it */ ++ shmem.clearValid(0); ++ shmem.setVersion(SHMEM_VERSION); ++ shmem.setDataVersion(CAC_DATA_VERSION); ++} ++ ++void ++Slot::verifyCACShMem(void) ++{ ++ /* if the memory is valid, then nothing to do */ ++ if (shmem.isValid()) { ++ return; ++ } ++ /* if we didn't find any cert fail */ ++ if (shmem.getFirstCacCert() == NOT_A_CAC) { ++ shmem.clearValid(0); ++ disconnect(); ++ throw PKCS11Exception(CKR_DEVICE_REMOVED); ++ } ++ /* we're all set, let others see our results */ ++ shmem.setValid(); ++} ++ ++void + Slot::loadObjects() + { + // throw away all token objects! +@@ -3406,9 +3459,11 @@ Slot::loadObjects() + std::list::iterator iter; + + if (state & GOV_CARD) { +- loadCACCert(0); +- loadCACCert(1); +- loadCACCert(2); ++ initCACShMem(); ++ for (int i=0; i < maxCacCerts; i++) { ++ loadCACCert(i); ++ } ++ verifyCACShMem(); + status = trans.end(); + loadReaderObject(); + return; +@@ -4720,10 +4775,6 @@ Slot::performECCSignature(CKYBuffer *out + CKYStatus status = trans.begin(conn); + if( status != CKYSUCCESS ) handleConnectionError(); + +- if (!mECC) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } +- + CKYISOStatus result; + bool loginAttempted = false; + +@@ -4790,9 +4841,6 @@ Slot::performRSAOp(CKYBuffer *output, co + unsigned int keySize, const PKCS11Object *key, + CKYByte direction) + { +- if ( mECC ) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } + + // + // establish a transaction +@@ -5145,10 +5193,6 @@ Slot::performECCKeyAgreement(CK_MECHANIS + CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, + const PKCS11Object *key, unsigned int keySize) + { +- if (!mECC) { +- throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED); +- } +- + Transaction trans; + CKYStatus status = trans.begin(conn); + if( status != CKYSUCCESS ) handleConnectionError(); +diff -up ./src/coolkey/slot.h.alt-cac ./src/coolkey/slot.h +--- ./src/coolkey/slot.h.alt-cac 2016-12-01 15:37:49.104167732 -0800 ++++ ./src/coolkey/slot.h 2016-12-01 15:37:49.117167964 -0800 +@@ -79,9 +79,11 @@ public: + bool CUIDIsEqual(const CKYBuffer *cuid) const; + unsigned short getVersion() const; + unsigned short getDataVersion() const; ++ unsigned char getFirstCacCert() const; + void setCUID(const CKYBuffer *cuid); + void setVersion(unsigned short version); + void setDataVersion(unsigned short version); ++ void setFirstCacCert(unsigned char firstCacCert); + bool isValid() const; + int size() const; + const unsigned char *getCUID() const; +@@ -90,6 +92,7 @@ public: + void setSize(int size); + void readData(CKYBuffer *data) const; + void writeData(const CKYBuffer *data); ++ void initCACHeaders(void); + void readCACCert(CKYBuffer *data, CKYByte instance) const; + void writeCACCert(const CKYBuffer *data, CKYByte instance); + void clearValid(CKYByte instance); +@@ -294,7 +297,13 @@ class CryptParams { + const CKYBuffer *paddedOutput) const = 0; + }; + +-#define MAX_CERT_SLOTS 3 ++#define MAX_CERT_SLOTS 10 ++typedef enum { ++ ALG_NONE= 0x0, ++ ALG_ECC = 0x1, ++ ALG_RSA = 0x2 ++} SlotAlgs; ++ + #define MAX_AUTH_USERS 3 + class Slot { + +@@ -349,7 +358,8 @@ class Slot { + bool mCACLocalLogin; + int pivContainer; + int pivKey; +- bool mECC; ++ int maxCacCerts; ++ SlotAlgs algs; + unsigned short p15aid; + unsigned short p15odfAddr; + unsigned short p15tokenInfoAddr; +@@ -424,8 +434,7 @@ class Slot { + list fetchSeparateObjects(); + + CKYStatus getCACAid(); +- CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize, +- bool throwException); ++ CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize); + CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize); + + CKYStatus getP15Params(); +@@ -485,6 +494,8 @@ class Slot { + void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu); + + CKYByte objectToKeyNum(const PKCS11Object *key); ++ void initCACShMem(void); ++ void verifyCACShMem(void); + Slot(const Slot &cpy) + #ifdef USE_SHMEM + : shmem(readerName) +@@ -580,7 +591,7 @@ class Slot { + CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params); + +- bool getIsECC() { return mECC; } ++ SlotAlgs getAlgs() { return algs; } + }; + + class SlotList { diff --git a/coolkey-1.1.0.tar.bz2 b/coolkey-1.1.0.tar.bz2 deleted file mode 100644 index ba245f3..0000000 --- a/coolkey-1.1.0.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:214381ab404b69ef59276a33ab5786848b005ceaa8f199f280ccb66c806a9cde -size 313668 diff --git a/coolkey-1.1.0.tar.gz b/coolkey-1.1.0.tar.gz new file mode 100644 index 0000000..7615199 --- /dev/null +++ b/coolkey-1.1.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8448e3abb81bffc593c96b577dcfbc05b40e8684188456c31be15fae73d730f7 +size 432808 diff --git a/coolkey-fix-token-removal-failure.patch b/coolkey-fix-token-removal-failure.patch new file mode 100644 index 0000000..5faecb5 --- /dev/null +++ b/coolkey-fix-token-removal-failure.patch @@ -0,0 +1,86 @@ +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-null.patch b/coolkey-null.patch deleted file mode 100644 index 150cd8f..0000000 --- a/coolkey-null.patch +++ /dev/null @@ -1,22 +0,0 @@ -https://bugzilla.redhat.com/show_bug.cgi?id=356971 -coolkey.cpp:37:1: error: "NULL" redefined -In file included from /usr/include/alloca.h:25, - from /usr/include/stdlib.h:612, - from /usr/include/c++/4.3.0/cstdlib:73, - from /usr/include/c++/4.3.0/bits/stl_algo.h:65, - from /usr/include/c++/4.3.0/algorithm:67, - from slot.h:27, - from coolkey.cpp:33: -/usr/lib64/gcc/x86_64-suse-linux/4.3.0/include/stddef.h:400:1: error: this is the location of the previous definition -================================================================================ ---- src/coolkey/coolkey.cpp -+++ src/coolkey/coolkey.cpp -@@ -34,8 +34,6 @@ - #include "cky_base.h" - #include "params.h" - --#define NULL 0 -- - /* static module data -------------------------------- */ - - static Log *log = NULL; diff --git a/coolkey-piv-ecc-el7.patch b/coolkey-piv-ecc-el7.patch new file mode 100644 index 0000000..b47b80c --- /dev/null +++ b/coolkey-piv-ecc-el7.patch @@ -0,0 +1,4792 @@ +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.changes b/coolkey.changes index 255f82b..70c032f 100644 --- a/coolkey.changes +++ b/coolkey.changes @@ -1,3 +1,23 @@ +------------------------------------------------------------------- +Mon Jul 17 20:55:48 CEST 2017 - sbrabec@suse.com + +- Integrate latest Centos 7 patches [bsc#1049213] + (coolkey-fix-token-removal-failure.patch, + coolkey-piv-ecc-el7.patch, coolkey-1.1.0-noapplet.patch, + coolkey-1.1.0-fix-spurious-event.patch, + coolkey-1.1.0-p15.patch, coolkey-1.1.0-p15-coverity.patch, + coolkey-1.1.0-more-keys.patch, + coolkey-1.1.0-fail-on-bad-mechanisms.patch, + coolkey-1.1.0-max-cpu-bug.patch, + coolkey-1.1.0-rhel7-alt-cac.patch). + * PK15 support. + * Fix CAC card support. + * Fix card removal issues. +- Use original tarball + (coolkey-1.1.0.tar.bz2 -> coolkey-1.1.0.tar.gz). +- Drop patch coolkey-null.patch. It is now part of + coolkey-piv-ecc-el7.patch. + ------------------------------------------------------------------- Tue Nov 22 16:01:46 CET 2016 - sbrabec@suse.com diff --git a/coolkey-rpmlintrc b/coolkey.rpmlintrc similarity index 100% rename from coolkey-rpmlintrc rename to coolkey.rpmlintrc diff --git a/coolkey.spec b/coolkey.spec index f649625..0fca601 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -1,7 +1,7 @@ # # spec file for package coolkey # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -23,10 +23,12 @@ Summary: CoolKey and CAC PKCS #11 PKI Module for Smart Cards License: LGPL-2.1 Group: Productivity/Security Url: http://directory.fedoraproject.org/wiki/CoolKey -Source: %{name}-%{version}.tar.bz2 -Source1: %{name}-rpmlintrc +Source: %{name}-%{version}.tar.gz +Source1: %{name}.rpmlintrc Source2: baselibs.conf -# Patches imported from Fedora: +# Patches imported from Fedora and CentOS: +# PATCH-FIX-SECURITY coolkey-cache-dir-move.patch sbrabec@suse.cz bnc304180 CVE-2007-4129 -- Fix file and directory permission flaw. +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. @@ -41,13 +43,19 @@ 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 -# PATCH-FIX-SECURITY coolkey-cache-dir-move.patch sbrabec@suse.cz bnc304180 CVE-2007-4129 -- Fix file and directory permission flaw. -Patch54: coolkey-cache-dir-move.patch -# PATCH-FIX-UPSTREAM coolkey-null.patch redhat356971 sbrabec@suse.cz -- Fix invalid NULL declaration. -Patch55: coolkey-null.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: gcc-c++ BuildRequires: libtool @@ -78,8 +86,6 @@ token. As the system is built out, we can add token support. CoolKeys are based on JavaCard 1.2. We are testing with Axalto Egate Cyberflex cards, which are available in both smart card and USB Fob form factors. - - %package devel Summary: CoolKey and CAC PKCS #11 PKI Module for Smart Cards Group: Development/Libraries/C and C++ @@ -105,10 +111,9 @@ add token support. CoolKeys are based on JavaCard 1.2. We are testing with Axalto Egate Cyberflex cards, which are available in both smart card and USB Fob form factors. - - %prep %setup -q +%patch1 %patch2 %patch3 %patch4 @@ -116,16 +121,25 @@ card and USB Fob form factors. %patch6 %patch7 %patch8 +%patch9 -p1 +%patch10 +%patch20 +%patch21 +%patch22 +%patch23 +%patch24 +%patch25 +%patch26 +%patch27 %patch53 -p1 -%patch54 -%patch55 %build autoreconf -f -i export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" export CXXFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" %configure\ - --disable-dependency-tracking \ + --with-debug\ + --disable-dependency-tracking\ --enable-pk11install make %{?_smp_mflags} From 3042ae222b7b788b967ea6e72bbe28b0fe1a44e8044f9a9852b23f43f0eeb07b Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Fri, 21 Jul 2017 12:50:41 +0000 Subject: [PATCH 5/6] Accepting request 511836 from home:sbrabec:branches:security:chipcard - Add nssdb installation scripts. - Run spec-cleaner. - Drop coolkey-1.1.0-evoandooo.patch: The patch does nothing now. Evolution and LibreOffice changed over time. They moved its directories and they don't use secmod.db any more. OBS-URL: https://build.opensuse.org/request/show/511836 OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=18 --- coolkey-1.1.0-evoandooo.patch | 11 -------- coolkey.changes | 9 ++++++ coolkey.spec | 53 ++++++++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 25 deletions(-) delete mode 100644 coolkey-1.1.0-evoandooo.patch diff --git a/coolkey-1.1.0-evoandooo.patch b/coolkey-1.1.0-evoandooo.patch deleted file mode 100644 index f2f6ef4..0000000 --- a/coolkey-1.1.0-evoandooo.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- coolkey-1.1.0/src/install/pk11install.c~ 2007-02-06 14:40:36.000000000 -0500 -+++ coolkey-1.1.0/src/install/pk11install.c 2007-09-05 15:01:57.000000000 -0400 -@@ -150,6 +150,8 @@ DirList dirList[] = { - { HomeDir, ".mozilla/*", NULL }, - { HomeDir, ".thunderbird/*", NULL }, - { HomeDir, ".netscape", NULL }, -+ { HomeDir, ".evolution", NULL }, -+ { HomeDir, ".ooo-2.0/user", NULL }, - #endif - #endif - #ifdef MAC diff --git a/coolkey.changes b/coolkey.changes index 70c032f..28d0e7b 100644 --- a/coolkey.changes +++ b/coolkey.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Fri Jul 21 14:00:08 CEST 2017 - sbrabec@suse.com + +- Add nssdb installation scripts. +- Run spec-cleaner. +- Drop coolkey-1.1.0-evoandooo.patch: The patch does nothing now. + Evolution and LibreOffice changed over time. They moved its + directories and they don't use secmod.db any more. + ------------------------------------------------------------------- Mon Jul 17 20:55:48 CEST 2017 - sbrabec@suse.com diff --git a/coolkey.spec b/coolkey.spec index 0fca601..15950f7 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -16,6 +16,8 @@ # +%define coolkey_module "CoolKey PKCS #11 Module" +%define nssdb %{_sysconfdir}/pki/nssdb Name: coolkey Version: 1.1.0 Release: 0 @@ -53,15 +55,13 @@ 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 -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: mozilla-nss-devel +BuildRequires: mozilla-nss-sysinit +BuildRequires: mozilla-nss-tools BuildRequires: pcsc-lite-devel -BuildRequires: pkg-config +BuildRequires: pkgconfig BuildRequires: zlib-devel #Requires: pcsc-lite # Requires: ifd-egate @@ -131,12 +131,11 @@ card and USB Fob form factors. %patch25 %patch26 %patch27 -%patch53 -p1 %build autoreconf -f -i -export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" -export CXXFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" +export CFLAGS="%{optflags} -fno-strict-aliasing" +export CXXFLAGS="%{optflags} -fno-strict-aliasing" %configure\ --with-debug\ --disable-dependency-tracking\ @@ -144,15 +143,42 @@ export CXXFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" make %{?_smp_mflags} %install -%makeinstall -ln -s pkcs11/libcoolkeypk11.so $RPM_BUILD_ROOT/%{_libdir} +%make_install +ln -s pkcs11/libcoolkeypk11.so %{buildroot}/%{_libdir} -%post -p /sbin/ldconfig +%triggerin -- mozilla-nss-sysinit mozilla-nss-tools +if [ -x %{_bindir}/pk11install -a -x %{_bindir}/modutil -a -f %{_sysconfdir}/pki/nssdb/pkcs11.txt ]; then + isThere=`modutil -rawlist -dbdir dbm:%{nssdb} | grep %{coolkey_module} || echo NO` + if [ "$isThere" == "NO" ]; then + pk11install -l -p %{nssdb} 'name=%{coolkey_module} library=libcoolkeypk11.so' ||: + fi + isThere=`modutil -rawlist -dbdir sql:%{nssdb} | grep %{coolkey_module} || echo NO` + if [ "$isThere" == "NO" ]; then + pk11install -s -p %{nssdb} 'name=%{coolkey_module} library=libcoolkeypk11.so' ||: + fi +fi -%postun -p /sbin/ldconfig +%post +/sbin/ldconfig +if [ -x %{_bindir}/pk11install -a -x %{_bindir}/modutil -a -f %{_sysconfdir}/pki/nssdb/pkcs11.txt ]; then + isThere=`modutil -rawlist -dbdir dbm:%{nssdb} | grep %{coolkey_module} || echo NO` + if [ "$isThere" == "NO" ]; then + pk11install -l -p %{nssdb} 'name=%{coolkey_module} library=libcoolkeypk11.so' ||: + fi + isThere=`modutil -rawlist -dbdir sql:%{nssdb} | grep %{coolkey_module} || echo NO` + if [ "$isThere" == "NO" ]; then + pk11install -s -p %{nssdb} 'name=%{coolkey_module} library=libcoolkeypk11.so' ||: + fi +fi + +%postun +/sbin/ldconfig +if [ $1 -eq 0 -a -x %{_bindir}/modutil -a -f %{_sysconfdir}/pki/nssdb/pkcs11.txt ]; then + modutil -delete %{coolkey_module} -dbdir dbm:%{nssdb} -force || : + modutil -delete %{coolkey_module} -dbdir sql:%{nssdb} -force || : +fi %files -%defattr(-,root,root) %doc ChangeLog LICENSE README %{_bindir}/pk11install %{_libdir}/libcoolkeypk11.so @@ -162,7 +188,6 @@ ln -s pkcs11/libcoolkeypk11.so $RPM_BUILD_ROOT/%{_libdir} %dir %{_libdir}/pkcs11 %files devel -%defattr(-,root,root) %{_libdir}/libckyapplet.so %{_libdir}/pkgconfig/*.pc %{_includedir}/*.h From 145e237c68e3959ca53fd42d550815c5105fb2c3eb402d51df22365bbb6c98c8 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 26 Jul 2017 18:49:37 +0000 Subject: [PATCH 6/6] Accepting request 512375 from home:jengelh:branches:security:chipcard - Remove vision statement and development methods from description. OBS-URL: https://build.opensuse.org/request/show/512375 OBS-URL: https://build.opensuse.org/package/show/security:chipcard/coolkey?expand=0&rev=19 --- coolkey.changes | 5 +++++ coolkey.spec | 16 ++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/coolkey.changes b/coolkey.changes index 28d0e7b..1ddf270 100644 --- a/coolkey.changes +++ b/coolkey.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Mon Jul 24 23:02:16 UTC 2017 - jengelh@inai.de + +- Remove vision statement and development methods from description. + ------------------------------------------------------------------- Fri Jul 21 14:00:08 CEST 2017 - sbrabec@suse.com diff --git a/coolkey.spec b/coolkey.spec index 15950f7..b40415c 100644 --- a/coolkey.spec +++ b/coolkey.spec @@ -79,12 +79,8 @@ keys are automatically provisioned with certificates, keys, and a PIN, unique for that user by the Red Hat Certificate System. Once the CoolKey is provisioned, the user can take the key to any system and use it to login (authenticate), send and receive signed and encrypted -email, or participate in secure messaging or IRC communication. Using a -CoolKey should be as easy as starting a car. To accomplish that vision, -we are focusing on building complete support for CoolKey on exactly one -token. As the system is built out, we can add token support. CoolKeys -are based on JavaCard 1.2. We are testing with Axalto Egate Cyberflex -cards, which are available in both smart card and USB Fob form factors. +email, or participate in secure messaging or IRC communication. +CoolKeys are based on JavaCard 1.2. %package devel Summary: CoolKey and CAC PKCS #11 PKI Module for Smart Cards @@ -103,13 +99,9 @@ keys, and a PIN unique to that user by the Red Hat Certificate System. Once the CoolKey is provisioned, the user can take the key to any system and use it to login (authenticate), send and receive signed and encrypted email, or participate in secure messaging or IRC -communication. Using a CoolKey should be as easy as starting a car. +communication. -To accomplish that vision we are focusing on building complete support -for CoolKey on exactly one token. As the system is built out, we can -add token support. CoolKeys are based on JavaCard 1.2. We are testing -with Axalto Egate Cyberflex cards, which are available in both smart -card and USB Fob form factors. +CoolKeys are based on JavaCard 1.2. %prep %setup -q